with(['items.schedule']) ->orderBy('created_at', 'desc') ->get(); } public function findById(int $id): ?ServicePackage { return ServicePackage::query() ->with(['items.schedule']) ->find($id); } public function create(array $data): ServicePackage { return ServicePackage::create($data); } public function update(int $id, array $data): ?ServicePackage { $model = $this->findById($id); if (! $model) { return null; } if (data_get($data, 'provider_id') !== null) { $hasDifferentProvider = $model->items() ->whereHas('schedule', fn ($query) => $query->where('provider_id', '!=', data_get($data, 'provider_id'))) ->exists(); if ($hasDifferentProvider) { throw ValidationException::withMessages([ 'provider_id' => __('messages.service_package_provider_mismatch'), ]); } } if (data_get($data, 'client_id') !== null) { $hasDifferentClient = $model->items() ->whereHas('schedule', fn ($query) => $query->where('client_id', '!=', data_get($data, 'client_id'))) ->exists(); if ($hasDifferentClient) { throw ValidationException::withMessages([ 'client_id' => __('messages.service_package_client_mismatch'), ]); } } $model->update($data); return $model->fresh(); } public function delete(int $id): bool { $model = $this->findById($id); if (! $model) { return false; } return $model->delete(); } // public function getByUserId(int $userId): Collection { return ServicePackage::query() ->with(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']) ->whereHas('client', fn ($query) => $query->where('user_id', $userId)) ->orderBy('created_at', 'desc') ->get(); } public function getByProviderUserId(int $userId): Collection { return ServicePackage::query() ->with(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']) ->whereHas('provider', fn ($query) => $query->where('user_id', $userId)) ->orderBy('created_at', 'desc') ->get(); } // public function acceptByProvider(int $id, int $userId): ServicePackage { $package = ServicePackage::query() ->with(['items.schedule']) ->whereHas('provider', fn ($query) => $query->where('user_id', $userId)) ->findOrFail($id); if ($package->status->value !== 'open') { throw ValidationException::withMessages([ 'status' => __('messages.service_package_must_be_open_for_changes'), ]); } $scheduleService = app(ScheduleService::class); DB::transaction(function () use ($package, $scheduleService) { foreach ($package->items as $item) { if ($item->schedule && $item->schedule->status === 'pending') { $scheduleService->updateStatus($item->schedule->id, 'accepted', fromPackage: true); } } }); return $package->fresh(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']); } public function refuseByProvider(int $id, int $userId): ServicePackage { $package = ServicePackage::query() ->with(['items.schedule']) ->whereHas('provider', fn ($query) => $query->where('user_id', $userId)) ->findOrFail($id); if ($package->status->value !== 'open') { throw ValidationException::withMessages([ 'status' => __('messages.service_package_must_be_open_for_changes'), ]); } $scheduleService = app(ScheduleService::class); DB::transaction(function () use ($package, $scheduleService) { foreach ($package->items as $item) { if ($item->schedule && $item->schedule->status === 'pending') { $scheduleService->updateStatus($item->schedule->id, 'rejected', fromPackage: true); } } $package->update(['status' => 'cancelled']); }); return $package->fresh(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']); } // public function createForUser(array $data, int $userId): ServicePackage { $client = Client::query() ->where('user_id', $userId) ->firstOrFail(); $data['client_id'] = $client->id; return $this->hasSchedulePayload($data) ? $this->createWithSchedules($data) : $this->create($data); } public function createWithSchedules(array $data): ServicePackage { return DB::transaction(function () use ($data) { $items = $this->scheduleItems($data); $providerId = $this->singleProviderId($data, $items); $schedules = app(ScheduleService::class)->createSingleOrMultiple( baseData: $this->baseScheduleData($data), schedules: $items, ); $servicePackage = ServicePackage::create([ 'client_id' => data_get($data, 'client_id'), 'provider_id' => $providerId, ]); foreach ($schedules as $schedule) { $servicePackage->items()->create([ 'schedule_id' => $schedule->id, ]); } return $servicePackage->fresh(['items.schedule.client.user', 'items.schedule.provider.user', 'items.schedule.address']); }); } // private function baseScheduleData(array $data): array { return Arr::except($data, [ 'schedules', 'dates', 'date', 'period_type', 'start_time', 'end_time', 'total_amount', 'offers_meal', ]); } private function hasSchedulePayload(array $data): bool { return ! empty(data_get($data, 'schedules')) || ! empty(data_get($data, 'dates')) || ! empty(data_get($data, 'date')); } private function scheduleItems(array $data): array { if (! empty(data_get($data, 'schedules'))) { return data_get($data, 'schedules'); } if (! empty(data_get($data, 'dates'))) { return array_map( fn (string $date) => array_merge( Arr::only($data, ['period_type', 'start_time', 'end_time', 'total_amount', 'offers_meal']), ['date' => $date], ), data_get($data, 'dates'), ); } return [ Arr::only($data, ['date', 'period_type', 'start_time', 'end_time', 'total_amount', 'offers_meal']), ]; } private function singleProviderId(array $data, array $items): int { $rootProviderId = data_get($data, 'provider_id'); $providerIds = collect($items) ->map(fn (array $item) => data_get($item, 'provider_id', $rootProviderId)) ->filter() ->unique() ->values(); if ($providerIds->count() !== 1) { throw ValidationException::withMessages([ 'schedules' => __('messages.service_package_same_provider'), ]); } return (int) $providerIds->first(); } }