whereKey($this->machineId)->lockForUpdate()->first(); if ($machine === null || $machine->status !== 'running') { return; } $provider = config('laverie.simulation.provider_name', 'simulated'); $previousStatus = $machine->status; $machine->update([ 'status' => 'available', 'current_user_id' => null, 'cycle_started_at' => null, 'cycle_ends_at' => null, 'last_heartbeat_at' => now(), ]); MachineStatusHistory::query()->create([ 'machine_id' => $machine->id, 'previous_status' => $previousStatus, 'new_status' => 'available', 'source' => $provider, 'reason' => 'simulated_cycle_completion', 'created_at' => now(), ]); MachineEvent::query()->create([ 'machine_id' => $machine->id, 'provider' => $provider, 'event_type' => 'cycle_completed', 'payload' => [ 'machine_command_id' => $this->machineCommandId, 'wash_id' => $this->washId, 'simulated' => true, ], 'occurred_at' => now(), 'received_at' => now(), 'processed_at' => now(), 'processing_status' => 'processed', ]); if ($this->washId !== null) { $wash = Wash::query()->whereKey($this->washId)->lockForUpdate()->first(); if ($wash !== null && $wash->status === 'running') { $startedAt = $wash->started_at ?? now(); $endedAt = now(); $wash->update([ 'status' => 'completed', 'ended_at' => $endedAt, 'duration_minutes' => max(1, (int) $startedAt->diffInMinutes($endedAt)), ]); if ($wash->booking_id !== null) { \App\Models\Booking::query() ->whereKey($wash->booking_id) ->update(['status' => 'completed']); } } } }); } }