validate([ 'status' => ['nullable', 'in:unassigned,allocated,active,used,expired,voided'], 'per_page' => ['nullable', 'integer', 'min:1', 'max:100'], ]); $household = Household::where('head_user_id', $request->user()->id)->first(); if (! $household) { return $this->ok([], 'No household yet'); } $perPage = (int) $request->input('per_page', 50); $codes = QrCode::query() ->where('assigned_to_household_id', $household->id) ->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status'))) ->orderByDesc('id') ->paginate($perPage); return $this->ok( QrCodeResource::collection($codes), null, [ 'page' => $codes->currentPage(), 'per_page' => $codes->perPage(), 'total' => $codes->total(), ], ); } public function balance(Request $request): JsonResponse { $household = Household::where('head_user_id', $request->user()->id)->first(); if (! $household) { return $this->ok([ 'active' => 0, 'allocated' => 0, 'used' => 0, 'expired' => 0, 'low_balance' => false, ]); } $counts = QrCode::query() ->where('assigned_to_household_id', $household->id) ->selectRaw('status, COUNT(*) as count') ->groupBy('status') ->pluck('count', 'status') ->all(); $active = (int) ($counts['active'] ?? 0); $threshold = (int) config('qr.low_balance_threshold', 5); return $this->ok([ 'active' => $active, 'allocated' => (int) ($counts['allocated'] ?? 0), 'used' => (int) ($counts['used'] ?? 0), 'expired' => (int) ($counts['expired'] ?? 0), 'low_balance' => $active <= $threshold, 'low_balance_threshold' => $threshold, ]); } public function activate(Request $request, QrCode $qrCode, QrAllocator $allocator): JsonResponse { $request->validate([ 'activate_batch' => ['nullable', 'boolean'], ]); $household = Household::where('head_user_id', $request->user()->id)->first(); if (! $household) { return $this->forbidden('You must have an active household'); } $activateBatch = $request->boolean('activate_batch'); if ($activateBatch) { // Activate the whole batch if (! $qrCode->batch_id) { return $this->fail('This QR code does not belong to a batch', null, 422); } $activatedCount = $allocator->activateBatch($qrCode, $household); if ($activatedCount === 0) { return $this->fail('No unactivated codes found in this batch, or you do not have permission to activate this batch', null, 422); } return $this->ok(['activated_count' => $activatedCount], "Successfully activated $activatedCount QR codes in the batch"); } // Single code activation if ($qrCode->assigned_to_household_id !== $household->id) { return $this->forbidden('This code is not assigned to your household'); } if ($qrCode->status instanceof Active) { return $this->ok(new QrCodeResource($qrCode), 'Code already active'); } if (! $allocator->activate($qrCode)) { return $this->fail('Code cannot be activated from its current state', null, 422); } return $this->ok(new QrCodeResource($qrCode->fresh()), 'Code activated'); } }