branch crud and intergration

This commit is contained in:
2026-09-08 12:13:49 +05:30
parent bebec10eb3
commit f664961fce
113 changed files with 41598 additions and 174 deletions
@@ -0,0 +1,44 @@
using ERPCore.Dtos.Config;
using ERPCore.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace ERPCore.Controllers;
/// <summary>
/// Branch configuration endpoints — the singleton toggle for whether this deployment
/// requires a branch on Employee/Warehouse records at all.
/// <para>
/// <b>Authorization:</b> writes are admitted by the inherited ERP door policy only, same
/// Phase-1 posture as <see cref="ProductConfigController"/> — any ERP-admitted user can
/// flip this flag until per-endpoint RBAC lands.
/// </para>
/// </summary>
[Route("api/v1/branch-config")]
public sealed class BranchConfigController : ApiControllerBase
{
private readonly IBranchConfigService _config;
public BranchConfigController(IBranchConfigService config) => _config = config;
[HttpGet]
[ProducesResponseType(typeof(BranchConfigDto), StatusCodes.Status200OK)]
public async Task<ActionResult<BranchConfigDto>> Get(CancellationToken ct)
{
var result = await _config.GetAsync(ct);
SetETag(result.RowVersion);
return Ok(result.Value);
}
[HttpPut]
[ProducesResponseType(typeof(BranchConfigDto), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status412PreconditionFailed)]
public async Task<ActionResult<BranchConfigDto>> Update(
[FromBody] UpdateBranchConfigRequest request, CancellationToken ct)
{
var expected = RequireIfMatch();
var result = await _config.UpdateAsync(request, expected, ct);
SetETag(result.RowVersion);
return Ok(result.Value);
}
}
@@ -15,6 +15,6 @@ public sealed class DashboardController : ApiControllerBase
/// <summary>Aggregate counts for stock, GRN, and procurement.</summary>
[HttpGet("stats")]
[ProducesResponseType(typeof(DashboardStatsDto), StatusCodes.Status200OK)]
public async Task<ActionResult<DashboardStatsDto>> GetStats(CancellationToken ct)
=> Ok(await _dashboard.GetStatsAsync(ct));
public async Task<ActionResult<DashboardStatsDto>> GetStats([FromQuery] int? branchId, CancellationToken ct)
=> Ok(await _dashboard.GetStatsAsync(branchId, ct));
}
@@ -22,8 +22,8 @@ public sealed class GrnsController : ApiControllerBase
[ProducesResponseType(typeof(PagedResponse<GrnSummaryDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<GrnSummaryDto>>> List(
[FromQuery] PageQuery query, [FromQuery] GrnStatus? status, [FromQuery] int? poId,
[FromQuery] int? vendorId, [FromQuery] int? warehouseId, CancellationToken ct)
=> Ok(await _grns.ListAsync(query, status, poId, vendorId, warehouseId, ct));
[FromQuery] int? vendorId, [FromQuery] int? warehouseId, [FromQuery] int? branchId, CancellationToken ct)
=> Ok(await _grns.ListAsync(query, status, poId, vendorId, warehouseId, branchId, ct));
[HttpGet("{grnId:int}")]
[ProducesResponseType(typeof(GrnDto), StatusCodes.Status200OK)]
@@ -25,8 +25,9 @@ public sealed class SalesInvoicesController : ApiControllerBase
[FromQuery] SalesInvoiceStatus? status,
[FromQuery] int? customerId,
[FromQuery] int? warehouseId,
[FromQuery] int? branchId,
CancellationToken ct)
=> Ok(await _invoices.ListAsync(query, status, customerId, warehouseId, ct));
=> Ok(await _invoices.ListAsync(query, status, customerId, warehouseId, branchId, ct));
[HttpGet("{salesInvoiceId:int}")]
[ProducesResponseType(typeof(SalesInvoiceDto), StatusCodes.Status200OK)]
@@ -17,8 +17,8 @@ public sealed class StockAdjustmentsController : ApiControllerBase
[HttpGet]
[ProducesResponseType(typeof(PagedResponse<AdjustmentSummaryDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<AdjustmentSummaryDto>>> List(
[FromQuery] PageQuery query, [FromQuery] int? warehouseId, [FromQuery] int? reasonCodeId, CancellationToken ct)
=> Ok(await _adjustments.ListAsync(query, warehouseId, reasonCodeId, ct));
[FromQuery] PageQuery query, [FromQuery] int? warehouseId, [FromQuery] int? branchId, [FromQuery] int? reasonCodeId, CancellationToken ct)
=> Ok(await _adjustments.ListAsync(query, warehouseId, branchId, reasonCodeId, ct));
/// <summary>Get one adjustment with its lines and the ledger entries it posted.</summary>
[HttpGet("{adjustmentId:int}")]
@@ -28,8 +28,8 @@ public sealed class StockController : ApiControllerBase
[HttpGet("on-hand/list")]
[ProducesResponseType(typeof(PagedResponse<StockOnHandDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<StockOnHandDto>>> OnHandList(
[FromQuery] int? itemId, [FromQuery] int? warehouseId, [FromQuery] PageQuery query, CancellationToken ct)
=> Ok(await _stock.GetOnHandListAsync(itemId, warehouseId, query, ct));
[FromQuery] int? itemId, [FromQuery] int? warehouseId, [FromQuery] int? branchId, [FromQuery] PageQuery query, CancellationToken ct)
=> Ok(await _stock.GetOnHandListAsync(itemId, warehouseId, branchId, query, ct));
/// <summary>
/// Immutable movement history. <c>sourceDocType</c>/<c>sourceDocId</c> answer "what did
@@ -39,11 +39,11 @@ public sealed class StockController : ApiControllerBase
[HttpGet("ledger")]
[ProducesResponseType(typeof(PagedResponse<StockLedgerRowDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<StockLedgerRowDto>>> Ledger(
[FromQuery] int? itemId, [FromQuery] int? warehouseId,
[FromQuery] int? itemId, [FromQuery] int? warehouseId, [FromQuery] int? branchId,
[FromQuery] DateOnly? from, [FromQuery] DateOnly? to,
[FromQuery] string? sourceDocType, [FromQuery] int? sourceDocId,
[FromQuery] PageQuery query, CancellationToken ct)
=> Ok(await _stock.GetLedgerAsync(itemId, warehouseId, from, to, sourceDocType, sourceDocId, query, ct));
=> Ok(await _stock.GetLedgerAsync(itemId, warehouseId, branchId, from, to, sourceDocType, sourceDocId, query, ct));
[HttpGet("valuation")]
[ProducesResponseType(typeof(StockValuationDto), StatusCodes.Status200OK)]
@@ -54,8 +54,8 @@ public sealed class StockController : ApiControllerBase
[HttpGet("reorder-alerts")]
[ProducesResponseType(typeof(PagedResponse<ReorderAlertDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<ReorderAlertDto>>> ReorderAlerts(
[FromQuery] int? warehouseId, [FromQuery] PageQuery query, CancellationToken ct)
=> Ok(await _reorder.GetAlertsAsync(warehouseId, query, ct));
[FromQuery] int? warehouseId, [FromQuery] int? branchId, [FromQuery] PageQuery query, CancellationToken ct)
=> Ok(await _reorder.GetAlertsAsync(warehouseId, branchId, query, ct));
/// <summary>Create a draft requisition for an item's suggested reorder quantity.</summary>
[HttpPost("reorder-alerts/{itemId:int}/requisition")]
@@ -18,8 +18,8 @@ public sealed class StockCountsController : ApiControllerBase
[HttpGet]
[ProducesResponseType(typeof(PagedResponse<CountSummaryDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<CountSummaryDto>>> List(
[FromQuery] PageQuery query, [FromQuery] CountStatus? status, [FromQuery] int? warehouseId, CancellationToken ct)
=> Ok(await _counts.ListAsync(query, status, warehouseId, ct));
[FromQuery] PageQuery query, [FromQuery] CountStatus? status, [FromQuery] int? warehouseId, [FromQuery] int? branchId, CancellationToken ct)
=> Ok(await _counts.ListAsync(query, status, warehouseId, branchId, ct));
[HttpGet("{countId:int}")]
[ProducesResponseType(typeof(CountDto), StatusCodes.Status200OK)]
@@ -19,8 +19,8 @@ public sealed class StockTransfersController : ApiControllerBase
[ProducesResponseType(typeof(PagedResponse<TransferSummaryDto>), StatusCodes.Status200OK)]
public async Task<ActionResult<PagedResponse<TransferSummaryDto>>> List(
[FromQuery] PageQuery query, [FromQuery] TransferStatus? status,
[FromQuery] int? srcWarehouseId, [FromQuery] int? destWarehouseId, CancellationToken ct)
=> Ok(await _transfers.ListAsync(query, status, srcWarehouseId, destWarehouseId, ct));
[FromQuery] int? srcWarehouseId, [FromQuery] int? destWarehouseId, [FromQuery] int? branchId, CancellationToken ct)
=> Ok(await _transfers.ListAsync(query, status, srcWarehouseId, destWarehouseId, branchId, ct));
[HttpGet("{transferId:int}")]
[ProducesResponseType(typeof(TransferDto), StatusCodes.Status200OK)]
@@ -1,6 +1,7 @@
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Hrm;
using ERPCore.Dtos.Users;
using ERPCore.Infra.Auth;
using ERPCore.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
@@ -15,11 +16,13 @@ public sealed class UsersController : ApiControllerBase
{
private readonly IUserManagementService _users;
private readonly IEmployeeUserLinkService _links;
private readonly ICurrentUser _currentUser;
public UsersController(IUserManagementService users, IEmployeeUserLinkService links)
public UsersController(IUserManagementService users, IEmployeeUserLinkService links, ICurrentUser currentUser)
{
_users = users;
_links = links;
_currentUser = currentUser;
}
/// <summary>Advisory forward-direction lookup: does a Staff record already exist with this email? (docs/12-BACKEND-HRM.md A.5)</summary>
@@ -53,7 +56,7 @@ public sealed class UsersController : ApiControllerBase
[ProducesResponseType(StatusCodes.Status409Conflict)]
public async Task<ActionResult<ManagedUserDto>> Create([FromBody] CreateUserRequest request, CancellationToken ct)
{
var result = await _users.CreateAsync(request, ct);
var result = await _users.CreateAsync(request, _currentUser.AuditUserId, ct);
return Created($"/api/v1/users/{result.UserId}", result);
}