orderBy('created_at', 'desc') ->get(); } public function findById(int $id): ?CartItem { return CartItem::find($id); } public function create(array $data): CartItem { return DB::transaction(function () use ($data) { [$cart, $schedule] = $this->validateItem($data['cart_id'], $data['schedule_id']); if (! $cart->provider_id) { $cart->update(['provider_id' => $schedule->provider_id]); } return CartItem::create($data); }); } public function update(int $id, array $data): ?CartItem { return DB::transaction(function () use ($id, $data): ?CartItem { $model = $this->findById($id); if (! $model) { return null; } $cartId = $data['cart_id'] ?? $model->cart_id; $scheduleId = $data['schedule_id'] ?? $model->schedule_id; [$cart, $schedule] = $this->validateItem($cartId, $scheduleId); if (! $cart->provider_id) { $cart->update(['provider_id' => $schedule->provider_id]); } $model->update($data); return $model->fresh(); }); } public function delete(int $id): bool { $model = $this->findById($id); if (!$model) { return false; } return DB::transaction(function () use ($model): bool { $this->validateItem($model->cart_id, $model->schedule_id); return $model->delete(); }); } private function validateItem(int $cartId, int $scheduleId): array { $cart = Cart::query()->lockForUpdate()->findOrFail($cartId); $schedule = Schedule::query()->findOrFail($scheduleId); if ($cart->status !== CartStatusEnum::OPEN) { throw ValidationException::withMessages([ 'cart_id' => 'Somente carrinhos abertos podem ser alterados.', ]); } if ($schedule->client_id !== $cart->client_id) { throw ValidationException::withMessages([ 'schedule_id' => 'O agendamento precisa pertencer ao mesmo cliente do carrinho.', ]); } if (! $schedule->provider_id || ($cart->provider_id && $schedule->provider_id !== $cart->provider_id)) { throw ValidationException::withMessages([ 'schedule_id' => 'Todos os agendamentos do carrinho precisam ser do mesmo prestador.', ]); } $belongsToAnotherCart = CartItem::query() ->where('schedule_id', $scheduleId) ->where('cart_id', '!=', $cartId) ->exists(); if ($belongsToAnotherCart) { throw ValidationException::withMessages([ 'schedule_id' => 'O agendamento já pertence a outro carrinho.', ]); } $hasActivePayment = Payment::query() ->where('schedule_id', $scheduleId) ->whereIn('status', [ PaymentStatusEnum::PENDING->value, PaymentStatusEnum::PROCESSING->value, PaymentStatusEnum::AUTHORIZED->value, PaymentStatusEnum::PAID->value, ]) ->exists(); if ($hasActivePayment) { throw ValidationException::withMessages([ 'schedule_id' => 'O agendamento já possui um pagamento e não pode ser adicionado ao carrinho.', ]); } return [$cart, $schedule]; } }