using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using ROLAC.API.Authorization; using ROLAC.API.DTOs.Expense; using ROLAC.API.Services; namespace ROLAC.API.Controllers; // Snapshots are reusable vendor-payment templates — a finance tool. Every action requires // Expenses:Write (super_admin bypasses), matching who can create vendor payments. [ApiController] [Route("api/expense-snapshots")] [Authorize] public class ExpenseSnapshotsController : ControllerBase { private readonly IExpenseSnapshotService _svc; private readonly IPermissionService _perms; public ExpenseSnapshotsController(IExpenseSnapshotService svc, IPermissionService perms) { _svc = svc; _perms = perms; } private List Roles() => User.FindAll("role").Select(claim => claim.Value).ToList(); private bool IsSuperAdmin() => User.IsInRole(PermissionAuthorizationHandler.SuperAdminRole); private async Task CanManageAsync() => IsSuperAdmin() || await _perms.HasPermissionAsync(Roles(), Modules.Expenses, PermissionActions.Write); [HttpGet] public async Task GetAll() { if (!await CanManageAsync()) return Forbid(); return Ok(await _svc.GetAllAsync()); } [HttpGet("{id:int}")] public async Task GetById(int id) { if (!await CanManageAsync()) return Forbid(); var dto = await _svc.GetByIdAsync(id); return dto is null ? NotFound() : Ok(dto); } [HttpPost] public async Task Create([FromBody] CreateExpenseSnapshotRequest r) { if (!await CanManageAsync()) return Forbid(); try { return Ok(new { id = await _svc.CreateAsync(r) }); } catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); } } [HttpPut("{id:int}")] public async Task Update(int id, [FromBody] UpdateExpenseSnapshotRequest r) { if (!await CanManageAsync()) return Forbid(); try { await _svc.UpdateAsync(id, r); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); } } [HttpDelete("{id:int}")] public async Task Delete(int id) { if (!await CanManageAsync()) return Forbid(); try { await _svc.DeleteAsync(id); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } }