feat(backend): enhance allocation and project management

Update controllers and services for allocation fidelity:
- AllocationController: variance data in responses, bulk operations
- ProjectController: include plan data in responses
- ProjectMonthPlanController: planning grid API
- AllocationMatrixService: support untracked allocations
- ProjectResource/TeamMemberResource: include reconciliation data

Improved test coverage for allocation flows.
This commit is contained in:
2026-03-08 18:22:53 -04:00
parent 9b38e28117
commit 9b0f42fdf5
14 changed files with 414 additions and 376 deletions

View File

@@ -21,6 +21,19 @@ test('project resource includes expected fields inside data wrapper', function (
expect($payload['data'])->toHaveKey('approved_estimate');
});
test('project resource includes scalar type_id and status_id', function () {
$project = Project::factory()->approved()->create();
$project->load(['status', 'type']);
$response = (new ProjectResource($project))->toResponse(Request::create('/'));
$payload = $response->getData(true);
expect($payload['data'])->toHaveKey('type_id');
expect($payload['data'])->toHaveKey('status_id');
expect($payload['data']['type_id'])->toBe($project->type_id);
expect($payload['data']['status_id'])->toBe($project->status_id);
});
test('project resource collection wraps multiple entries', function () {
$projects = Project::factory()->count(2)->create();

View File

@@ -21,6 +21,18 @@ test('team member resource wraps data and includes role when loaded', function (
expect($payload['data']['role']['id'])->toBe($role->id);
});
test('team member resource includes scalar role_id', function () {
$role = Role::factory()->create();
$teamMember = TeamMember::factory()->create(['role_id' => $role->id]);
$teamMember->load('role');
$response = (new TeamMemberResource($teamMember))->toResponse(Request::create('/'));
$payload = $response->getData(true);
expect($payload['data'])->toHaveKey('role_id');
expect($payload['data']['role_id'])->toBe($teamMember->role_id);
});
test('team member resource collection keeps data wrapper', function () {
$role = Role::factory()->create();
$teamMembers = TeamMember::factory()->count(2)->create(['role_id' => $role->id]);