Files
Verde-Web/app/Http/Controllers/Api/V1/Admin/AdminTeamController.php
admin 15f9295d34 feat(backend): complete Module 9 (teams + trucks)
trucks (with optional last_known_coordinates POINT 4326),
collection_teams, team_members. Admin CRUD for both. TeamConflictDetector
flags double-assignment of driver/scanner/truck/helper across active
teams; override_conflicts: true bypasses for emergencies. Promotes
routes.default_team_id to a real FK now that collection_teams exists.

144 feature tests passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 02:48:40 +08:00

151 lines
5.2 KiB
PHP

<?php
namespace App\Http\Controllers\Api\V1\Admin;
use App\Http\Controllers\Api\V1\ApiController;
use App\Http\Requests\Team\StoreCollectionTeamRequest;
use App\Http\Resources\CollectionTeamResource;
use App\Models\CollectionTeam;
use App\Models\TeamMember;
use App\Services\Team\TeamConflictDetector;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class AdminTeamController extends ApiController
{
public function __construct(private readonly TeamConflictDetector $conflicts) {}
public function index(Request $request): JsonResponse
{
$request->validate([
'status' => ['nullable', 'in:active,inactive'],
'area_id' => ['nullable', 'integer'],
'q' => ['nullable', 'string', 'max:100'],
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
]);
$perPage = (int) $request->input('per_page', 25);
$teams = CollectionTeam::query()
->with(['area', 'driver', 'scanner', 'truck'])
->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status')))
->when($request->filled('area_id'), fn ($q) => $q->where('area_id', $request->integer('area_id')))
->when($request->filled('q'), fn ($q) => $q->where('name', 'like', '%'.$request->string('q').'%'))
->orderBy('name')
->paginate($perPage);
return $this->ok(
CollectionTeamResource::collection($teams),
null,
[
'page' => $teams->currentPage(),
'per_page' => $teams->perPage(),
'total' => $teams->total(),
'last_page' => $teams->lastPage(),
],
);
}
public function store(StoreCollectionTeamRequest $request): JsonResponse
{
$data = $request->validated();
$helperIds = $data['helper_ids'] ?? [];
$override = (bool) ($data['override_conflicts'] ?? false);
unset($data['helper_ids'], $data['override_conflicts']);
if (! $override) {
$conflicts = $this->conflicts->check(
$data['driver_id'] ?? null,
$data['scanner_id'] ?? null,
$data['truck_id'] ?? null,
$helperIds,
);
if (! empty($conflicts)) {
return $this->fail('Team has assignment conflicts', ['conflicts' => $conflicts], 422);
}
}
$team = DB::transaction(function () use ($data, $helperIds) {
$team = CollectionTeam::create($data);
$today = now()->toDateString();
foreach ($helperIds as $uid) {
TeamMember::create([
'team_id' => $team->id,
'user_id' => $uid,
'role_in_team' => TeamMember::ROLE_HELPER,
'assigned_from' => $today,
]);
}
return $team;
});
return $this->created(
new CollectionTeamResource(
$team->fresh()->load(['area', 'driver', 'scanner', 'truck', 'helpers.user']),
),
'Team created',
);
}
public function show(CollectionTeam $team): JsonResponse
{
$team->load(['area', 'driver', 'scanner', 'truck', 'helpers.user']);
return $this->ok(new CollectionTeamResource($team));
}
public function update(StoreCollectionTeamRequest $request, CollectionTeam $team): JsonResponse
{
$data = $request->validated();
$helperIds = $data['helper_ids'] ?? null;
$override = (bool) ($data['override_conflicts'] ?? false);
unset($data['helper_ids'], $data['override_conflicts']);
if (! $override) {
$conflicts = $this->conflicts->check(
$data['driver_id'] ?? $team->driver_id,
$data['scanner_id'] ?? $team->scanner_id,
$data['truck_id'] ?? $team->truck_id,
$helperIds ?? [],
$team->id,
);
if (! empty($conflicts)) {
return $this->fail('Team has assignment conflicts', ['conflicts' => $conflicts], 422);
}
}
DB::transaction(function () use ($team, $data, $helperIds) {
$team->update($data);
if ($helperIds !== null) {
$today = now()->toDateString();
$team->members()->where('role_in_team', TeamMember::ROLE_HELPER)->delete();
foreach ($helperIds as $uid) {
TeamMember::create([
'team_id' => $team->id,
'user_id' => $uid,
'role_in_team' => TeamMember::ROLE_HELPER,
'assigned_from' => $today,
]);
}
}
});
return $this->ok(
new CollectionTeamResource(
$team->fresh()->load(['area', 'driver', 'scanner', 'truck', 'helpers.user']),
),
'Team updated',
);
}
public function destroy(CollectionTeam $team): JsonResponse
{
$team->delete();
return $this->ok(null, 'Team deleted');
}
}