91 lines
3.5 KiB
C#
91 lines
3.5 KiB
C#
using Distribution.Features.Stock;
|
|
using Distribution.Infra.Authorization;
|
|
using Distribution.Infra.UoW;
|
|
using Distribution.Models;
|
|
|
|
namespace Distribution.Features.Invoice;
|
|
|
|
public class InvoiceService(
|
|
IInvoiceRepository repo,
|
|
IUnitOfWork uow,
|
|
ICurrentUserService currentUser)
|
|
{
|
|
private static InvoiceResponse ToResponse(Models.Invoice i) =>
|
|
new(i.Id, i.FK_ShopPOId,
|
|
i.ShopPO?.Store?.StoreName ?? string.Empty,
|
|
i.Status, i.PaymentStatus, i.CreatedBy,
|
|
i.PrintedAt, i.PrintedBy,
|
|
i.FinalizedAt, i.FinalizedBy,
|
|
i.TotalAmount, i.IsActive, i.CreatedAt);
|
|
|
|
public async Task<InvoiceResponse?> GetByIdAsync(Guid id)
|
|
{
|
|
var invoice = await repo.GetByIdAsync(id);
|
|
return invoice is null ? null : ToResponse(invoice);
|
|
}
|
|
|
|
public async Task<PagedResponse<InvoiceResponse>> GetAllAsync(Guid? agentId, Guid? routeId, Guid? shopId, InvoiceStatus? status, int page, int pageSize)
|
|
{
|
|
var total = await repo.GetCountAsync(agentId, routeId, shopId, status);
|
|
var items = await repo.GetAllAsync(agentId, routeId, shopId, status, page, pageSize);
|
|
return new PagedResponse<InvoiceResponse>(page, pageSize, total, items.Select(ToResponse).ToList());
|
|
}
|
|
|
|
public async Task<InvoiceResponse> PrintAsync(Guid id, Guid printedBy, CancellationToken ct = default)
|
|
{
|
|
var invoice = await repo.GetByIdAsync(id)
|
|
?? throw new KeyNotFoundException("Invoice not found");
|
|
|
|
if (invoice.Status != InvoiceStatus.Draft)
|
|
throw new InvalidOperationException($"Cannot print an invoice in {invoice.Status} status");
|
|
|
|
invoice.Status = InvoiceStatus.Printed;
|
|
invoice.PrintedAt = DateTime.Now;
|
|
invoice.PrintedBy = printedBy;
|
|
|
|
await uow.BeginAsync(ct);
|
|
try { repo.Update(invoice); await uow.CommitAsync(ct); }
|
|
catch { await uow.RollbackAsync(ct); throw; }
|
|
|
|
return ToResponse(invoice);
|
|
}
|
|
|
|
public async Task<InvoiceResponse> FinalizeAsync(Guid id, FinalizeInvoiceRequest request, Guid finalizedBy, CancellationToken ct = default)
|
|
{
|
|
var invoice = await repo.GetByIdAsync(id)
|
|
?? throw new KeyNotFoundException("Invoice not found");
|
|
|
|
if (invoice.Status != InvoiceStatus.Printed)
|
|
throw new InvalidOperationException($"Cannot finalize an invoice in {invoice.Status} status");
|
|
|
|
var adjustments = request.Adjustments ?? [];
|
|
if (adjustments.Count > 0)
|
|
{
|
|
var poItems = invoice.ShopPO.Items.Where(i => i.IsActive).ToList();
|
|
decimal total = 0;
|
|
foreach (var item in poItems)
|
|
{
|
|
var adjustment = adjustments.FirstOrDefault(a => a.ShopPOItemId == item.Id);
|
|
var billedQuantity = adjustment is not null ? adjustment.AdjustedQuantity : item.Quantity;
|
|
|
|
if (billedQuantity < 0 || billedQuantity > item.Quantity)
|
|
throw new InvalidOperationException(
|
|
$"Adjusted quantity for item {item.Id} must be between 0 and {item.Quantity}");
|
|
|
|
total += billedQuantity * item.UnitPrice;
|
|
}
|
|
invoice.TotalAmount = total;
|
|
}
|
|
|
|
invoice.Status = InvoiceStatus.Finalized;
|
|
invoice.FinalizedAt = DateTime.Now;
|
|
invoice.FinalizedBy = finalizedBy;
|
|
|
|
await uow.BeginAsync(ct);
|
|
try { repo.Update(invoice); await uow.CommitAsync(ct); }
|
|
catch { await uow.RollbackAsync(ct); throw; }
|
|
|
|
return ToResponse(invoice);
|
|
}
|
|
}
|