Refactor sales pipeline: ShopPO, Invoice, SysConfig models
Major refactor replacing Sale/Order with ShopPO → Invoice → LoadingSheet flow. Removed legacy Sale/Order models and features; introduced ShopPO, ShopPOItem, Invoice, LoadingSheetOrder, and SysConfig models. Updated related entities, enums, repositories, and controllers. Added new migrations for schema changes and system config. Overhauled business logic and DI registrations. Updated documentation with migration plan.
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
using Distribution.Models;
|
||||
|
||||
namespace Distribution.Features.ShopPO;
|
||||
|
||||
public interface IShopPORepository
|
||||
{
|
||||
Task<Models.ShopPO?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.ShopPO>> GetAllAsync(Guid? agentId, Guid? routeId, Guid? shopId, bool? confirmed, int page, int pageSize);
|
||||
Task<int> GetCountAsync(Guid? agentId, Guid? routeId, Guid? shopId, bool? confirmed);
|
||||
Task<List<Models.ShopPO>> GetConfirmedWithoutInvoiceAsync(Guid? agentId, Guid? routeId, Guid? shopId);
|
||||
Task<List<Models.ShopPOItem>> GetActiveItemsByShopPOIdAsync(Guid shopPOId);
|
||||
Task<List<Models.ShopPO>> GetByStoreIdAsync(Guid storeId);
|
||||
Task AddAsync(Models.ShopPO entity);
|
||||
void Update(Models.ShopPO entity);
|
||||
void Remove(Models.ShopPO entity);
|
||||
Task AddItemsAsync(IEnumerable<Models.ShopPOItem> items);
|
||||
Task ReplaceItemsAsync(Guid shopPOId, List<Models.ShopPOItem> newItems);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.ShopPO;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/shop-pos")]
|
||||
public class ShopPOController(ShopPOService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll(
|
||||
[FromQuery] Guid? agentId,
|
||||
[FromQuery] Guid? routeId,
|
||||
[FromQuery] Guid? shopId,
|
||||
[FromQuery] bool? confirmed,
|
||||
[FromQuery] int page = 1,
|
||||
[FromQuery] int pageSize = 20)
|
||||
{
|
||||
var result = await service.GetAllAsync(agentId, routeId, shopId, confirmed, page, pageSize);
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Distribution.Models;
|
||||
|
||||
namespace Distribution.Features.ShopPO;
|
||||
|
||||
public record CreateShopPORequest(Guid StoreId, List<ShopPOItemRequest> Items);
|
||||
public record ShopPOItemRequest(Guid ItemId, int Quantity, decimal? UnitPrice = null);
|
||||
public record UpdateShopPOItemsRequest(List<ShopPOItemRequest> Items);
|
||||
|
||||
public record ShopPOItemResponse(Guid Id, Guid ItemId, string ItemName, int Quantity, int QuantityFulfilled, decimal UnitPrice, bool IsActive);
|
||||
|
||||
public record ShopPOResponse(
|
||||
Guid Id,
|
||||
Guid StoreId,
|
||||
string StoreName,
|
||||
Guid RaisedById,
|
||||
Guid? InvoiceId,
|
||||
decimal TotalAmount,
|
||||
ShopPOStatus Status,
|
||||
DateTime? ConfirmedAt,
|
||||
Guid? ConfirmedBy,
|
||||
DateTime? FulfilledAt,
|
||||
List<ShopPOItemResponse> Items,
|
||||
bool IsActive,
|
||||
DateTime CreatedAt);
|
||||
@@ -0,0 +1,91 @@
|
||||
using Distribution.Data;
|
||||
using Distribution.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.ShopPO;
|
||||
|
||||
public class ShopPORepository(AppDBContext context) : IShopPORepository
|
||||
{
|
||||
public async Task<Models.ShopPO?> GetByIdAsync(Guid id) =>
|
||||
await context.ShopPOs
|
||||
.Include(p => p.Store)
|
||||
.Include(p => p.Items.Where(i => i.IsActive))
|
||||
.ThenInclude(i => i.Item)
|
||||
.FirstOrDefaultAsync(p => p.Id == id && p.IsActive);
|
||||
|
||||
public async Task<List<Models.ShopPO>> GetAllAsync(Guid? agentId, Guid? routeId, Guid? shopId, bool? confirmed, int page, int pageSize) =>
|
||||
await context.ShopPOs
|
||||
.Include(p => p.Store)
|
||||
.Where(p => p.IsActive
|
||||
&& (agentId == null || p.RaisedById == agentId)
|
||||
&& (routeId == null || p.Store.FK_RouteId == routeId)
|
||||
&& (shopId == null || p.FK_StoreId == shopId)
|
||||
&& (confirmed == null || (confirmed == true ? p.ConfirmedAt != null : p.ConfirmedAt == null)))
|
||||
.OrderByDescending(p => p.CreatedAt)
|
||||
.Skip((page - 1) * pageSize)
|
||||
.Take(pageSize)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<int> GetCountAsync(Guid? agentId, Guid? routeId, Guid? shopId, bool? confirmed) =>
|
||||
await context.ShopPOs
|
||||
.Include(p => p.Store)
|
||||
.CountAsync(p => p.IsActive
|
||||
&& (agentId == null || p.RaisedById == agentId)
|
||||
&& (routeId == null || p.Store.FK_RouteId == routeId)
|
||||
&& (shopId == null || p.FK_StoreId == shopId)
|
||||
&& (confirmed == null || (confirmed == true ? p.ConfirmedAt != null : p.ConfirmedAt == null)));
|
||||
|
||||
public async Task<List<Models.ShopPO>> GetConfirmedWithoutInvoiceAsync(Guid? agentId, Guid? routeId, Guid? shopId) =>
|
||||
await context.ShopPOs
|
||||
.Include(p => p.Store)
|
||||
.Include(p => p.Items.Where(i => i.IsActive))
|
||||
.Where(p => p.IsActive
|
||||
&& p.ConfirmedAt != null
|
||||
&& p.InvoiceId == null
|
||||
&& (agentId == null || p.RaisedById == agentId)
|
||||
&& (routeId == null || p.Store.FK_RouteId == routeId)
|
||||
&& (shopId == null || p.FK_StoreId == shopId))
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<List<Models.ShopPOItem>> GetActiveItemsByShopPOIdAsync(Guid shopPOId) =>
|
||||
await context.ShopPOItems
|
||||
.Include(i => i.Item)
|
||||
.Where(i => i.FK_ShopPOId == shopPOId && i.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task<List<Models.ShopPO>> GetByStoreIdAsync(Guid storeId) =>
|
||||
await context.ShopPOs
|
||||
.Include(p => p.Items.Where(i => i.IsActive))
|
||||
.Where(p => p.FK_StoreId == storeId && p.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.ShopPO entity) =>
|
||||
await context.ShopPOs.AddAsync(entity);
|
||||
|
||||
public void Update(Models.ShopPO entity) =>
|
||||
context.ShopPOs.Update(entity);
|
||||
|
||||
public void Remove(Models.ShopPO entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.ShopPOs.Update(entity);
|
||||
}
|
||||
|
||||
public async Task AddItemsAsync(IEnumerable<Models.ShopPOItem> items) =>
|
||||
await context.ShopPOItems.AddRangeAsync(items);
|
||||
|
||||
public async Task ReplaceItemsAsync(Guid shopPOId, List<Models.ShopPOItem> newItems)
|
||||
{
|
||||
var current = await context.ShopPOItems
|
||||
.Where(i => i.FK_ShopPOId == shopPOId && i.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var item in current)
|
||||
{
|
||||
item.IsActive = false;
|
||||
context.ShopPOItems.Update(item);
|
||||
}
|
||||
|
||||
await context.ShopPOItems.AddRangeAsync(newItems);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using Distribution.Features.Stock;
|
||||
using Distribution.Infra.UoW;
|
||||
using Distribution.Models;
|
||||
|
||||
namespace Distribution.Features.ShopPO;
|
||||
|
||||
public class ShopPOService(
|
||||
IShopPORepository repo,
|
||||
IUnitOfWork uow)
|
||||
{
|
||||
private static ShopPOResponse ToResponse(Models.ShopPO p) =>
|
||||
new(p.Id, p.FK_StoreId, p.Store?.StoreName ?? string.Empty,
|
||||
p.RaisedById, p.InvoiceId, p.TotalAmount, p.Status,
|
||||
p.ConfirmedAt, p.ConfirmedBy, p.FulfilledAt,
|
||||
p.Items.Where(i => i.IsActive).Select(i =>
|
||||
new ShopPOItemResponse(i.Id, i.FK_ItemId, i.Item?.Name ?? string.Empty,
|
||||
i.Quantity, i.QuantityFulfilled, i.UnitPrice, i.IsActive)).ToList(),
|
||||
p.IsActive, p.CreatedAt);
|
||||
|
||||
public async Task<PagedResponse<ShopPOResponse>> GetAllAsync(Guid? agentId, Guid? routeId, Guid? shopId, bool? confirmed, int page, int pageSize)
|
||||
{
|
||||
var total = await repo.GetCountAsync(agentId, routeId, shopId, confirmed);
|
||||
var items = await repo.GetAllAsync(agentId, routeId, shopId, confirmed, page, pageSize);
|
||||
return new PagedResponse<ShopPOResponse>(page, pageSize, total, items.Select(ToResponse).ToList());
|
||||
}
|
||||
|
||||
public async Task<ShopPOResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var po = await repo.GetByIdAsync(id);
|
||||
return po is null ? null : ToResponse(po);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user