[CLAUDE] Office: P11-E AttendanceReport+Excel+OtPolicy + P11-F MaTicket codegen (Wave 1)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m10s

P11-F: MaTicket gen-on-create qua WorkflowAppCodeGen (IT/2026/NNN Serializable atomic, kanban no-workflow). P11-E: GetAttendanceReportQuery monthly aggregate (day-type weekday/weekend/holiday OT x OtPolicy multiplier in-memory) + AttendanceReportExcelExporter (ClosedXML) + 2 endpoint Admin-only + fe-admin AttendanceReportPage. Migration-free. +5 test (186->191). reviewer PASS (gotcha #44 role-string verified, 0 blocker).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-08 12:34:48 +07:00
parent e9ee97fb3b
commit 6a664298fa
17 changed files with 719 additions and 7 deletions

View File

@ -2,13 +2,14 @@ using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SolutionErp.Application.Office;
using SolutionErp.Application.Reports.Services;
namespace SolutionErp.Api.Controllers;
[ApiController]
[Route("api/attendances")]
[Authorize]
public class AttendancesController(IMediator mediator) : ControllerBase
public class AttendancesController(IMediator mediator, IAttendanceReportExcelExporter excelExporter) : ControllerBase
{
[HttpPost("check-in")]
public async Task<IActionResult> CheckIn([FromBody] CheckInCommand cmd)
@ -30,4 +31,19 @@ public class AttendancesController(IMediator mediator) : ControllerBase
var now = DateTime.Now;
return Ok(await mediator.Send(new GetMyAttendanceQuery(year ?? now.Year, month ?? now.Month)));
}
// P11-E: báo cáo chấm công tháng + OT quy đổi — admin-only (MVP).
[HttpGet("report")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetReport([FromQuery] int year, [FromQuery] int month, [FromQuery] Guid? departmentId)
=> Ok(await mediator.Send(new GetAttendanceReportQuery(year, month, departmentId)));
[HttpGet("report/excel")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> GetReportExcel([FromQuery] int year, [FromQuery] int month, [FromQuery] Guid? departmentId)
{
var report = await mediator.Send(new GetAttendanceReportQuery(year, month, departmentId));
var result = excelExporter.Export(report);
return File(result.Content, result.ContentType, result.FileName);
}
}