diff --git a/Domus.Common/Helpers/PaginationHelper.cs b/Domus.Common/Helpers/PaginationHelper.cs index 99df54e..ab5af5e 100644 --- a/Domus.Common/Helpers/PaginationHelper.cs +++ b/Domus.Common/Helpers/PaginationHelper.cs @@ -90,7 +90,7 @@ public static PaginatedResult BuildPaginatedResult(IMapper? mapper, ICo var results = source.Skip((pageIndex - 1) * pageSize) .Take(pageSize); paginatedResult.Items = results; - paginatedResult.Items = mapper is null ? results : mapper.Map>(results.AsEnumerable()); + paginatedResult.Items = mapper is null ? results.ToList() : mapper.Map>(results.AsEnumerable()); return paginatedResult; } diff --git a/Domus.Domain/Dtos/Quotations/DtoProductDetailQuotationRevision.cs b/Domus.Domain/Dtos/Quotations/DtoProductDetailQuotationRevision.cs index c2b4cb1..0ea4a04 100644 --- a/Domus.Domain/Dtos/Quotations/DtoProductDetailQuotationRevision.cs +++ b/Domus.Domain/Dtos/Quotations/DtoProductDetailQuotationRevision.cs @@ -4,6 +4,7 @@ namespace Domus.Domain.Dtos.Quotations; public class DtoProductDetailQuotationRevision { + public Guid Id { get; set; } public string ProductName { get; set; } = null!; public double Price { get; set; } @@ -13,6 +14,4 @@ public class DtoProductDetailQuotationRevision public double Quantity { get; set; } public string QuantityType { get; set; } = null!; - - public DtoProductDetail Detail { get; set; } = null!; } diff --git a/Domus.Domain/Dtos/Quotations/DtoQuotationFullDetails.cs b/Domus.Domain/Dtos/Quotations/DtoQuotationFullDetails.cs index 1eca71a..20bc152 100644 --- a/Domus.Domain/Dtos/Quotations/DtoQuotationFullDetails.cs +++ b/Domus.Domain/Dtos/Quotations/DtoQuotationFullDetails.cs @@ -17,7 +17,6 @@ public class DtoQuotationFullDetails public DateTime? ExpireAt { get; set; } [JsonPropertyName("products")] - // public ICollection ProductDetailQuotations { get; set; } = new List(); public ICollection ProductDetailQuotations { get; set; } = new List(); [JsonPropertyName("services")] diff --git a/Domus.Domain/Dtos/Quotations/DtoQuotationRevisionWithPriceAndVersion.cs b/Domus.Domain/Dtos/Quotations/DtoQuotationRevisionWithPriceAndVersion.cs new file mode 100644 index 0000000..472a231 --- /dev/null +++ b/Domus.Domain/Dtos/Quotations/DtoQuotationRevisionWithPriceAndVersion.cs @@ -0,0 +1,8 @@ +namespace Domus.Domain.Dtos.Quotations; + +public class DtoQuotationRevisionWithPriceAndVersion +{ + public Guid Id { get; set; } + public int Version { get; set; } + public double TotalPrice { get; set; } +} diff --git a/Domus.Domain/Dtos/Quotations/DtoQuotationWithoutProductsAndServices.cs b/Domus.Domain/Dtos/Quotations/DtoQuotationWithoutProductsAndServices.cs new file mode 100644 index 0000000..afaac67 --- /dev/null +++ b/Domus.Domain/Dtos/Quotations/DtoQuotationWithoutProductsAndServices.cs @@ -0,0 +1,16 @@ +namespace Domus.Domain.Dtos.Quotations; + +public class DtoQuotationWithoutProductsAndServices +{ + public Guid Id { get; set; } + + public DtoDomusUser Customer { get; set; } = null!; + + public DtoDomusUser Staff { get; set; } = null!; + + public string Status { get; set; } = null!; + + public double TotalPrice { get; set; } + + public DateTime? ExpireAt { get; set; } +} \ No newline at end of file diff --git a/Domus.Service/AutoMappings/AutoMapperConfiguration.cs b/Domus.Service/AutoMappings/AutoMapperConfiguration.cs index ddc2107..3efe206 100644 --- a/Domus.Service/AutoMappings/AutoMapperConfiguration.cs +++ b/Domus.Service/AutoMappings/AutoMapperConfiguration.cs @@ -138,7 +138,9 @@ private static void CreateProductMaps(IMapperConfigurationExpression mapper) mapper.CreateMap() .ForMember(dest => dest.ProductName, - opt => opt.MapFrom(src => src.ProductDetail.Product.ProductName)); + opt => opt.MapFrom(src => src.ProductDetail.Product.ProductName)) + .ForMember(dest => dest.Id, + opt => opt.MapFrom(src => src.ProductDetailId)); mapper.CreateMap() .ForMember(dest => dest.DisplayPrice, @@ -200,14 +202,10 @@ private static void CreateQuotationMaps(IMapperConfigurationExpression mapper) opt => opt.Ignore()) .ForMember(dest => dest.ServiceQuotations, opt => opt.Ignore()); - - // mapper.CreateMap() - // .ForMember(dest => dest.MonetaryUnit, - // opt => opt.Condition(src => !string.IsNullOrEmpty(src.MonetaryUnit))) - // .ForMember(dest => dest.QuantityType, - // opt => opt.Condition(src => !string.IsNullOrEmpty(src.QuantityType))); mapper.CreateMap(); + mapper.CreateMap(); + mapper.CreateMap(); } private static void CreatePackageMaps(IMapperConfigurationExpression mapper) diff --git a/Domus.Service/Implementations/QuotationService.cs b/Domus.Service/Implementations/QuotationService.cs index f79c446..46b59ed 100644 --- a/Domus.Service/Implementations/QuotationService.cs +++ b/Domus.Service/Implementations/QuotationService.cs @@ -125,31 +125,32 @@ public async Task CreateQuotation(CreateQuotationRequest re PackageId = request.PackageId }; + var quotationRevision = new QuotationRevision + { + Quotation = quotation, + Version = 0, + CreatedAt = DateTime.Now + }; + foreach (var productDetail in request.ProductDetails) { var productDetailEntity = await _productDetailRepository.GetAsync(pd => pd.Id == productDetail.Id); if (productDetailEntity == null) throw new ProductDetailNotFoundException(); - var quotationRevision = new QuotationRevision - { - Quotation = quotation, - Version = 0, - CreatedAt = DateTime.Now - }; var productDetailQuotationRevision = new ProductDetailQuotationRevision { ProductDetailId = productDetail.Id, QuotationRevision = quotationRevision, Quantity = Math.Max(productDetail.Quantity, 1), - Price = productDetailEntity.DisplayPrice, + Price = productDetail.Price, MonetaryUnit = "USD", QuantityType = "Unit", }; quotationRevision.ProductDetailQuotationRevisions.Add(productDetailQuotationRevision); - quotation.QuotationRevisions.Add(quotationRevision); + quotationRevision.TotalPrice += productDetailQuotationRevision.Price * productDetailQuotationRevision.Quantity; } foreach (var service in request.Services) @@ -166,8 +167,10 @@ public async Task CreateQuotation(CreateQuotationRequest re }; quotation.ServiceQuotations.Add(serviceQuotation); + quotationRevision.TotalPrice += service.Price; } + quotation.QuotationRevisions.Add(quotationRevision); await _quotationRepository.AddAsync(quotation); await _unitOfWork.CommitAsync(); @@ -228,7 +231,10 @@ public async Task GetAllQuotations() foreach (var quotation in quotations) { - quotation.TotalPrice = (float)await GetQuotationTotalPrice(quotation.Id); + var quotationRevisions = (await _quotationRevisionRepository.FindAsync(r => !r.IsDeleted && r.QuotationId == quotation.Id)) + .ProjectTo(_mapper.ConfigurationProvider); + + quotation.TotalPrice = (float)(quotationRevisions.OrderByDescending(qr => qr.Version).FirstOrDefault()?.TotalPrice ?? 0); } return new ServiceActionResult(true) { Data = quotations }; @@ -253,7 +259,10 @@ public async Task GetPaginatedQuotations(BasePaginatedReque foreach (var quotation in await ((IQueryable)paginatedResult.Items!).ToListAsync()) { - quotation.TotalPrice = (float)await GetQuotationTotalPrice(quotation.Id); + var quotationRevisions = (await _quotationRevisionRepository.FindAsync(r => !r.IsDeleted && r.QuotationId == quotation.Id)) + .ProjectTo(_mapper.ConfigurationProvider); + + quotation.TotalPrice = (float)(quotationRevisions.OrderByDescending(qr => qr.Version).FirstOrDefault()?.TotalPrice ?? 0); quotationList.Add(quotation); } @@ -280,9 +289,8 @@ public async Task GetQuotationById(Guid id) quotation.ProductDetailQuotations = _mapper.Map>(products); - var totalProductPrice = products.Sum(r => (float)(r?.Price ?? 0) * r?.Quantity ?? 0); - var totalServicePrice = quotation.ServiceQuotations.Sum(s => s.Price); - quotation.TotalPrice = totalProductPrice + totalServicePrice; + quotation.TotalPrice = + (await quotationRevisions.OrderByDescending(qr => qr.Version).FirstOrDefaultAsync())?.TotalPrice ?? 0; return new ServiceActionResult(true) { Data = quotation }; } @@ -291,31 +299,40 @@ public async Task SearchQuotations(SearchUsingGetRequest re { var quotations = await (await _quotationRepository.FindAsync(p => !p.IsDeleted)) .OrderByDescending(p => p.CreatedAt) - .ProjectTo(_mapper.ConfigurationProvider) + .ProjectTo(_mapper.ConfigurationProvider) .ToListAsync(); - - foreach (var quotation in quotations) - { - quotation.TotalPrice = await GetQuotationTotalPrice(quotation.Id); - } if (!string.IsNullOrEmpty(request.SearchField)) { quotations = quotations - .Where(p => ReflectionHelper.GetStringValueByName(typeof(DtoQuotationFullDetails), request.SearchField, p).Contains(request.SearchValue ?? string.Empty, StringComparison.OrdinalIgnoreCase)) + .Where(p => ReflectionHelper.GetStringValueByName(typeof(DtoQuotationWithoutProductsAndServices), request.SearchField, p).Contains(request.SearchValue ?? string.Empty, StringComparison.OrdinalIgnoreCase)) .ToList(); } if (!string.IsNullOrEmpty(request.SortField)) { - Expression> orderExpr = p => ReflectionHelper.GetValueByName(typeof(DtoQuotationFullDetails), request.SortField, p); + Expression> orderExpr = p => ReflectionHelper.GetValueByName(typeof(DtoQuotationWithoutProductsAndServices), request.SortField, p); quotations = request.Descending ? quotations.OrderByDescending(orderExpr.Compile()).ToList() : quotations.OrderBy(orderExpr.Compile()).ToList(); } - + var paginatedResult = PaginationHelper.BuildPaginatedResult(quotations, request.PageSize, request.PageIndex); + var paginatedQuotations = (ICollection)paginatedResult.Items!; + var quotationList = new List(); + + foreach (var quotation in paginatedQuotations) + { + var quotationRevisions = (await _quotationRevisionRepository.FindAsync(r => !r.IsDeleted && r.QuotationId == quotation.Id)) + .ProjectTo(_mapper.ConfigurationProvider); + + quotation.TotalPrice = quotationRevisions.OrderByDescending(qr => qr.Version).FirstOrDefault()?.TotalPrice ?? 0; + quotationList.Add(quotation); + } + + paginatedResult.Items = quotationList; + return new ServiceActionResult(true) { Data = paginatedResult }; } @@ -356,12 +373,14 @@ public async Task UpdateQuotation(UpdateQuotationRequest re }; quotation.ServiceQuotations.Add(newServiceQuotation); + newQuotationRevision.TotalPrice += requestService.Price; continue; } quotation.ServiceQuotations.Remove(serviceQuotation); serviceQuotation.Price = requestService.Price; quotation.ServiceQuotations.Add(serviceQuotation); + newQuotationRevision.TotalPrice += requestService.Price; } var excludedServices = new List(quotation.ServiceQuotations.Where(s => !request.Services.Select(rs => rs.ServiceId).Contains(s.ServiceId))); @@ -376,7 +395,7 @@ public async Task UpdateQuotation(UpdateQuotationRequest re { Price = requestProductDetail.Price, MonetaryUnit = string.IsNullOrEmpty(requestProductDetail.MonetaryUnit) ? "USD" : requestProductDetail.MonetaryUnit, - Quantity = requestProductDetail.Quantity, + Quantity = Math.Max(requestProductDetail.Quantity, 1), QuantityType = string.IsNullOrEmpty(requestProductDetail.QuantityType) ? "Unit" : requestProductDetail.QuantityType, IsDeleted = false, ProductDetailId = requestProductDetail.ProductDetailId, @@ -384,6 +403,7 @@ public async Task UpdateQuotation(UpdateQuotationRequest re }; newQuotationRevision.ProductDetailQuotationRevisions.Add(productDetailInQuotaionRevision); + newQuotationRevision.TotalPrice += productDetailInQuotaionRevision.Price * productDetailInQuotaionRevision.Quantity; } quotation.QuotationRevisions.Add(newQuotationRevision);