diff --git a/.version b/.version index 52f543b..74062c9 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.5.14.20 \ No newline at end of file +1.5.17.23 \ No newline at end of file diff --git a/Netina.Api/AppSettings/appsettings.DevelopmentVesmeh.json b/Netina.Api/AppSettings/appsettings.DevelopmentVesmeh.json index 8610861..410ba95 100644 --- a/Netina.Api/AppSettings/appsettings.DevelopmentVesmeh.json +++ b/Netina.Api/AppSettings/appsettings.DevelopmentVesmeh.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "PostgresServer": "Host=185.220.227.246;Username=vesmmehAgent;Password=g05CTjK358Vx3Eoc9satsWyVwo+15UmsA2dnCrZRUYh1pLTe;Database=NetinaShopDB;Application Name=NetinaShopApi", + "PostgresServer": "Host=185.220.227.39;Username=vesmmehAgent;Password=g05CTjK358Vx3Eoc9satsWyVwo+15UmsA2dnCrZRUYh1pLTe;Database=NetinaShopDB;Application Name=NetinaShopApi", "Postgres": "Host=pg-0;Username=postgres;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=NetinaShopDB", "MartenDB": "Host=pg-0;Username=postgres;Password=xHTpBf4wC+bBeNg2pL6Ga7VEWKFJx7VPEUpqxwPFfOc2YYTVwFQuHfsiqoVeT9+6;Database=NetinaShopMartenDB" }, diff --git a/Netina.Api/Controllers/BlogController.cs b/Netina.Api/Controllers/BlogController.cs index dcb26ed..5932977 100644 --- a/Netina.Api/Controllers/BlogController.cs +++ b/Netina.Api/Controllers/BlogController.cs @@ -36,6 +36,10 @@ public class BlogController : ICarterModule .WithDisplayName("Update Blog") .HasApiVersion(1.0); + group.MapGet("{blogId}/comment", GetBlogCommentsAsync) + .WithDisplayName("Get Blog Comments") + .HasApiVersion(1.0); + group.MapDelete("{id}", Delete) .RequireAuthorization(builder => builder.AddAuthenticationSchemes("Bearer").RequireAuthenticatedUser() @@ -49,6 +53,10 @@ public class BlogController : ICarterModule } + + private async Task GetBlogCommentsAsync([FromQuery] int page, [FromQuery] int count, [FromRoute] Guid blogId, IMediator mediator, CancellationToken cancellationToken) + => TypedResults.Ok(await mediator.Send(new GetCommentsQuery(page, count, null, blogId), cancellationToken)); + private async Task GetBlogNewLinkAsync([FromQuery]string slug,IRepositoryWrapper repositoryWrapper,IOptionsSnapshot snapshot,CancellationToken cancellationToken) { var htmlSlug = HttpUtility.UrlEncode(slug); diff --git a/Netina.Api/Netina.Api.csproj b/Netina.Api/Netina.Api.csproj index d9e7e6a..8eb30c9 100644 --- a/Netina.Api/Netina.Api.csproj +++ b/Netina.Api/Netina.Api.csproj @@ -6,8 +6,8 @@ enable true Linux - 1.5.14.20 - 1.5.14.20 + 1.5.17.23 + 1.5.17.23 @@ -15,7 +15,7 @@ - + diff --git a/Netina.Api/WebFramework/Configurations/ServiceExtensions.cs b/Netina.Api/WebFramework/Configurations/ServiceExtensions.cs index 977c174..eb04e9d 100644 --- a/Netina.Api/WebFramework/Configurations/ServiceExtensions.cs +++ b/Netina.Api/WebFramework/Configurations/ServiceExtensions.cs @@ -72,7 +72,7 @@ public static class ServiceExtensions serviceCollection.AddDbContextFactory(options => { options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking); - options.UseNpgsql(Configuration.GetConnectionString("Postgres"), b => b.MigrationsAssembly("Netina.Repository")) + options.UseNpgsql(Configuration.GetConnectionString("PostgresServer"), b => b.MigrationsAssembly("Netina.Repository")) .UseProjectAssembly(typeof(ApplicationUser).Assembly); //options.EnableServiceProviderCaching(true); diff --git a/Netina.Common/Extensions/StringExtensions.cs b/Netina.Common/Extensions/StringExtensions.cs index 7f53870..1781901 100644 --- a/Netina.Common/Extensions/StringExtensions.cs +++ b/Netina.Common/Extensions/StringExtensions.cs @@ -17,6 +17,7 @@ namespace Netina.Common.Extensions return outPut; } + public static string ToPriceWhitPriceType(this long price, string priceType) { return price.ToString("N0") + " " + priceType; diff --git a/Netina.Core/EntityServices/DiscountHandlers/CalculateOrderDiscountCommandHandler.cs b/Netina.Core/EntityServices/DiscountHandlers/CalculateOrderDiscountCommandHandler.cs index 5693f37..848ef80 100644 --- a/Netina.Core/EntityServices/DiscountHandlers/CalculateOrderDiscountCommandHandler.cs +++ b/Netina.Core/EntityServices/DiscountHandlers/CalculateOrderDiscountCommandHandler.cs @@ -1,4 +1,6 @@ -namespace Netina.Core.EntityServices.DiscountHandlers; +using Netina.Domain.Entities.ProductCategories; + +namespace Netina.Core.EntityServices.DiscountHandlers; public class CalculateOrderDiscountCommandHandler( IRepositoryWrapper repositoryWrapper, @@ -51,8 +53,12 @@ public class CalculateOrderDiscountCommandHandler( .FirstOrDefaultAsync(d => d.Code == request.DiscountCode, cancellationToken); if ( categoryDiscount!=null && !categoryDiscount.IsExpired()) { - totalPrice = request.Order.OrderProducts.Where(op => op.ProductCategoryId == categoryDiscount.CategoryId).Sum(op => op.ProductCost); - + var subCats = await repositoryWrapper.SetRepository().TableNoTracking + .Where(c => c.ParentId == categoryDiscount.CategoryId) + .Select(c => c.Id) + .ToListAsync(cancellationToken); + subCats.Add(categoryDiscount.CategoryId); + totalPrice = request.Order.OrderProducts.Where(op => subCats.Contains(op.ProductCategoryId)).Sum(op => op.ProductCost); } } else if (discount.Type == DiscountType.Product) diff --git a/Netina.Core/EntityServices/DiscountHandlers/CalculateProductDiscountCommandHandler.cs b/Netina.Core/EntityServices/DiscountHandlers/CalculateProductDiscountCommandHandler.cs index 7ede885..1e51659 100644 --- a/Netina.Core/EntityServices/DiscountHandlers/CalculateProductDiscountCommandHandler.cs +++ b/Netina.Core/EntityServices/DiscountHandlers/CalculateProductDiscountCommandHandler.cs @@ -68,6 +68,12 @@ public class CalculateProductDiscountCommandHandler(IRepositoryWrapper repositor request.DiscountPercent = request.Cost == 0 ? 0 : 100 - 100 * request.CostWithDiscount / request.Cost; } + if (request.DiscountPercent == 0) + { + request.CostWithDiscount = 0; + request.HasDiscount = false; + } + return request; } diff --git a/Netina.Core/EntityServices/OrderHandlers/CalculateOrderCommandHandler.cs b/Netina.Core/EntityServices/OrderHandlers/CalculateOrderCommandHandler.cs index b610617..c1a221a 100644 --- a/Netina.Core/EntityServices/OrderHandlers/CalculateOrderCommandHandler.cs +++ b/Netina.Core/EntityServices/OrderHandlers/CalculateOrderCommandHandler.cs @@ -23,8 +23,17 @@ public class CalculateOrderCommandHandler(IRepositoryWrapper repositoryWrapper, var deliveryPrice = order.OrderDelivery?.DeliveryCost ?? 0; double productDiscountPrice = order.OrderProducts.Sum(op=>(op.ProductFee - op.ProductFeeWithDiscount) * op.Count); double discountCodePrice = 0; - if (!order.DiscountCode.IsNullOrEmpty()) - discountCodePrice += await mediator.Send(new CalculateOrderDiscountCommand(order.DiscountCode, order),cancellationToken); + + try + { + if (!order.DiscountCode.IsNullOrEmpty()) + discountCodePrice += await mediator.Send(new CalculateOrderDiscountCommand(order.DiscountCode, order), + cancellationToken); + } + catch (Exception ) + { + order.RemoveDiscount(); + } var taxesPrice = (((totalProductPrice - (discountCodePrice + productDiscountPrice)) + totalPackingPrice + servicePrice) / 100) * taxesFee; diff --git a/Netina.Domain/Dtos/LargDtos/BlogLDto.cs b/Netina.Domain/Dtos/LargDtos/BlogLDto.cs index e060c2b..4fc639b 100644 --- a/Netina.Domain/Dtos/LargDtos/BlogLDto.cs +++ b/Netina.Domain/Dtos/LargDtos/BlogLDto.cs @@ -10,6 +10,8 @@ public class BlogLDto : BaseDto public string Summery { get; set; } = string.Empty; public string MainImage { get; set; } = string.Empty; public bool IsSuggested { get; set; } + public float Rate { get; set; } + public int CommentCount { get; set; } public Guid CategoryId { get; set; } public string CategoryName { get; set; } = string.Empty; public Guid AuthorId { get; set; } diff --git a/Netina.Domain/Dtos/LargDtos/ProductLDto.cs b/Netina.Domain/Dtos/LargDtos/ProductLDto.cs index 810eada..c57f5fb 100644 --- a/Netina.Domain/Dtos/LargDtos/ProductLDto.cs +++ b/Netina.Domain/Dtos/LargDtos/ProductLDto.cs @@ -19,6 +19,8 @@ public class ProductLDto : BaseDto public double PackingCost { get; set; } public int MaxOrderCount { get; set; } public int Stock { get; set; } + public float Rate { get; set; } + public int CommentCount { get; set; } public Guid BrandId { get; set; } public string BrandName { get; set; } = string.Empty; public Guid CategoryId { get; set; } diff --git a/Netina.Domain/Dtos/SmallDtos/BlogSDto.cs b/Netina.Domain/Dtos/SmallDtos/BlogSDto.cs index 5caa123..5652006 100644 --- a/Netina.Domain/Dtos/SmallDtos/BlogSDto.cs +++ b/Netina.Domain/Dtos/SmallDtos/BlogSDto.cs @@ -8,6 +8,8 @@ public class BlogSDto : BaseDto public int ReadingTime { get; set; } public string Summery { get; set; } = string.Empty; public bool IsSuggested { get; set; } + public float Rate { get; set; } + public int CommentCount { get; set; } public Guid CategoryId { get; set; } public string CategoryName { get; set; } = string.Empty; public string MainImage { get; set; } = string.Empty; diff --git a/Netina.Domain/Dtos/SmallDtos/ProductSDto.cs b/Netina.Domain/Dtos/SmallDtos/ProductSDto.cs index ffabb05..62cc053 100644 --- a/Netina.Domain/Dtos/SmallDtos/ProductSDto.cs +++ b/Netina.Domain/Dtos/SmallDtos/ProductSDto.cs @@ -21,7 +21,7 @@ public class ProductSDto : BaseDto public bool BeDisplayed { get; set; } public double PackingCost { get; set; } public float Rate { get; set; } - public int ReviewCount { get; set; } + public int CommentCount { get; set; } public int Viewed { get; set; } public string MainImage { get; set; } = string.Empty; public Guid CategoryId { get; set; } diff --git a/Netina.Domain/Mappers/ProductMapper.g.cs b/Netina.Domain/Mappers/ProductMapper.g.cs index 71cebd1..82fa224 100644 --- a/Netina.Domain/Mappers/ProductMapper.g.cs +++ b/Netina.Domain/Mappers/ProductMapper.g.cs @@ -30,6 +30,7 @@ namespace Netina.Domain.Mappers BeDisplayed = p1.BeDisplayed, PackingCost = p1.PackingCost, Stock = p1.Stock, + Rate = p1.Rate, HasExpressDelivery = p1.HasExpressDelivery, MaxOrderCount = p1.MaxOrderCount, BrandId = p1.BrandId, @@ -67,6 +68,7 @@ namespace Netina.Domain.Mappers result.BeDisplayed = p4.BeDisplayed; result.PackingCost = p4.PackingCost; result.Stock = p4.Stock; + result.Rate = p4.Rate; result.HasExpressDelivery = p4.HasExpressDelivery; result.MaxOrderCount = p4.MaxOrderCount; result.BrandId = p4.BrandId; @@ -95,6 +97,7 @@ namespace Netina.Domain.Mappers BeDisplayed = p16.BeDisplayed, PackingCost = p16.PackingCost, Stock = p16.Stock, + Rate = p16.Rate, HasExpressDelivery = p16.HasExpressDelivery, MaxOrderCount = p16.MaxOrderCount, BrandId = p16.BrandId, @@ -149,6 +152,8 @@ namespace Netina.Domain.Mappers PackingCost = p19.PackingCost, MaxOrderCount = p19.MaxOrderCount, Stock = p19.Stock, + Rate = (float)(p19.Rate == 0f ? 4.5d : (double)p19.Rate), + CommentCount = p19.ReviewCount, BrandId = p19.BrandId, BrandName = p19.Brand == null ? null : p19.Brand.PersianName, CategoryId = p19.CategoryId, @@ -182,6 +187,8 @@ namespace Netina.Domain.Mappers result.PackingCost = p22.PackingCost; result.MaxOrderCount = p22.MaxOrderCount; result.Stock = p22.Stock; + result.Rate = (float)(p22.Rate == 0f ? 4.5d : (double)p22.Rate); + result.CommentCount = p22.ReviewCount; result.BrandId = p22.BrandId; result.BrandName = p22.Brand == null ? null : p22.Brand.PersianName; result.CategoryId = p22.CategoryId; @@ -210,6 +217,8 @@ namespace Netina.Domain.Mappers PackingCost = p28.PackingCost, MaxOrderCount = p28.MaxOrderCount, Stock = p28.Stock, + Rate = (float)(p28.Rate == 0f ? 4.5d : (double)p28.Rate), + CommentCount = p28.ReviewCount, BrandId = p28.BrandId, BrandName = p28.Brand == null ? null : p28.Brand.PersianName, CategoryId = p28.CategoryId, @@ -257,7 +266,6 @@ namespace Netina.Domain.Mappers PackingCost = p31.PackingCost, Stock = p31.Stock, Rate = p31.Rate, - ReviewCount = p31.ReviewCount, Viewed = p31.Viewed, MaxOrderCount = p31.MaxOrderCount, BrandId = p31.BrandId, @@ -296,7 +304,6 @@ namespace Netina.Domain.Mappers result.PackingCost = p32.PackingCost; result.Stock = p32.Stock; result.Rate = p32.Rate; - result.ReviewCount = p32.ReviewCount; result.Viewed = p32.Viewed; result.MaxOrderCount = p32.MaxOrderCount; result.BrandId = p32.BrandId; @@ -328,8 +335,8 @@ namespace Netina.Domain.Mappers MaxOrderCount = p40.MaxOrderCount, BeDisplayed = p40.BeDisplayed, PackingCost = p40.PackingCost, - Rate = p40.Rate, - ReviewCount = p40.ReviewCount, + Rate = (float)(p40.Rate == 0f ? 4.5d : (double)p40.Rate), + CommentCount = p40.ReviewCount, Viewed = p40.Viewed, MainImage = p40.Files.FirstOrDefault(funcMain15) != null ? p40.Files.FirstOrDefault(funcMain16).FileLocation : (p40.Files.Count > 0 ? p40.Files.FirstOrDefault().FileLocation : string.Empty), CategoryId = p40.CategoryId, @@ -364,8 +371,8 @@ namespace Netina.Domain.Mappers result.MaxOrderCount = p41.MaxOrderCount; result.BeDisplayed = p41.BeDisplayed; result.PackingCost = p41.PackingCost; - result.Rate = p41.Rate; - result.ReviewCount = p41.ReviewCount; + result.Rate = (float)(p41.Rate == 0f ? 4.5d : (double)p41.Rate); + result.CommentCount = p41.ReviewCount; result.Viewed = p41.Viewed; result.MainImage = p41.Files.FirstOrDefault(funcMain15) != null ? p41.Files.FirstOrDefault(funcMain16).FileLocation : (p41.Files.Count > 0 ? p41.Files.FirstOrDefault().FileLocation : string.Empty); result.CategoryId = p41.CategoryId; @@ -395,8 +402,8 @@ namespace Netina.Domain.Mappers MaxOrderCount = p43.MaxOrderCount, BeDisplayed = p43.BeDisplayed, PackingCost = p43.PackingCost, - Rate = p43.Rate, - ReviewCount = p43.ReviewCount, + Rate = (float)(p43.Rate == 0f ? 4.5d : (double)p43.Rate), + CommentCount = p43.ReviewCount, Viewed = p43.Viewed, MainImage = p43.Files.FirstOrDefault(f => f.IsPrimary) != null ? p43.Files.FirstOrDefault(f => f.IsPrimary).FileLocation : (p43.Files.Count > 0 ? p43.Files.FirstOrDefault().FileLocation : string.Empty), CategoryId = p43.CategoryId, diff --git a/Netina.Domain/MapsterRegister.cs b/Netina.Domain/MapsterRegister.cs index 6294a06..80ebcd1 100644 --- a/Netina.Domain/MapsterRegister.cs +++ b/Netina.Domain/MapsterRegister.cs @@ -63,6 +63,8 @@ public class MapsterRegister : IRegister .Map("MainImage", o => o.Files.FirstOrDefault(f => f.IsPrimary) != null ? o.Files.FirstOrDefault(f => f.IsPrimary).FileLocation : o.Files.Count > 0 ? o.Files.FirstOrDefault().FileLocation : string.Empty) .Map("CategoryName", o => o.Category == null ? null : o.Category.Name) .Map("BrandName", o => o.Brand == null ? null : o.Brand.PersianName) + .Map(d=>d.Rate , o=>o.Rate == 0 ? 4.5 : o.Rate) + .Map(d => d.CommentCount, o => o.ReviewCount) .IgnoreNullValues(false) .TwoWays(); @@ -79,6 +81,8 @@ public class MapsterRegister : IRegister .Map(o => o.AuthorFullName, d => d.Author != null ? d.Author.FirstName + " " + d.Author.LastName : string.Empty) .Map("CategoryName", o => o.Category == null ? null : o.Category.Name) .Map("BrandName", o => o.Brand == null ? null : o.Brand.PersianName) + .Map(d => d.Rate, o => o.Rate == 0 ? 4.5 : o.Rate) + .Map(d => d.CommentCount, o => o.ReviewCount) .IgnoreNullValues(false) .TwoWays(); diff --git a/Netina.Repository/Handlers/Discounts/CreateDiscountCommandHandler.cs b/Netina.Repository/Handlers/Discounts/CreateDiscountCommandHandler.cs index 56c8dae..83e75eb 100644 --- a/Netina.Repository/Handlers/Discounts/CreateDiscountCommandHandler.cs +++ b/Netina.Repository/Handlers/Discounts/CreateDiscountCommandHandler.cs @@ -1,4 +1,6 @@ -namespace Netina.Repository.Handlers.Discounts; +using BaseApiException = Netina.Common.Models.Exception.BaseApiException; + +namespace Netina.Repository.Handlers.Discounts; public class CreateDiscountCommandHandler(IRepositoryWrapper repositoryWrapper) : IRequestHandler @@ -15,35 +17,42 @@ public class CreateDiscountCommandHandler(IRepositoryWrapper repositoryWrapper) if (foundDiscount != null) throw new BaseApiException(ApiResultStatusCode.BadRequest, "کد تخفیف مورد نظر تکراری می باشد"); } + + if (request is { AmountType: DiscountAmountType.Percent, DiscountPercent: 0 }) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "در تخفیف درصدی ، درصد تخفیف نمی تواند صفر باشد"); + + if (request is { AmountType: DiscountAmountType.Amount, DiscountAmount: 0 }) + throw new BaseApiException(ApiResultStatusCode.BadRequest, "در تخفیف مبلغی ، مبلغ تخفیف نمی تواند صفر باشد"); + switch (request.Type) { case DiscountType.All: - var ent = Discount.Create(request.Code,request.Description, request.DiscountPercent, request.DiscountAmount, - request.HasCode, request.AmountType, request.Type, request.Count,request.IsImmortal, request.StartDate, + var ent = Discount.Create(request.Code, request.Description, request.DiscountPercent, request.DiscountAmount, + request.HasCode, request.AmountType, request.Type, request.Count, request.IsImmortal, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, - request.IsInfinity, request.UseCount, request.IsForInvitation,request.IsForFirstPurchase,request.IsSpecialOffer); + request.IsInfinity, request.UseCount, request.IsForInvitation, request.IsForFirstPurchase, request.IsSpecialOffer); repositoryWrapper.SetRepository().Add(ent); break; case DiscountType.Category: - var catDis = CategoryDiscount.Create(request.Code,request.Description, request.DiscountPercent, request.DiscountAmount, request.HasCode, - request.AmountType, request.Type, request.Count,request.IsImmortal, request.StartDate, request.ExpireDate, request.PriceFloor, + var catDis = CategoryDiscount.Create(request.Code, request.Description, request.DiscountPercent, request.DiscountAmount, request.HasCode, + request.AmountType, request.Type, request.Count, request.IsImmortal, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, - request.IsForInvitation,request.IsForFirstPurchase,request.IsSpecialOffer, request.CategoryId); + request.IsForInvitation, request.IsForFirstPurchase, request.IsSpecialOffer, request.CategoryId); repositoryWrapper.SetRepository().Add(catDis); break; case DiscountType.Product: - var productDis = ProductDiscount.Create(request.Code,request.Description, request.DiscountPercent, request.DiscountAmount, request.HasCode, + var productDis = ProductDiscount.Create(request.Code, request.Description, request.DiscountPercent, request.DiscountAmount, request.HasCode, request.AmountType, request.Type, request.Count, request.IsImmortal, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, - request.IsForInvitation,request.IsForFirstPurchase, request.IsSpecialOffer,request.ProductId); + request.IsForInvitation, request.IsForFirstPurchase, request.IsSpecialOffer, request.ProductId); repositoryWrapper.SetRepository().Add(productDis); break; default: - var def = Discount.Create(request.Code,request.Description, request.DiscountPercent, request.DiscountAmount, request.HasCode, + var def = Discount.Create(request.Code, request.Description, request.DiscountPercent, request.DiscountAmount, request.HasCode, request.AmountType, request.Type, request.Count, request.IsImmortal, request.StartDate, request.ExpireDate, request.PriceFloor, request.HasPriceFloor, request.PriceCeiling, request.HasPriceCeiling, request.IsInfinity, request.UseCount, - request.IsForInvitation, request.IsForFirstPurchase,request.IsSpecialOffer); + request.IsForInvitation, request.IsForFirstPurchase, request.IsSpecialOffer); repositoryWrapper.SetRepository().Add(def); break; }