214 lines
7.8 KiB
PHP
214 lines
7.8 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\Models\User;
|
|
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:500'],
|
|
]);
|
|
$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();
|
|
$override = (bool) ($data['override_conflicts'] ?? false);
|
|
|
|
if (! isset($data['helper_count']) && isset($data['helper_ids'])) {
|
|
$data['helper_count'] = count($data['helper_ids']);
|
|
$data['helper_assignment_mode'] = 'manual';
|
|
}
|
|
|
|
$helperIds = $this->resolveHelpers($data);
|
|
$expectedCount = (int) ($data['helper_count'] ?? 0);
|
|
if ($expectedCount > 0 && count($helperIds) < $expectedCount) {
|
|
return $this->fail('Not enough available helpers found.', [
|
|
'helper_count' => ['Only ' . count($helperIds) . ' available helper(s) found.']
|
|
], 422);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
unset($data['helper_ids'], $data['override_conflicts'], $data['helper_count'], $data['helper_assignment_mode']);
|
|
|
|
$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();
|
|
$override = (bool) ($data['override_conflicts'] ?? false);
|
|
|
|
$helperIds = null;
|
|
if (array_key_exists('helper_count', $data) || array_key_exists('helper_ids', $data)) {
|
|
if (! isset($data['helper_count']) && isset($data['helper_ids'])) {
|
|
$data['helper_count'] = count($data['helper_ids']);
|
|
$data['helper_assignment_mode'] = 'manual';
|
|
}
|
|
$helperIds = $this->resolveHelpers($data, $team->id);
|
|
$expectedCount = (int) ($data['helper_count'] ?? 0);
|
|
if ($expectedCount > 0 && count($helperIds) < $expectedCount) {
|
|
return $this->fail('Not enough available helpers found.', [
|
|
'helper_count' => ['Only ' . count($helperIds) . ' available helper(s) found.']
|
|
], 422);
|
|
}
|
|
}
|
|
|
|
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->helpers()->pluck('user_id')->toArray(),
|
|
$team->id,
|
|
);
|
|
if (! empty($conflicts)) {
|
|
return $this->fail('Team has assignment conflicts', ['conflicts' => $conflicts], 422);
|
|
}
|
|
}
|
|
|
|
unset($data['helper_ids'], $data['override_conflicts'], $data['helper_count'], $data['helper_assignment_mode']);
|
|
|
|
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',
|
|
);
|
|
}
|
|
|
|
protected function resolveHelpers(array $data, ?int $excludeTeamId = null): array
|
|
{
|
|
$mode = $data['helper_assignment_mode'] ?? 'manual';
|
|
$count = (int) ($data['helper_count'] ?? 0);
|
|
|
|
if ($count <= 0) {
|
|
return [];
|
|
}
|
|
|
|
if ($mode === 'manual') {
|
|
return $data['helper_ids'] ?? [];
|
|
}
|
|
|
|
$override = (bool) ($data['override_conflicts'] ?? false);
|
|
$query = User::where('role', User::ROLE_HELPER)->where('status', User::STATUS_ACTIVE);
|
|
|
|
if (! $override) {
|
|
$today = now()->toDateString();
|
|
$assignedHelperIds = TeamMember::query()
|
|
->where('role_in_team', TeamMember::ROLE_HELPER)
|
|
->whereDate('assigned_from', '<=', $today)
|
|
->where(function ($q) use ($today) {
|
|
$q->whereNull('assigned_until')->orWhereDate('assigned_until', '>=', $today);
|
|
})
|
|
->when($excludeTeamId, fn ($q, $id) => $q->where('team_id', '!=', $id))
|
|
->pluck('user_id')
|
|
->toArray();
|
|
|
|
$query->whereNotIn('id', $assignedHelperIds);
|
|
}
|
|
|
|
return $query->inRandomOrder()->take($count)->pluck('id')->toArray();
|
|
}
|
|
|
|
public function destroy(CollectionTeam $team): JsonResponse
|
|
{
|
|
$team->delete();
|
|
|
|
return $this->ok(null, 'Team deleted');
|
|
}
|
|
}
|