Initial project setup with domain, UoW, and API structure
Added .gitignore, solution, and project files for .NET 10. Introduced AGENTS.md and PLAN.md for guidelines and planning. Implemented appsettings.json, launchSettings.json, and MySQL config. Created AppDBContext and all domain models with composite keys. Added IUnitOfWork and EFUnitOfWork. Structured feature folders for Region, Route, Vehicle, Store, Warehouse, and Order with DTOs, repositories, services, and controllers. Added initial EF Core migrations and sample HTTP request. Registered dependencies and enabled OpenAPI in development.
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
namespace Distribution.Features.Order;
|
||||
|
||||
public interface IOrderRepository
|
||||
{
|
||||
Task<Models.Order?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.Order>> GetAllAsync();
|
||||
Task AddAsync(Models.Order entity);
|
||||
void Update(Models.Order entity);
|
||||
void Remove(Models.Order entity);
|
||||
Task<List<Models.OrderItem>> GetItemsByOrderIdAsync(Guid orderId);
|
||||
Task<List<Models.Order>> GetByStoreIdAsync(Guid storeId);
|
||||
Task AddItemsAsync(IEnumerable<Models.OrderItem> items);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Order;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/orders")]
|
||||
public class OrderController(OrderService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpGet("store/{storeId:guid}")]
|
||||
public async Task<IActionResult> GetByStore(Guid storeId) =>
|
||||
Ok(await service.GetByStoreIdAsync(storeId));
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(CreateOrderRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.CreateAsync(request, ct);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<IActionResult> Update(Guid id, UpdateOrderRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.UpdateAsync(id, request, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
var deleted = await service.DeleteAsync(id, ct);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace Distribution.Features.Order;
|
||||
|
||||
public record OrderItemRequest(Guid ItemId, int Quantity);
|
||||
|
||||
public record CreateOrderRequest(Guid StoreId, DateTime OrderDate, decimal TotalAmount, List<OrderItemRequest> Items);
|
||||
|
||||
public record UpdateOrderRequest(DateTime OrderDate, decimal TotalAmount);
|
||||
|
||||
public record OrderItemResponse(Guid ItemId, int Quantity);
|
||||
|
||||
public record OrderResponse(
|
||||
Guid Id,
|
||||
DateTime OrderDate,
|
||||
Guid StoreId,
|
||||
decimal TotalAmount,
|
||||
List<OrderItemResponse> Items,
|
||||
bool IsActive,
|
||||
DateTime CreatedAt);
|
||||
@@ -0,0 +1,34 @@
|
||||
using Distribution.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Order;
|
||||
|
||||
public class OrderRepository(AppDBContext context) : IOrderRepository
|
||||
{
|
||||
public async Task<Models.Order?> GetByIdAsync(Guid id) =>
|
||||
await context.Orders.FindAsync(id);
|
||||
|
||||
public async Task<List<Models.Order>> GetAllAsync() =>
|
||||
await context.Orders.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.Order entity) =>
|
||||
await context.Orders.AddAsync(entity);
|
||||
|
||||
public void Update(Models.Order entity) =>
|
||||
context.Orders.Update(entity);
|
||||
|
||||
public void Remove(Models.Order entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.Orders.Update(entity);
|
||||
}
|
||||
|
||||
public async Task<List<Models.OrderItem>> GetItemsByOrderIdAsync(Guid orderId) =>
|
||||
await context.OrderItems.Where(oi => oi.FK_OrderId == orderId).ToListAsync();
|
||||
|
||||
public async Task<List<Models.Order>> GetByStoreIdAsync(Guid storeId) =>
|
||||
await context.Orders.Where(o => o.FK_StoreId == storeId && o.IsActive).ToListAsync();
|
||||
|
||||
public async Task AddItemsAsync(IEnumerable<Models.OrderItem> items) =>
|
||||
await context.OrderItems.AddRangeAsync(items);
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Order;
|
||||
|
||||
public class OrderService(IOrderRepository repo, IUnitOfWork uow)
|
||||
{
|
||||
private static OrderResponse ToResponse(Models.Order o, List<Models.OrderItem> items) =>
|
||||
new(o.Id, o.OrderDate, o.FK_StoreId, o.TotalAmount,
|
||||
items.Select(i => new OrderItemResponse(i.FK_ItemId, i.Quantity)).ToList(),
|
||||
o.IsActive, o.CreatedAt);
|
||||
|
||||
public async Task<List<OrderResponse>> GetAllAsync()
|
||||
{
|
||||
var orders = (await repo.GetAllAsync()).Where(o => o.IsActive).ToList();
|
||||
var result = new List<OrderResponse>();
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var items = await repo.GetItemsByOrderIdAsync(order.Id);
|
||||
result.Add(ToResponse(order, items));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<OrderResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var order = await repo.GetByIdAsync(id);
|
||||
if (order is null || !order.IsActive) return null;
|
||||
var items = await repo.GetItemsByOrderIdAsync(id);
|
||||
return ToResponse(order, items);
|
||||
}
|
||||
|
||||
public async Task<List<OrderResponse>> GetByStoreIdAsync(Guid storeId)
|
||||
{
|
||||
var orders = await repo.GetByStoreIdAsync(storeId);
|
||||
var result = new List<OrderResponse>();
|
||||
foreach (var order in orders)
|
||||
{
|
||||
var items = await repo.GetItemsByOrderIdAsync(order.Id);
|
||||
result.Add(ToResponse(order, items));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<OrderResponse> CreateAsync(CreateOrderRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var order = new Models.Order
|
||||
{
|
||||
FK_StoreId = request.StoreId,
|
||||
OrderDate = request.OrderDate,
|
||||
TotalAmount = request.TotalAmount
|
||||
};
|
||||
var orderItems = request.Items.Select(i => new Models.OrderItem
|
||||
{
|
||||
FK_OrderId = order.Id,
|
||||
FK_ItemId = i.ItemId,
|
||||
Quantity = i.Quantity
|
||||
}).ToList();
|
||||
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
await repo.AddAsync(order);
|
||||
await repo.AddItemsAsync(orderItems);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return ToResponse(order, orderItems);
|
||||
}
|
||||
|
||||
public async Task<OrderResponse?> UpdateAsync(Guid id, UpdateOrderRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var order = await repo.GetByIdAsync(id);
|
||||
if (order is null || !order.IsActive) return null;
|
||||
order.OrderDate = request.OrderDate;
|
||||
order.TotalAmount = request.TotalAmount;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(order);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
var items = await repo.GetItemsByOrderIdAsync(id);
|
||||
return ToResponse(order, items);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var order = await repo.GetByIdAsync(id);
|
||||
if (order is null || !order.IsActive) return false;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Remove(order);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Distribution.Features.Region;
|
||||
|
||||
public interface IRegionRepository
|
||||
{
|
||||
Task<Models.Region?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.Region>> GetAllAsync();
|
||||
Task AddAsync(Models.Region entity);
|
||||
void Update(Models.Region entity);
|
||||
void Remove(Models.Region entity);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Region;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/regions")]
|
||||
public class RegionController(RegionService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(CreateRegionRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.CreateAsync(request, ct);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<IActionResult> Update(Guid id, UpdateRegionRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.UpdateAsync(id, request, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
var deleted = await service.DeleteAsync(id, ct);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Distribution.Features.Region;
|
||||
|
||||
public record CreateRegionRequest(string Name);
|
||||
|
||||
public record UpdateRegionRequest(string Name);
|
||||
|
||||
public record RegionResponse(Guid Id, string Name, bool IsActive, DateTime CreatedAt);
|
||||
@@ -0,0 +1,25 @@
|
||||
using Distribution.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Region;
|
||||
|
||||
public class RegionRepository(AppDBContext context) : IRegionRepository
|
||||
{
|
||||
public async Task<Models.Region?> GetByIdAsync(Guid id) =>
|
||||
await context.Regions.FindAsync(id);
|
||||
|
||||
public async Task<List<Models.Region>> GetAllAsync() =>
|
||||
await context.Regions.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.Region entity) =>
|
||||
await context.Regions.AddAsync(entity);
|
||||
|
||||
public void Update(Models.Region entity) =>
|
||||
context.Regions.Update(entity);
|
||||
|
||||
public void Remove(Models.Region entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.Regions.Update(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Region;
|
||||
|
||||
public class RegionService(IRegionRepository repo, IUnitOfWork uow)
|
||||
{
|
||||
public async Task<List<RegionResponse>> GetAllAsync() =>
|
||||
(await repo.GetAllAsync())
|
||||
.Where(r => r.IsActive)
|
||||
.Select(r => new RegionResponse(r.Id, r.Name, r.IsActive, r.CreatedAt))
|
||||
.ToList();
|
||||
|
||||
public async Task<RegionResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var region = await repo.GetByIdAsync(id);
|
||||
if (region is null || !region.IsActive) return null;
|
||||
return new RegionResponse(region.Id, region.Name, region.IsActive, region.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<RegionResponse> CreateAsync(CreateRegionRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var region = new Models.Region { Name = request.Name };
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
await repo.AddAsync(region);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return new RegionResponse(region.Id, region.Name, region.IsActive, region.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<RegionResponse?> UpdateAsync(Guid id, UpdateRegionRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var region = await repo.GetByIdAsync(id);
|
||||
if (region is null || !region.IsActive) return null;
|
||||
region.Name = request.Name;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(region);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return new RegionResponse(region.Id, region.Name, region.IsActive, region.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var region = await repo.GetByIdAsync(id);
|
||||
if (region is null || !region.IsActive) return false;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Remove(region);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Distribution.Features.Route;
|
||||
|
||||
public interface IRouteRepository
|
||||
{
|
||||
Task<Models.Route?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.Route>> GetAllAsync();
|
||||
Task AddAsync(Models.Route entity);
|
||||
void Update(Models.Route entity);
|
||||
void Remove(Models.Route entity);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Route;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/routes")]
|
||||
public class RouteController(RouteService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(CreateRouteRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.CreateAsync(request, ct);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<IActionResult> Update(Guid id, UpdateRouteRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.UpdateAsync(id, request, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
var deleted = await service.DeleteAsync(id, ct);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Distribution.Features.Route;
|
||||
|
||||
public record CreateRouteRequest(string RouteName, string StartPoint, string EndPoint, decimal Length);
|
||||
|
||||
public record UpdateRouteRequest(string RouteName, string StartPoint, string EndPoint, decimal Length);
|
||||
|
||||
public record RouteResponse(Guid Id, string RouteName, string StartPoint, string EndPoint, decimal Length, bool IsActive, DateTime CreatedAt);
|
||||
@@ -0,0 +1,25 @@
|
||||
using Distribution.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Route;
|
||||
|
||||
public class RouteRepository(AppDBContext context) : IRouteRepository
|
||||
{
|
||||
public async Task<Models.Route?> GetByIdAsync(Guid id) =>
|
||||
await context.Routes.FindAsync(id);
|
||||
|
||||
public async Task<List<Models.Route>> GetAllAsync() =>
|
||||
await context.Routes.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.Route entity) =>
|
||||
await context.Routes.AddAsync(entity);
|
||||
|
||||
public void Update(Models.Route entity) =>
|
||||
context.Routes.Update(entity);
|
||||
|
||||
public void Remove(Models.Route entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.Routes.Update(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Route;
|
||||
|
||||
public class RouteService(IRouteRepository repo, IUnitOfWork uow)
|
||||
{
|
||||
public async Task<List<RouteResponse>> GetAllAsync() =>
|
||||
(await repo.GetAllAsync())
|
||||
.Where(r => r.IsActive)
|
||||
.Select(r => new RouteResponse(r.Id, r.RouteName, r.StartPoint, r.EndPoint, r.Length, r.IsActive, r.CreatedAt))
|
||||
.ToList();
|
||||
|
||||
public async Task<RouteResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var route = await repo.GetByIdAsync(id);
|
||||
if (route is null || !route.IsActive) return null;
|
||||
return new RouteResponse(route.Id, route.RouteName, route.StartPoint, route.EndPoint, route.Length, route.IsActive, route.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<RouteResponse> CreateAsync(CreateRouteRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var route = new Models.Route
|
||||
{
|
||||
RouteName = request.RouteName,
|
||||
StartPoint = request.StartPoint,
|
||||
EndPoint = request.EndPoint,
|
||||
Length = request.Length
|
||||
};
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
await repo.AddAsync(route);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return new RouteResponse(route.Id, route.RouteName, route.StartPoint, route.EndPoint, route.Length, route.IsActive, route.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<RouteResponse?> UpdateAsync(Guid id, UpdateRouteRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var route = await repo.GetByIdAsync(id);
|
||||
if (route is null || !route.IsActive) return null;
|
||||
route.RouteName = request.RouteName;
|
||||
route.StartPoint = request.StartPoint;
|
||||
route.EndPoint = request.EndPoint;
|
||||
route.Length = request.Length;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(route);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return new RouteResponse(route.Id, route.RouteName, route.StartPoint, route.EndPoint, route.Length, route.IsActive, route.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var route = await repo.GetByIdAsync(id);
|
||||
if (route is null || !route.IsActive) return false;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Remove(route);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
public interface IStoreRepository
|
||||
{
|
||||
Task<Models.Store?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.Store>> GetAllAsync();
|
||||
Task AddAsync(Models.Store entity);
|
||||
void Update(Models.Store entity);
|
||||
void Remove(Models.Store entity);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/stores")]
|
||||
public class StoreController(StoreService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(CreateStoreRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.CreateAsync(request, ct);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<IActionResult> Update(Guid id, UpdateStoreRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.UpdateAsync(id, request, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
var deleted = await service.DeleteAsync(id, ct);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
public record CreateStoreRequest(
|
||||
string OwnerName,
|
||||
string StoreName,
|
||||
string StoreAddress,
|
||||
decimal Latitude,
|
||||
decimal Longitude,
|
||||
decimal OneTimeAmount,
|
||||
decimal CreditAmount);
|
||||
|
||||
public record UpdateStoreRequest(
|
||||
string OwnerName,
|
||||
string StoreName,
|
||||
string StoreAddress,
|
||||
decimal Latitude,
|
||||
decimal Longitude,
|
||||
decimal OneTimeAmount,
|
||||
decimal CreditAmount);
|
||||
|
||||
public record StoreResponse(
|
||||
Guid Id,
|
||||
string OwnerName,
|
||||
string StoreName,
|
||||
string StoreAddress,
|
||||
decimal Latitude,
|
||||
decimal Longitude,
|
||||
decimal OneTimeAmount,
|
||||
decimal CreditAmount,
|
||||
bool IsActive,
|
||||
DateTime CreatedAt);
|
||||
@@ -0,0 +1,25 @@
|
||||
using Distribution.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
public class StoreRepository(AppDBContext context) : IStoreRepository
|
||||
{
|
||||
public async Task<Models.Store?> GetByIdAsync(Guid id) =>
|
||||
await context.Stores.FindAsync(id);
|
||||
|
||||
public async Task<List<Models.Store>> GetAllAsync() =>
|
||||
await context.Stores.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.Store entity) =>
|
||||
await context.Stores.AddAsync(entity);
|
||||
|
||||
public void Update(Models.Store entity) =>
|
||||
context.Stores.Update(entity);
|
||||
|
||||
public void Remove(Models.Store entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.Stores.Update(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Store;
|
||||
|
||||
public class StoreService(IStoreRepository repo, IUnitOfWork uow)
|
||||
{
|
||||
private static StoreResponse ToResponse(Models.Store s) =>
|
||||
new(s.Id, s.OwnerName, s.StoreName, s.StoreAddress, s.Latitude, s.Longitude, s.OneTimeAmount, s.CreditAmount, s.IsActive, s.CreatedAt);
|
||||
|
||||
public async Task<List<StoreResponse>> GetAllAsync() =>
|
||||
(await repo.GetAllAsync())
|
||||
.Where(s => s.IsActive)
|
||||
.Select(ToResponse)
|
||||
.ToList();
|
||||
|
||||
public async Task<StoreResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null || !store.IsActive) return null;
|
||||
return ToResponse(store);
|
||||
}
|
||||
|
||||
public async Task<StoreResponse> CreateAsync(CreateStoreRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var store = new Models.Store
|
||||
{
|
||||
OwnerName = request.OwnerName,
|
||||
StoreName = request.StoreName,
|
||||
StoreAddress = request.StoreAddress,
|
||||
Latitude = request.Latitude,
|
||||
Longitude = request.Longitude,
|
||||
OneTimeAmount = request.OneTimeAmount,
|
||||
CreditAmount = request.CreditAmount
|
||||
};
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
await repo.AddAsync(store);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return ToResponse(store);
|
||||
}
|
||||
|
||||
public async Task<StoreResponse?> UpdateAsync(Guid id, UpdateStoreRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null || !store.IsActive) return null;
|
||||
store.OwnerName = request.OwnerName;
|
||||
store.StoreName = request.StoreName;
|
||||
store.StoreAddress = request.StoreAddress;
|
||||
store.Latitude = request.Latitude;
|
||||
store.Longitude = request.Longitude;
|
||||
store.OneTimeAmount = request.OneTimeAmount;
|
||||
store.CreditAmount = request.CreditAmount;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(store);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return ToResponse(store);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var store = await repo.GetByIdAsync(id);
|
||||
if (store is null || !store.IsActive) return false;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Remove(store);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Distribution.Features.Vehicle;
|
||||
|
||||
public interface IVehicleRepository
|
||||
{
|
||||
Task<Models.Vehicle?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.Vehicle>> GetAllAsync();
|
||||
Task AddAsync(Models.Vehicle entity);
|
||||
void Update(Models.Vehicle entity);
|
||||
void Remove(Models.Vehicle entity);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Vehicle;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/vehicles")]
|
||||
public class VehicleController(VehicleService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(CreateVehicleRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.CreateAsync(request, ct);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<IActionResult> Update(Guid id, UpdateVehicleRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.UpdateAsync(id, request, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
var deleted = await service.DeleteAsync(id, ct);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Distribution.Models;
|
||||
|
||||
namespace Distribution.Features.Vehicle;
|
||||
|
||||
public record CreateVehicleRequest(string RegNumber, string NumberPlate, VehicleType Type);
|
||||
|
||||
public record UpdateVehicleRequest(string RegNumber, string NumberPlate, VehicleType Type);
|
||||
|
||||
public record VehicleResponse(Guid Id, string RegNumber, string NumberPlate, VehicleType Type, bool IsActive, DateTime CreatedAt);
|
||||
@@ -0,0 +1,25 @@
|
||||
using Distribution.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Vehicle;
|
||||
|
||||
public class VehicleRepository(AppDBContext context) : IVehicleRepository
|
||||
{
|
||||
public async Task<Models.Vehicle?> GetByIdAsync(Guid id) =>
|
||||
await context.Vehicles.FindAsync(id);
|
||||
|
||||
public async Task<List<Models.Vehicle>> GetAllAsync() =>
|
||||
await context.Vehicles.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.Vehicle entity) =>
|
||||
await context.Vehicles.AddAsync(entity);
|
||||
|
||||
public void Update(Models.Vehicle entity) =>
|
||||
context.Vehicles.Update(entity);
|
||||
|
||||
public void Remove(Models.Vehicle entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.Vehicles.Update(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Vehicle;
|
||||
|
||||
public class VehicleService(IVehicleRepository repo, IUnitOfWork uow)
|
||||
{
|
||||
public async Task<List<VehicleResponse>> GetAllAsync() =>
|
||||
(await repo.GetAllAsync())
|
||||
.Where(v => v.IsActive)
|
||||
.Select(v => new VehicleResponse(v.Id, v.RegNumber, v.NumberPlate, v.Type, v.IsActive, v.CreatedAt))
|
||||
.ToList();
|
||||
|
||||
public async Task<VehicleResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var vehicle = await repo.GetByIdAsync(id);
|
||||
if (vehicle is null || !vehicle.IsActive) return null;
|
||||
return new VehicleResponse(vehicle.Id, vehicle.RegNumber, vehicle.NumberPlate, vehicle.Type, vehicle.IsActive, vehicle.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<VehicleResponse> CreateAsync(CreateVehicleRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var vehicle = new Models.Vehicle
|
||||
{
|
||||
RegNumber = request.RegNumber,
|
||||
NumberPlate = request.NumberPlate,
|
||||
Type = request.Type
|
||||
};
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
await repo.AddAsync(vehicle);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return new VehicleResponse(vehicle.Id, vehicle.RegNumber, vehicle.NumberPlate, vehicle.Type, vehicle.IsActive, vehicle.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<VehicleResponse?> UpdateAsync(Guid id, UpdateVehicleRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var vehicle = await repo.GetByIdAsync(id);
|
||||
if (vehicle is null || !vehicle.IsActive) return null;
|
||||
vehicle.RegNumber = request.RegNumber;
|
||||
vehicle.NumberPlate = request.NumberPlate;
|
||||
vehicle.Type = request.Type;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(vehicle);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return new VehicleResponse(vehicle.Id, vehicle.RegNumber, vehicle.NumberPlate, vehicle.Type, vehicle.IsActive, vehicle.CreatedAt);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var vehicle = await repo.GetByIdAsync(id);
|
||||
if (vehicle is null || !vehicle.IsActive) return false;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Remove(vehicle);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Distribution.Features.Warehouse;
|
||||
|
||||
public interface IWarehouseRepository
|
||||
{
|
||||
Task<Models.Warehouse?> GetByIdAsync(Guid id);
|
||||
Task<List<Models.Warehouse>> GetAllAsync();
|
||||
Task AddAsync(Models.Warehouse entity);
|
||||
void Update(Models.Warehouse entity);
|
||||
void Remove(Models.Warehouse entity);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Distribution.Features.Warehouse;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/warehouses")]
|
||||
public class WarehouseController(WarehouseService service) : ControllerBase
|
||||
{
|
||||
[HttpGet]
|
||||
public async Task<IActionResult> GetAll() =>
|
||||
Ok(await service.GetAllAsync());
|
||||
|
||||
[HttpGet("{id:guid}")]
|
||||
public async Task<IActionResult> GetById(Guid id)
|
||||
{
|
||||
var result = await service.GetByIdAsync(id);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> Create(CreateWarehouseRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.CreateAsync(request, ct);
|
||||
return CreatedAtAction(nameof(GetById), new { id = result.Id }, result);
|
||||
}
|
||||
|
||||
[HttpPut("{id:guid}")]
|
||||
public async Task<IActionResult> Update(Guid id, UpdateWarehouseRequest request, CancellationToken ct)
|
||||
{
|
||||
var result = await service.UpdateAsync(id, request, ct);
|
||||
return result is null ? NotFound() : Ok(result);
|
||||
}
|
||||
|
||||
[HttpDelete("{id:guid}")]
|
||||
public async Task<IActionResult> Delete(Guid id, CancellationToken ct)
|
||||
{
|
||||
var deleted = await service.DeleteAsync(id, ct);
|
||||
return deleted ? NoContent() : NotFound();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Distribution.Models;
|
||||
|
||||
namespace Distribution.Features.Warehouse;
|
||||
|
||||
public record CreateWarehouseRequest(string Name, string Location, WareHouseType Type, Guid? VehicleId);
|
||||
|
||||
public record UpdateWarehouseRequest(string Name, string Location, WareHouseType Type, Guid? VehicleId);
|
||||
|
||||
public record WarehouseResponse(Guid Id, string Name, string Location, WareHouseType Type, Guid? VehicleId, bool IsActive, DateTime CreatedAt);
|
||||
@@ -0,0 +1,25 @@
|
||||
using Distribution.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Distribution.Features.Warehouse;
|
||||
|
||||
public class WarehouseRepository(AppDBContext context) : IWarehouseRepository
|
||||
{
|
||||
public async Task<Models.Warehouse?> GetByIdAsync(Guid id) =>
|
||||
await context.Warehouses.FindAsync(id);
|
||||
|
||||
public async Task<List<Models.Warehouse>> GetAllAsync() =>
|
||||
await context.Warehouses.ToListAsync();
|
||||
|
||||
public async Task AddAsync(Models.Warehouse entity) =>
|
||||
await context.Warehouses.AddAsync(entity);
|
||||
|
||||
public void Update(Models.Warehouse entity) =>
|
||||
context.Warehouses.Update(entity);
|
||||
|
||||
public void Remove(Models.Warehouse entity)
|
||||
{
|
||||
entity.IsActive = false;
|
||||
context.Warehouses.Update(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using Distribution.Infra.UoW;
|
||||
|
||||
namespace Distribution.Features.Warehouse;
|
||||
|
||||
public class WarehouseService(IWarehouseRepository repo, IUnitOfWork uow)
|
||||
{
|
||||
private static WarehouseResponse ToResponse(Models.Warehouse w) =>
|
||||
new(w.Id, w.Name, w.Location, w.Type, w.VehicleId, w.IsActive, w.CreatedAt);
|
||||
|
||||
public async Task<List<WarehouseResponse>> GetAllAsync() =>
|
||||
(await repo.GetAllAsync())
|
||||
.Where(w => w.IsActive)
|
||||
.Select(ToResponse)
|
||||
.ToList();
|
||||
|
||||
public async Task<WarehouseResponse?> GetByIdAsync(Guid id)
|
||||
{
|
||||
var warehouse = await repo.GetByIdAsync(id);
|
||||
if (warehouse is null || !warehouse.IsActive) return null;
|
||||
return ToResponse(warehouse);
|
||||
}
|
||||
|
||||
public async Task<WarehouseResponse> CreateAsync(CreateWarehouseRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var warehouse = new Models.Warehouse
|
||||
{
|
||||
Name = request.Name,
|
||||
Location = request.Location,
|
||||
Type = request.Type,
|
||||
VehicleId = request.VehicleId
|
||||
};
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
await repo.AddAsync(warehouse);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return ToResponse(warehouse);
|
||||
}
|
||||
|
||||
public async Task<WarehouseResponse?> UpdateAsync(Guid id, UpdateWarehouseRequest request, CancellationToken ct = default)
|
||||
{
|
||||
var warehouse = await repo.GetByIdAsync(id);
|
||||
if (warehouse is null || !warehouse.IsActive) return null;
|
||||
warehouse.Name = request.Name;
|
||||
warehouse.Location = request.Location;
|
||||
warehouse.Type = request.Type;
|
||||
warehouse.VehicleId = request.VehicleId;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Update(warehouse);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return ToResponse(warehouse);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteAsync(Guid id, CancellationToken ct = default)
|
||||
{
|
||||
var warehouse = await repo.GetByIdAsync(id);
|
||||
if (warehouse is null || !warehouse.IsActive) return false;
|
||||
await uow.BeginAsync(ct);
|
||||
try
|
||||
{
|
||||
repo.Remove(warehouse);
|
||||
await uow.CommitAsync(ct);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await uow.RollbackAsync(ct);
|
||||
throw;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user