diff --git a/API/ROLAC.API/Controllers/ExpenseCategoriesController.cs b/API/ROLAC.API/Controllers/ExpenseCategoriesController.cs index 7e9f327..e039375 100644 --- a/API/ROLAC.API/Controllers/ExpenseCategoriesController.cs +++ b/API/ROLAC.API/Controllers/ExpenseCategoriesController.cs @@ -7,7 +7,8 @@ namespace ROLAC.API.Controllers; [ApiController] [Route("api/expense-categories")] -[Authorize(Roles = "finance,super_admin")] +[Authorize] // read (GetAll) is open to any authenticated user — the member self-service + // reimbursement form needs the category list. Write actions are finance-only below. public class ExpenseCategoriesController : ControllerBase { private readonly IExpenseCategoryService _svc; @@ -18,26 +19,32 @@ public class ExpenseCategoriesController : ControllerBase => Ok(await _svc.GetAllAsync(includeInactive)); [HttpPost("groups")] + [Authorize(Roles = "finance,super_admin")] public async Task CreateGroup([FromBody] CreateExpenseGroupRequest r) => Ok(new { id = await _svc.CreateGroupAsync(r) }); [HttpPut("groups/{id:int}")] + [Authorize(Roles = "finance,super_admin")] public async Task UpdateGroup(int id, [FromBody] UpdateExpenseGroupRequest r) { try { await _svc.UpdateGroupAsync(id, r); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } [HttpDelete("groups/{id:int}")] + [Authorize(Roles = "finance,super_admin")] public async Task DeactivateGroup(int id) { try { await _svc.DeactivateGroupAsync(id); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } [HttpPost("subcategories")] + [Authorize(Roles = "finance,super_admin")] public async Task CreateSub([FromBody] CreateExpenseSubCategoryRequest r) { try { return Ok(new { id = await _svc.CreateSubCategoryAsync(r) }); } catch (KeyNotFoundException) { return NotFound(); } } [HttpPut("subcategories/{id:int}")] + [Authorize(Roles = "finance,super_admin")] public async Task UpdateSub(int id, [FromBody] UpdateExpenseSubCategoryRequest r) { try { await _svc.UpdateSubCategoryAsync(id, r); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } [HttpDelete("subcategories/{id:int}")] + [Authorize(Roles = "finance,super_admin")] public async Task DeactivateSub(int id) { try { await _svc.DeactivateSubCategoryAsync(id); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } } diff --git a/API/ROLAC.API/Services/MonthlyStatementService.cs b/API/ROLAC.API/Services/MonthlyStatementService.cs index 4ba1669..2392936 100644 --- a/API/ROLAC.API/Services/MonthlyStatementService.cs +++ b/API/ROLAC.API/Services/MonthlyStatementService.cs @@ -51,7 +51,7 @@ public class MonthlyStatementService : IMonthlyStatementService public async Task UpdateAsync(int id, UpdateMonthlyStatementRequest r) { - var s = await _db.MonthlyStatements.FindAsync(id) + var s = await _db.MonthlyStatements.FirstOrDefaultAsync(x => x.Id == id) ?? throw new KeyNotFoundException($"MonthlyStatement {id} not found."); if (s.IsFinalized) throw new InvalidOperationException("Statement is finalized and cannot be modified."); s.OpeningBalance = r.OpeningBalance; s.TotalOtherIncome = r.TotalOtherIncome; @@ -62,7 +62,7 @@ public class MonthlyStatementService : IMonthlyStatementService public async Task FinalizeAsync(int id) { - var s = await _db.MonthlyStatements.FindAsync(id) + var s = await _db.MonthlyStatements.FirstOrDefaultAsync(x => x.Id == id) ?? throw new KeyNotFoundException($"MonthlyStatement {id} not found."); s.IsFinalized = true; s.FinalizedAt = DateTimeOffset.UtcNow; s.FinalizedBy = CurrentUserId; await _db.SaveChangesAsync();