using System.Security.Claims; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using ROLAC.API.DTOs.Disbursement; using ROLAC.API.Services; namespace ROLAC.API.Controllers; [ApiController] [Route("api/disbursements")] [Authorize(Roles = "finance,super_admin")] public class DisbursementsController : ControllerBase { private readonly IDisbursementService _svc; public DisbursementsController(IDisbursementService svc) => _svc = svc; [HttpGet("approved-unpaid")] public async Task GetApprovedUnpaid() => Ok(await _svc.GetApprovedUnpaidGroupedAsync()); [HttpPost("issue")] public async Task Issue([FromBody] IssueChecksRequest r) { try { return Ok(await _svc.IssueChecksAsync(r)); } catch (KeyNotFoundException) { return NotFound(); } catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); } } [HttpGet("checks")] public async Task GetRegister( [FromQuery] int page = 1, [FromQuery] int pageSize = 20, [FromQuery] string? status = null, [FromQuery] string? search = null, [FromQuery] DateOnly? from = null, [FromQuery] DateOnly? to = null) => Ok(await _svc.GetRegisterAsync(page, pageSize, status, search, from, to)); [HttpGet("checks/{id:int}")] public async Task GetById(int id) { var dto = await _svc.GetByIdAsync(id); return dto is null ? NotFound() : Ok(dto); } [HttpPost("checks/{id:int}/void")] public async Task Void(int id, [FromBody] VoidCheckRequest r) { try { await _svc.VoidAsync(id, r.Reason); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); } } [HttpGet("checks/{id:int}/pdf")] public async Task GetPdf(int id) { var result = await _svc.RenderPdfAsync(id); if (result is null) return NotFound(); return File(result.Value.stream, result.Value.contentType, result.Value.fileName); } [HttpGet("checks/{id:int}/receipt-pdf")] public async Task GetReceiptPdf(int id) { var result = await _svc.RenderReceiptPdfAsync(id); if (result is null) return NotFound(); return File(result.Value.stream, result.Value.contentType, result.Value.fileName); } [HttpPost("checks/{id:int}/acknowledge")] [RequestSizeLimit(5_242_880)] public async Task Acknowledge(int id, [FromForm] IFormFile signature, [FromForm] string signedName) { if (signature is null || signature.Length == 0) return BadRequest(new { message = "No signature." }); if (string.IsNullOrWhiteSpace(signedName)) return BadRequest(new { message = "Signed name is required." }); var allowed = new[] { "image/png", "image/jpeg", "image/webp" }; if (!allowed.Contains(signature.ContentType)) return BadRequest(new { message = "Unsupported image type." }); try { await using var stream = signature.OpenReadStream(); await _svc.AcknowledgeReceiptAsync(id, stream, signature.FileName, signedName.Trim()); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } catch (InvalidOperationException ex) { return Conflict(new { message = ex.Message }); } } [HttpGet("checks/{id:int}/signature")] public async Task GetSignature(int id) { try { var result = await _svc.OpenSignatureAsync(id); if (result is null) return NotFound(); return File(result.Value.stream, result.Value.contentType); } catch (KeyNotFoundException) { return NotFound(); } } }