[CLAUDE] Hrm: P11-C Vehicle+Driver catalogs (Mig 44) + gotcha #57 filtered-unique 3 HRM catalog (Mig 45)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m18s

P11-C: extend HrmConfigs +2 kind (Vehicle/Driver) declarative. Mig 44 AddVehicleAndDriverCatalogs (2 table filtered-unique Code, tables 91->93). Domain entity + EF config (filtered day-1) + 2 DbSet + HrmConfigFeatures Region5/6 CRUD + Controller +2 route-group (GET public / write Roles=Admin) + MenuKeys +2 +All (auto Admin perm) + DbInitializer 2 menu leaf + idempotent seed 2 veh/2 drv. FE declarative KIND_CONFIG +2 kind x2 app (SHA256 mirror) + 4-place (types/page/menuKeys/Layout staticMap), :kind-driven no new route.

gotcha #57 (bundled; OtPolicy missed in backlog, caught via grep) - Mig 45 FilterHrmCatalogUniqueIndexesByIsDeleted: LeaveType+ShiftPattern+OtPolicy bare .IsUnique() -> .HasFilter([IsDeleted]=0) (recreate-on-soft-deleted-slot 500 fix, mirror Holiday Mig 43). Tests +5 HrmConfigFilteredUniqueTests (181->186 PASS) test-before RED->GREEN. Reviewer caught FE<->BE Driver required-field mismatch -> fixed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-06-08 10:32:28 +07:00
parent f8179c5fbd
commit 30a99aa03f
27 changed files with 14144 additions and 16 deletions

View File

@ -134,4 +134,64 @@ public class HrmConfigsController(IMediator mediator) : ControllerBase
await mediator.Send(new DeleteOtPolicyCommand(id), ct);
return NoContent();
}
// ===== Vehicles (Mig 44 P11-C — S51) =====
[HttpGet("vehicles")]
public async Task<List<VehicleDto>> ListVehicles([FromQuery] string? q, [FromQuery] bool? isActive, CancellationToken ct)
=> await mediator.Send(new ListVehiclesQuery(q, isActive), ct);
[HttpPost("vehicles")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> CreateVehicle([FromBody] CreateVehicleCommand body, CancellationToken ct)
{
var id = await mediator.Send(body, ct);
return CreatedAtAction(nameof(ListVehicles), new { id }, new { id });
}
[HttpPut("vehicles/{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> UpdateVehicle(Guid id, [FromBody] UpdateVehicleCommand body, CancellationToken ct)
{
if (id != body.Id) return BadRequest("Id mismatch");
await mediator.Send(body, ct);
return NoContent();
}
[HttpDelete("vehicles/{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> DeleteVehicle(Guid id, CancellationToken ct)
{
await mediator.Send(new DeleteVehicleCommand(id), ct);
return NoContent();
}
// ===== Drivers (Mig 44 P11-C — S51) =====
[HttpGet("drivers")]
public async Task<List<DriverDto>> ListDrivers([FromQuery] string? q, [FromQuery] bool? isActive, CancellationToken ct)
=> await mediator.Send(new ListDriversQuery(q, isActive), ct);
[HttpPost("drivers")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> CreateDriver([FromBody] CreateDriverCommand body, CancellationToken ct)
{
var id = await mediator.Send(body, ct);
return CreatedAtAction(nameof(ListDrivers), new { id }, new { id });
}
[HttpPut("drivers/{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> UpdateDriver(Guid id, [FromBody] UpdateDriverCommand body, CancellationToken ct)
{
if (id != body.Id) return BadRequest("Id mismatch");
await mediator.Send(body, ct);
return NoContent();
}
[HttpDelete("drivers/{id:guid}")]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> DeleteDriver(Guid id, CancellationToken ct)
{
await mediator.Send(new DeleteDriverCommand(id), ct);
return NoContent();
}
}