c775146b64
Implementation A partner, not just software HexDive Technologies' local team handles setup, data migration, training and ongoing support — in Sinhala, Tamil and English. [confirm] 1 Discovery Map your network, products and processes. 2 Configuration Set up depots, pricing, schemes, routes and users. 3 Migration & training Move your data and train every team. 4 Go-live & support Dedicated account manager and local support desk.
110 lines
3.8 KiB
C#
110 lines
3.8 KiB
C#
using Distribution.Infra.Authorization;
|
|
using Distribution.Models;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace Distribution.Features.Expense;
|
|
|
|
[ApiController]
|
|
[Route("api/expenses")]
|
|
public class ExpenseController(
|
|
ExpenseService service,
|
|
IPermissionService permissions,
|
|
ICurrentUserService currentUser) : ControllerBase
|
|
{
|
|
private async Task<bool> HasAsync(string code)
|
|
{
|
|
if (currentUser.RoleId is not { } roleId) return false;
|
|
return await permissions.HasPermissionAsync(roleId, code);
|
|
}
|
|
|
|
[HttpGet]
|
|
[Authorize("expense.view")]
|
|
public async Task<IActionResult> List(
|
|
[FromQuery] ExpenseStatus? status,
|
|
[FromQuery] Guid? categoryId,
|
|
[FromQuery] Guid? warehouseId,
|
|
[FromQuery] DateTime? from,
|
|
[FromQuery] DateTime? to,
|
|
[FromQuery] int page = 1,
|
|
[FromQuery] int pageSize = 20) =>
|
|
Ok(await service.ListAsync(status, categoryId, warehouseId, from, to, page, pageSize));
|
|
|
|
[HttpGet("{id:guid}")]
|
|
[Authorize("expense.view")]
|
|
public async Task<IActionResult> Get(Guid id)
|
|
{
|
|
var result = await service.GetAsync(id);
|
|
return result is null ? NotFound() : Ok(result);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Create endpoint takes a required ?action= query to drive the 4 form buttons:
|
|
/// draft → Save draft; post → Save & post (requires expense.post); pay → Save & pay
|
|
/// (requires expense.post + expense.pay). Draft is the default.
|
|
/// </summary>
|
|
[HttpPost]
|
|
[Authorize("expense.create")]
|
|
public async Task<IActionResult> Create(
|
|
CreateExpenseRequest request,
|
|
[FromQuery] ExpenseAction action = ExpenseAction.Draft,
|
|
CancellationToken ct = default)
|
|
{
|
|
if (action is ExpenseAction.Post or ExpenseAction.Pay && !await HasAsync("expense.post"))
|
|
return Forbid();
|
|
if (action == ExpenseAction.Pay && !await HasAsync("expense.pay"))
|
|
return Forbid();
|
|
|
|
try { return Ok(await service.CreateAsync(request, action, ct)); }
|
|
catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); }
|
|
}
|
|
|
|
[HttpPut("{id:guid}")]
|
|
[Authorize("expense.create")]
|
|
public async Task<IActionResult> UpdateDraft(Guid id, UpdateExpenseDraftRequest request, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var result = await service.UpdateDraftAsync(id, request, ct);
|
|
return result is null ? NotFound() : Ok(result);
|
|
}
|
|
catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); }
|
|
}
|
|
|
|
[HttpPost("{id:guid}/post")]
|
|
[Authorize("expense.post")]
|
|
public async Task<IActionResult> Post(Guid id, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var result = await service.PostAsync(id, ct);
|
|
return result is null ? NotFound() : Ok(result);
|
|
}
|
|
catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); }
|
|
}
|
|
|
|
[HttpPost("{id:guid}/pay")]
|
|
[Authorize("expense.pay")]
|
|
public async Task<IActionResult> Pay(Guid id, ExpensePaymentRequest request, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var result = await service.PayAsync(id, request, ct);
|
|
return result is null ? NotFound() : Ok(result);
|
|
}
|
|
catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); }
|
|
}
|
|
|
|
[HttpPost("{id:guid}/void")]
|
|
[Authorize("expense.void")]
|
|
public async Task<IActionResult> Void(Guid id, VoidExpenseRequest request, CancellationToken ct)
|
|
{
|
|
try
|
|
{
|
|
var result = await service.VoidAsync(id, request?.Reason, ct);
|
|
return result is null ? NotFound() : Ok(result);
|
|
}
|
|
catch (InvalidOperationException ex) { return BadRequest(new { error = ex.Message }); }
|
|
}
|
|
}
|