initial commit
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using Indotalent.ConfigBackEnd.Extensions;
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class CreateBillRequest
|
||||
{
|
||||
public DateTime? BillDate { get; set; }
|
||||
public Data.Enums.BillStatus BillStatus { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? PurchaseOrderId { get; set; }
|
||||
}
|
||||
|
||||
public class CreateBillResponse
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? AutoNumber { get; set; }
|
||||
}
|
||||
|
||||
public record CreateBillCommand(CreateBillRequest Data) : IRequest<CreateBillResponse>;
|
||||
|
||||
public class CreateBillHandler : IRequestHandler<CreateBillCommand, CreateBillResponse>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public CreateBillHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<CreateBillResponse> Handle(CreateBillCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entityName = nameof(Data.Entities.Bill);
|
||||
var autoNo = await _context.GenerateAutoNumberAsync(
|
||||
entityName: entityName,
|
||||
prefixTemplate: $"BILL/{{Year}}/{{Month}}/",
|
||||
ct: cancellationToken
|
||||
);
|
||||
|
||||
var entity = new Data.Entities.Bill
|
||||
{
|
||||
AutoNumber = autoNo,
|
||||
BillDate = request.Data.BillDate,
|
||||
BillStatus = request.Data.BillStatus,
|
||||
Description = request.Data.Description,
|
||||
PurchaseOrderId = request.Data.PurchaseOrderId
|
||||
};
|
||||
|
||||
_context.Bill.Add(entity);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new CreateBillResponse
|
||||
{
|
||||
Id = entity.Id,
|
||||
AutoNumber = entity.AutoNumber
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class CreateBillValidator : AbstractValidator<CreateBillRequest>
|
||||
{
|
||||
public CreateBillValidator()
|
||||
{
|
||||
RuleFor(x => x.BillDate).NotEmpty().WithMessage("Bill Date is required");
|
||||
RuleFor(x => x.PurchaseOrderId).NotEmpty().WithMessage("Purchase Order is required");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public record DeleteBillByIdCommand(string Id) : IRequest<bool>;
|
||||
|
||||
public class DeleteBillByIdHandler : IRequestHandler<DeleteBillByIdCommand, bool>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public DeleteBillByIdHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<bool> Handle(DeleteBillByIdCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await _context.Bill
|
||||
.FirstOrDefaultAsync(x => x.Id == request.Id, cancellationToken);
|
||||
|
||||
if (entity == null) return false;
|
||||
|
||||
_context.Bill.Remove(entity);
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class BillPurchaseOrderItemResponse
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? ProductId { get; set; }
|
||||
public string? ProductName { get; set; }
|
||||
public string? Summary { get; set; }
|
||||
public decimal? UnitPrice { get; set; }
|
||||
public double? Quantity { get; set; }
|
||||
public decimal? Total { get; set; }
|
||||
}
|
||||
|
||||
public class GetBillByIdResponse
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? AutoNumber { get; set; }
|
||||
public DateTime? BillDate { get; set; }
|
||||
public Data.Enums.BillStatus BillStatus { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? PurchaseOrderId { get; set; }
|
||||
public string? PurchaseOrderAutoNumber { 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<BillPurchaseOrderItemResponse> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public record GetBillByIdQuery(string Id) : IRequest<GetBillByIdResponse?>;
|
||||
|
||||
public class GetBillByIdHandler : IRequestHandler<GetBillByIdQuery, GetBillByIdResponse?>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public GetBillByIdHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<GetBillByIdResponse?> Handle(GetBillByIdQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var company = await _context.Company
|
||||
.AsNoTracking()
|
||||
.Include(x => x.Currency)
|
||||
.OrderByDescending(x => x.IsDefault)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
|
||||
return await _context.Bill
|
||||
.AsNoTracking()
|
||||
.Include(x => x.PurchaseOrder)
|
||||
.ThenInclude(po => po!.Vendor)
|
||||
.Include(x => x.PurchaseOrder)
|
||||
.ThenInclude(po => po!.PurchaseOrderItemList)
|
||||
.ThenInclude(i => i.Product)
|
||||
.Where(x => x.Id == request.Id)
|
||||
.Select(x => new GetBillByIdResponse
|
||||
{
|
||||
Id = x.Id,
|
||||
AutoNumber = x.AutoNumber,
|
||||
BillDate = x.BillDate,
|
||||
BillStatus = x.BillStatus,
|
||||
Description = x.Description,
|
||||
PurchaseOrderId = x.PurchaseOrderId,
|
||||
PurchaseOrderAutoNumber = x.PurchaseOrder!.AutoNumber,
|
||||
VendorName = x.PurchaseOrder!.Vendor!.Name,
|
||||
VendorStreet = x.PurchaseOrder!.Vendor!.Street,
|
||||
VendorCity = x.PurchaseOrder!.Vendor!.City,
|
||||
CompanyName = company != null ? company.Name : string.Empty,
|
||||
CompanyStreet = company != null ? company.StreetAddress : string.Empty,
|
||||
CompanyCity = company != null ? company.City : string.Empty,
|
||||
CurrencySymbol = company != null && company.Currency != null ? company.Currency.Symbol : "IDR",
|
||||
BeforeTaxAmount = x.PurchaseOrder!.BeforeTaxAmount,
|
||||
TaxAmount = x.PurchaseOrder!.TaxAmount,
|
||||
AfterTaxAmount = x.PurchaseOrder!.AfterTaxAmount,
|
||||
CreatedAt = x.CreatedAt,
|
||||
CreatedBy = x.CreatedBy,
|
||||
UpdatedAt = x.UpdatedAt,
|
||||
UpdatedBy = x.UpdatedBy,
|
||||
Items = x.PurchaseOrder!.PurchaseOrderItemList.Select(i => new BillPurchaseOrderItemResponse
|
||||
{
|
||||
Id = i.Id,
|
||||
ProductId = i.ProductId,
|
||||
ProductName = i.Product!.Name,
|
||||
Summary = i.Summary,
|
||||
UnitPrice = i.UnitPrice,
|
||||
Quantity = i.Quantity,
|
||||
Total = i.Total
|
||||
}).ToList()
|
||||
}).FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class GetBillListResponse
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? AutoNumber { get; set; }
|
||||
public DateTime? BillDate { get; set; }
|
||||
public string? PurchaseOrderAutoNumber { get; set; }
|
||||
public string? VendorName { get; set; }
|
||||
public decimal? AfterTaxAmount { get; set; }
|
||||
public Data.Enums.BillStatus BillStatus { get; set; }
|
||||
}
|
||||
|
||||
public record GetBillListQuery() : IRequest<List<GetBillListResponse>>;
|
||||
|
||||
public class GetBillListHandler : IRequestHandler<GetBillListQuery, List<GetBillListResponse>>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public GetBillListHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<List<GetBillListResponse>> Handle(GetBillListQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _context.Bill
|
||||
.AsNoTracking()
|
||||
.Include(x => x.PurchaseOrder)
|
||||
.ThenInclude(po => po!.Vendor)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.Select(x => new GetBillListResponse
|
||||
{
|
||||
Id = x.Id,
|
||||
AutoNumber = x.AutoNumber,
|
||||
BillDate = x.BillDate,
|
||||
PurchaseOrderAutoNumber = x.PurchaseOrder!.AutoNumber,
|
||||
VendorName = x.PurchaseOrder!.Vendor!.Name,
|
||||
AfterTaxAmount = x.PurchaseOrder!.AfterTaxAmount,
|
||||
BillStatus = x.BillStatus
|
||||
}).ToListAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Indotalent.Data.Enums;
|
||||
using Indotalent.ConfigBackEnd.Extensions;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class BillLookupResponse
|
||||
{
|
||||
public List<LookupItem> PurchaseOrders { get; set; } = new();
|
||||
public List<LookupStatusItem> Statuses { get; set; } = new();
|
||||
}
|
||||
|
||||
public class LookupItem
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
public class LookupStatusItem
|
||||
{
|
||||
public int Value { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
public record GetBillLookupQuery() : IRequest<BillLookupResponse>;
|
||||
|
||||
public class GetBillLookupHandler : IRequestHandler<GetBillLookupQuery, BillLookupResponse>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public GetBillLookupHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<BillLookupResponse> Handle(GetBillLookupQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = new BillLookupResponse();
|
||||
|
||||
response.PurchaseOrders = await _context.PurchaseOrder.AsNoTracking()
|
||||
.Where(x => x.OrderStatus == PurchaseOrderStatus.Confirmed)
|
||||
.OrderByDescending(x => x.CreatedAt)
|
||||
.Select(x => new LookupItem { Id = x.Id, Name = x.AutoNumber })
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
response.Statuses = Enum.GetValues(typeof(BillStatus))
|
||||
.Cast<BillStatus>()
|
||||
.Select(x => new LookupStatusItem
|
||||
{
|
||||
Value = (int)x,
|
||||
Name = x.GetDescription()
|
||||
}).ToList();
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public record GetPurchaseOrderDetailForBillQuery(string PurchaseOrderId) : IRequest<GetBillByIdResponse?>;
|
||||
|
||||
public class GetPurchaseOrderDetailForBillHandler : IRequestHandler<GetPurchaseOrderDetailForBillQuery, GetBillByIdResponse?>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public GetPurchaseOrderDetailForBillHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<GetBillByIdResponse?> Handle(GetPurchaseOrderDetailForBillQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
return await _context.PurchaseOrder
|
||||
.AsNoTracking()
|
||||
.Include(x => x.PurchaseOrderItemList)
|
||||
.ThenInclude(i => i.Product)
|
||||
.Where(x => x.Id == request.PurchaseOrderId)
|
||||
.Select(x => new GetBillByIdResponse
|
||||
{
|
||||
PurchaseOrderId = x.Id,
|
||||
BeforeTaxAmount = x.BeforeTaxAmount,
|
||||
TaxAmount = x.TaxAmount,
|
||||
AfterTaxAmount = x.AfterTaxAmount,
|
||||
Items = x.PurchaseOrderItemList.Select(i => new BillPurchaseOrderItemResponse
|
||||
{
|
||||
Id = i.Id,
|
||||
ProductId = i.ProductId,
|
||||
ProductName = i.Product!.Name,
|
||||
Summary = i.Summary,
|
||||
UnitPrice = i.UnitPrice,
|
||||
Quantity = i.Quantity,
|
||||
Total = i.Total
|
||||
}).ToList()
|
||||
}).FirstOrDefaultAsync(cancellationToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Indotalent.Infrastructure.Database;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class UpdateBillRequest
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
public DateTime? BillDate { get; set; }
|
||||
public Data.Enums.BillStatus BillStatus { get; set; }
|
||||
public string? AutoNumber { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? PurchaseOrderId { get; set; }
|
||||
public DateTimeOffset? CreatedAt { get; set; }
|
||||
public string? CreatedBy { get; set; }
|
||||
public DateTimeOffset? UpdatedAt { get; set; }
|
||||
public string? UpdatedBy { get; set; }
|
||||
}
|
||||
|
||||
public record UpdateBillCommand(UpdateBillRequest Data) : IRequest<bool>;
|
||||
|
||||
public class UpdateBillHandler : IRequestHandler<UpdateBillCommand, bool>
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
public UpdateBillHandler(AppDbContext context) => _context = context;
|
||||
|
||||
public async Task<bool> Handle(UpdateBillCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var entity = await _context.Bill
|
||||
.FirstOrDefaultAsync(x => x.Id == request.Data.Id, cancellationToken);
|
||||
|
||||
if (entity == null) return false;
|
||||
|
||||
entity.BillDate = request.Data.BillDate;
|
||||
entity.BillStatus = request.Data.BillStatus;
|
||||
entity.Description = request.Data.Description;
|
||||
entity.PurchaseOrderId = request.Data.PurchaseOrderId;
|
||||
|
||||
await _context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using FluentValidation;
|
||||
|
||||
namespace Indotalent.Features.Purchase.Bill.Cqrs;
|
||||
|
||||
public class UpdateBillValidator : AbstractValidator<UpdateBillRequest>
|
||||
{
|
||||
public UpdateBillValidator()
|
||||
{
|
||||
RuleFor(x => x.Id).NotEmpty();
|
||||
RuleFor(x => x.PurchaseOrderId).NotEmpty().WithMessage("Purchase Order is required");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user