using Microsoft.AspNetCore.Mvc; using ROLAC.API.Authorization; using ROLAC.API.DTOs.Payee; using ROLAC.API.Services; namespace ROLAC.API.Controllers; [ApiController] [Route("api/payee-1099")] [HasPermission(Modules.Form1099, PermissionActions.Read)] public class Payee1099Controller : ControllerBase { private readonly IPayee1099Service _svc; public Payee1099Controller(IPayee1099Service svc) => _svc = svc; [HttpGet] public async Task GetAll([FromQuery] bool includeInactive = false) => Ok(await _svc.GetAllAsync(includeInactive)); [HttpGet("{id:int}")] public async Task GetById(int id) => await _svc.GetByIdAsync(id) is { } dto ? Ok(dto) : NotFound(); [HttpPost] [HasPermission(Modules.Form1099, PermissionActions.Write)] public async Task Create([FromBody] SavePayee1099Request r) => Ok(new { id = await _svc.CreateAsync(r) }); [HttpPut("{id:int}")] [HasPermission(Modules.Form1099, PermissionActions.Write)] public async Task Update(int id, [FromBody] SavePayee1099Request r) { await _svc.UpdateAsync(id, r); return NoContent(); } [HttpDelete("{id:int}")] [HasPermission(Modules.Form1099, PermissionActions.Delete)] public async Task Delete(int id) { await _svc.DeleteAsync(id); return NoContent(); } // Full TIN reveal is gated on Write (a stronger right than Read). [HttpGet("{id:int}/tin")] [HasPermission(Modules.Form1099, PermissionActions.Write)] public async Task RevealTin(int id) => Ok(new { tin = await _svc.RevealTinAsync(id) }); // Mirrors the expense-receipt upload: multipart form file, size-limited, type-checked. [HttpPost("{id:int}/w9")] [HasPermission(Modules.Form1099, PermissionActions.Write)] [RequestSizeLimit(10_485_760)] public async Task UploadW9(int id, IFormFile file) { if (file is null || file.Length == 0) return BadRequest(new { message = "No file." }); var allowed = new[] { "image/jpeg", "image/png", "image/webp", "application/pdf" }; if (!allowed.Contains(file.ContentType)) return BadRequest(new { message = "Unsupported file type." }); try { await using var stream = file.OpenReadStream(); await _svc.SaveW9Async(id, stream, file.FileName); return NoContent(); } catch (KeyNotFoundException) { return NotFound(); } } // Class-level Read gate covers viewing the stored W-9 (mirrors the receipt GET). [HttpGet("{id:int}/w9")] public async Task GetW9(int id) { var result = await _svc.OpenW9Async(id); if (result is null) return NotFound(); return File(result.Value.stream, result.Value.contentType); } }