whereKey($machine->id)->lockForUpdate()->firstOrFail(); if (! in_array($machine->status, ['available', 'reserved'], true)) { throw new MachineNotAvailableException("Statut actuel : {$machine->status}"); } $booking = null; if ($bookingId !== null) { $booking = Booking::query() ->whereKey($bookingId) ->where('user_id', $user->id) ->where('machine_id', $machine->id) ->lockForUpdate() ->firstOrFail(); if (! in_array($booking->status, ['confirmed', 'active'], true)) { throw new \RuntimeException('La réservation n\'est pas valide pour démarrer un lavage.'); } } $cost = $booking !== null ? (float) $booking->reserved_amount : $this->pricingService->getActivePrice($machine); if ($booking === null) { $this->walletService->debit( $user, $cost, Wash::class, null, 'wash-debit:'.Str::uuid(), ['machine_id' => $machine->id], ); } $wash = Wash::query()->create([ 'uuid' => (string) Str::uuid(), 'user_id' => $user->id, 'machine_id' => $machine->id, 'booking_id' => $booking?->id, 'trigger_method' => $triggerMethod, 'status' => 'pending_start', 'program' => $program, 'cost' => $cost, 'duration_minutes' => WashCycleProgress::estimateDurationMinutes($machine->type), ]); $result = $this->machineIntegrationService->startCycle($machine, [ 'wash_id' => $wash->id, 'wash_uuid' => $wash->uuid, 'program' => $program, 'requested_by_user_id' => $user->id, ], $user); if (! $result->success) { throw new \RuntimeException('Échec du démarrage du cycle machine.'); } $command = $machine->commands()->latest('id')->first(); $wash->update([ 'status' => 'running', 'machine_command_id' => $command?->id, 'started_at' => now(), ]); if ($booking !== null) { $booking->update(['status' => 'active']); } $machine->update(['current_user_id' => $user->id]); $this->auditService->log( $user, 'wash.started', $wash, null, $wash->fresh()->toArray(), $machine->establishment?->organization_id, $machine->establishment_id, ); return $wash->fresh(['machine', 'booking']); }); } }