using Indotalent.Infrastructure.Database; using MediatR; using Microsoft.EntityFrameworkCore; namespace Indotalent.Features.Purchase.DebitNote.Cqrs; public class DebitNoteItemResponse { public string? Id { get; set; } public string? ProductId { get; set; } public string? ProductName { get; set; } public decimal UnitPrice { get; set; } public double Quantity { get; set; } public decimal Total { get; set; } } public class GetDebitNoteByIdResponse { public string? Id { get; set; } public string? AutoNumber { get; set; } public DateTime? DebitNoteDate { get; set; } public Data.Enums.DebitNoteStatus DebitNoteStatus { get; set; } public string? Description { get; set; } public string? PurchaseReturnId { get; set; } public string? PurchaseReturnNumber { get; set; } public string? VendorName { get; set; } public string? VendorStreet { get; set; } public string? VendorCity { get; set; } public string? CompanyName { get; set; } public string? CompanyStreet { get; set; } public string? CompanyCity { get; set; } public string? CurrencySymbol { get; set; } public decimal BeforeTaxAmount { get; set; } public decimal TaxAmount { get; set; } public decimal AfterTaxAmount { get; set; } public DateTimeOffset? CreatedAt { get; set; } public string? CreatedBy { get; set; } public DateTimeOffset? UpdatedAt { get; set; } public string? UpdatedBy { get; set; } public List Items { get; set; } = new(); } public record GetDebitNoteByIdQuery(string Id) : IRequest; public class GetDebitNoteByIdHandler : IRequestHandler { private readonly AppDbContext _context; public GetDebitNoteByIdHandler(AppDbContext context) => _context = context; public async Task Handle(GetDebitNoteByIdQuery request, CancellationToken cancellationToken) { var company = await _context.Company .AsNoTracking() .Include(x => x.Currency) .OrderByDescending(x => x.IsDefault) .FirstOrDefaultAsync(cancellationToken); var debitNote = await _context.DebitNote .AsNoTracking() .Include(x => x.PurchaseReturn) .ThenInclude(pr => pr!.GoodsReceive) .ThenInclude(gr => gr!.PurchaseOrder) .ThenInclude(po => po!.Vendor) .Include(x => x.PurchaseReturn) .ThenInclude(pr => pr!.GoodsReceive) .ThenInclude(gr => gr!.PurchaseOrder) .ThenInclude(po => po!.Tax) .FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken); if (debitNote == null) return null; var purchaseOrder = debitNote.PurchaseReturn?.GoodsReceive?.PurchaseOrder; var taxRate = purchaseOrder?.Tax?.PercentageValue ?? 0; var transactions = await _context.InventoryTransaction .AsNoTracking() .Include(x => x.Product) .Where(x => x.ModuleId == debitNote.PurchaseReturnId && x.ModuleName == nameof(Data.Entities.PurchaseReturn)) .ToListAsync(cancellationToken); var items = new List(); decimal subTotal = 0; foreach (var trans in transactions) { var poItem = await _context.PurchaseOrderItem .AsNoTracking() .FirstOrDefaultAsync(x => x.PurchaseOrderId == purchaseOrder!.Id && x.ProductId == trans.ProductId, cancellationToken); var unitPrice = poItem?.UnitPrice ?? 0; var qty = Math.Abs(trans.Movement ?? 0); var total = unitPrice * (decimal)qty; items.Add(new DebitNoteItemResponse { Id = trans.Id, ProductId = trans.ProductId, ProductName = trans.Product?.Name, UnitPrice = unitPrice, Quantity = qty, Total = total }); subTotal += total; } var taxAmount = subTotal * (decimal)(taxRate / 100); return new GetDebitNoteByIdResponse { Id = debitNote.Id, AutoNumber = debitNote.AutoNumber, DebitNoteDate = debitNote.DebitNoteDate, DebitNoteStatus = debitNote.DebitNoteStatus, Description = debitNote.Description, PurchaseReturnId = debitNote.PurchaseReturnId, PurchaseReturnNumber = debitNote.PurchaseReturn?.AutoNumber, VendorName = purchaseOrder?.Vendor?.Name, VendorStreet = purchaseOrder?.Vendor?.Street, VendorCity = purchaseOrder?.Vendor?.City, CompanyName = company?.Name, CompanyStreet = company?.StreetAddress, CompanyCity = company?.City, CurrencySymbol = company?.Currency?.Symbol ?? "IDR", BeforeTaxAmount = subTotal, TaxAmount = taxAmount, AfterTaxAmount = subTotal + taxAmount, CreatedAt = debitNote.CreatedAt, CreatedBy = debitNote.CreatedBy, UpdatedAt = debitNote.UpdatedAt, UpdatedBy = debitNote.UpdatedBy, Items = items }; } }