diff --git a/Domus.Api/Controllers/QuotationsController.cs b/Domus.Api/Controllers/QuotationsController.cs index 00bd75c..012b395 100644 --- a/Domus.Api/Controllers/QuotationsController.cs +++ b/Domus.Api/Controllers/QuotationsController.cs @@ -60,6 +60,22 @@ public async Task CreateQuotation(CreateQuotationRequest request) ).ConfigureAwait(false); } + [HttpPost("/api/staff/quotations")] + public async Task CreateQuotationByStaff(CreateQuotationRequest request, string customerId) + { + return await ExecuteServiceLogic( + async () => await _quotationService.CreateQuotationByStaff(request, customerId, GetJwtToken()).ConfigureAwait(false) + ).ConfigureAwait(false); + } + + [HttpPost("/api/customer/quotations")] + public async Task CreateQuotationByCustomer(CreateQuotationRequest request) + { + return await ExecuteServiceLogic( + async () => await _quotationService.CreateQuotationByCustomer(request, GetJwtToken()).ConfigureAwait(false) + ).ConfigureAwait(false); + } + [HttpPut("{id:guid}")] public async Task UpdateQuotation(UpdateQuotationRequest request, Guid id) { diff --git a/Domus.Service/Implementations/QuotationService.cs b/Domus.Service/Implementations/QuotationService.cs index 36c2196..7fbb9ad 100644 --- a/Domus.Service/Implementations/QuotationService.cs +++ b/Domus.Service/Implementations/QuotationService.cs @@ -107,28 +107,29 @@ public async Task CreateNegotiationMessage(CreateNegotiatio if (request.IsCustomerMessage) { - _notificationRepository.AddAsync(new Notification() + await _notificationRepository.AddAsync(new Notification() { RecipientId = quotation.StaffId, - Content = NotificationHelper.CreateNegotiationMessageForStaff((quotation.Customer.FullName.Equals("N/A") ? quotation.Customer.Email : quotation.Customer.FullName),quotationId), + Content = NotificationHelper.CreateNegotiationMessageForStaff((quotation.Customer.FullName.Equals("N/A") ? quotation.Customer.Email! : quotation.Customer.FullName),quotationId), SentAt = DateTime.Now, - Image = quotation.Customer.ProfileImage, + Image = quotation.Customer.ProfileImage ?? string.Empty, RedirectString = $"customer/settings/quotations/{quotationId}" } ); } else { - _notificationRepository.AddAsync(new Notification() + await _notificationRepository.AddAsync(new Notification() { RecipientId = quotation.CustomerId, - Content = NotificationHelper.CreateNegotiationMessageForCustomer((quotation.Staff.FullName.Equals("N/A") ? quotation.Staff.Email : quotation.Staff.FullName),quotationId), + Content = NotificationHelper.CreateNegotiationMessageForCustomer((quotation.Staff.FullName.Equals("N/A") ? quotation.Staff.Email! : quotation.Staff.FullName),quotationId), SentAt = DateTime.Now, - Image = quotation.Staff.ProfileImage, + Image = quotation.Staff.ProfileImage ?? string.Empty, RedirectString = $"customer/settings/quotations/{quotationId}" } ); } + await _unitOfWork.CommitAsync(); return new ServiceActionResult(true); } @@ -702,4 +703,118 @@ public async Task SearchStaffQuotations(SearchUsingGetReque return new ServiceActionResult(true) { Data = paginatedResult }; } + + private async Task CreateQuotationGeneral(CreateQuotationRequest request, string staffId, string customerId, bool createdByStaff) + { + var quotation = new Quotation + { + CustomerId = customerId, + StaffId = staffId, + CreatedBy = createdByStaff ? staffId: customerId, + CreatedAt = DateTime.Now, + ExpireAt = request.ExpireAt ?? DateTime.Now.AddDays(30), + Status = QuotationStatusConstants.Requested, + IsDeleted = false, + 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 productDetailQuotationRevision = new ProductDetailQuotationRevision + { + ProductDetailId = productDetail.Id, + QuotationRevision = quotationRevision, + Quantity = Math.Max(productDetail.Quantity, 1), + Price = productDetail.Price, + MonetaryUnit = "USD", + QuantityType = "Unit", + }; + + quotationRevision.ProductDetailQuotationRevisions.Add(productDetailQuotationRevision); + quotationRevision.TotalPrice += productDetailQuotationRevision.Price * productDetailQuotationRevision.Quantity; + } + + foreach (var service in request.Services) + { + var serviceEntity = await _serviceRepository.GetAsync(pd => pd.Id == service.ServiceId); + if (serviceEntity == null) + throw new ServiceNotFoundException(); + + var serviceQuotation = new ServiceQuotation + { + ServiceId = service.ServiceId, + QuotationId = quotation.Id, + Price = service.Price + }; + + quotation.ServiceQuotations.Add(serviceQuotation); + quotationRevision.TotalPrice += service.Price; + } + + quotation.QuotationRevisions.Add(quotationRevision); + await _quotationRepository.AddAsync(quotation); + var customer = await _userRepository.GetAsync(x => !x.IsDeleted && x.Id == quotation.CustomerId) ?? throw new UserNotFoundException("Customer not found"); + await _notificationRepository.AddAsync(new Notification() + { + RecipientId = NotificationHelper.ADMIN_ID, + Content = NotificationHelper.CreateNewQuotationMessage((string.IsNullOrEmpty(customer.FullName) || customer.FullName.Equals("N/A") ? customer.Email! : customer.FullName), quotation.Id), + SentAt = DateTime.Now, + Image = customer.ProfileImage ?? string.Empty, + RedirectString = $"staff/quotations/{quotation.Id}" + }); + + await _unitOfWork.CommitAsync(); + // return await GetQuotationById(quotation.Id); + return new ServiceActionResult(true); + } + + public async Task CreateQuotationByStaff(CreateQuotationRequest request, string customerId, string token) + { + var isValidToken = _jwtService.IsValidToken(token); + if (!isValidToken) + throw new InvalidTokenException(); + + if (request.PackageId != default && !await _packageRepository.ExistsAsync(p => !p.IsDeleted && p.Id == request.PackageId)) + throw new PackageNotFoundException(); + + var userId = _jwtService.GetTokenClaim(token, TokenClaimConstants.SUBJECT)?.ToString() ?? string.Empty; + var creator = await _userRepository.GetAsync(u => !u.IsDeleted && u.Id == userId) ?? throw new UserNotFoundException("Creator not found"); + var creatorRoles = await _userManager.GetRolesAsync(creator); + var createdByStaff = creatorRoles.Contains(UserRoleConstants.STAFF); + if (!createdByStaff) + throw new Service.Exceptions.UnauthorizedAccessException("You are not authorized to create quotation"); + + return await CreateQuotationGeneral(request, creator.Id, customerId, createdByStaff); + } + + public async Task CreateQuotationByCustomer(CreateQuotationRequest request, string token) + { + var isValidToken = _jwtService.IsValidToken(token); + if (!isValidToken) + throw new InvalidTokenException(); + + if (request.PackageId != default && !await _packageRepository.ExistsAsync(p => !p.IsDeleted && p.Id == request.PackageId)) + throw new PackageNotFoundException(); + + var userId = _jwtService.GetTokenClaim(token, TokenClaimConstants.SUBJECT)?.ToString() ?? string.Empty; + var creator = await _userRepository.GetAsync(u => !u.IsDeleted && u.Id == userId) ?? throw new UserNotFoundException("Creator not found"); + var creatorRoles = await _userManager.GetRolesAsync(creator); + var createdByStaff = creatorRoles.Contains(UserRoleConstants.STAFF); + if (createdByStaff) + throw new Service.Exceptions.UnauthorizedAccessException("You are not authorized to create quotation"); + + return await CreateQuotationGeneral(request, "c713aacc-3582-4598-8670-22590d837179", creator.Id, createdByStaff); + } } diff --git a/Domus.Service/Interfaces/IQuotationService.cs b/Domus.Service/Interfaces/IQuotationService.cs index 4a5c2f8..f2bdde0 100644 --- a/Domus.Service/Interfaces/IQuotationService.cs +++ b/Domus.Service/Interfaces/IQuotationService.cs @@ -9,6 +9,8 @@ namespace Domus.Service.Interfaces; public interface IQuotationService : IAutoRegisterable { Task CreateQuotation(CreateQuotationRequest request, string token); + Task CreateQuotationByStaff(CreateQuotationRequest request, string customerId, string token); + Task CreateQuotationByCustomer(CreateQuotationRequest request, string token); Task DeleteQuotation(Guid id); Task GetAllQuotations(); Task GetPaginatedQuotations(BasePaginatedRequest request);