AppointmentService.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <?php
  2. namespace App\Services;
  3. use App\Enums\AppointmentStatusEnum;
  4. use App\Enums\NotificationRecipientEnum;
  5. use App\Models\Appointment;
  6. use Carbon\Carbon;
  7. use Illuminate\Database\Eloquent\Collection;
  8. use Illuminate\Pagination\LengthAwarePaginator;
  9. use Illuminate\Support\Str;
  10. class AppointmentService
  11. {
  12. public function __construct(protected NotificationService $notificationService) {}
  13. public function getAll(): Collection
  14. {
  15. return Appointment::with(['user', 'partnerAgreement', 'partnerAgreementService'])
  16. ->orderBy('date', 'desc')
  17. ->get();
  18. }
  19. public function getAllByUser(int $userId): Collection
  20. {
  21. return Appointment::with(['partnerAgreement', 'partnerAgreementService'])
  22. ->where('user_id', $userId)
  23. ->orderBy('date', 'desc')
  24. ->get();
  25. }
  26. public function getAllByPartnerUser(int $userId): Collection
  27. {
  28. return Appointment::with(['user', 'partnerAgreement', 'partnerAgreementService'])
  29. ->whereHas('partnerAgreement', fn($q) => $q->where('user_id', $userId))
  30. ->orderBy('date', 'desc')
  31. ->get();
  32. }
  33. public function findById(int $id): ?Appointment
  34. {
  35. return Appointment::with(['user', 'partnerAgreement', 'partnerAgreementService'])->find($id);
  36. }
  37. public function create(array $data): Appointment
  38. {
  39. $data['order_number'] = $this->generateOrderNumber();
  40. $data['requested_at'] = now();
  41. return Appointment::create($data);
  42. }
  43. public function notifyCreation(Appointment $model): void
  44. {
  45. $dateStr = $model->date ? Carbon::parse($model->date)->format('d/m/Y') : null;
  46. $message = $dateStr
  47. ? "Um agendamento #{$model->order_number} foi criado para você" . ($model->time ? " para {$dateStr} às {$model->time}" : " em {$dateStr}") . "."
  48. : "Um agendamento #{$model->order_number} foi criado para você.";
  49. $this->notificationService->createAutoForUser([
  50. 'title' => 'Novo agendamento',
  51. 'message' => $message,
  52. 'recipient' => NotificationRecipientEnum::ASSOCIADO,
  53. 'source' => 'appointment',
  54. 'source_id' => $model->id,
  55. ], $model->user_id);
  56. }
  57. public function update(int $id, array $data): ?Appointment
  58. {
  59. $model = Appointment::find($id);
  60. if (!$model) {
  61. return null;
  62. }
  63. $model->update($data);
  64. return $model->fresh(['user', 'partnerAgreement', 'partnerAgreementService']);
  65. }
  66. public function delete(int $id): bool
  67. {
  68. $model = Appointment::find($id);
  69. if (!$model) {
  70. return false;
  71. }
  72. return $model->delete();
  73. }
  74. public function getAdminCounters(): array
  75. {
  76. return [
  77. 'pendentes' => Appointment::where('status', AppointmentStatusEnum::PENDENTE)->count(),
  78. 'aprovados' => Appointment::where('status', AppointmentStatusEnum::CONFIRMADO)->count(),
  79. 'recusados' => Appointment::where('status', AppointmentStatusEnum::RECUSADO)->count(),
  80. ];
  81. }
  82. public function getAllPaginated(array $filters = [], int $perPage = 10): LengthAwarePaginator
  83. {
  84. $query = Appointment::with(['user', 'partnerAgreement', 'partnerAgreementService'])
  85. ->orderBy('requested_at', 'desc');
  86. if (!empty($filters['status'])) {
  87. $query->where('status', $filters['status']);
  88. }
  89. if (!empty($filters['search'])) {
  90. $term = '%' . mb_strtolower($filters['search']) . '%';
  91. $query->where(function ($q) use ($term) {
  92. $q->whereHas('user', function ($uq) use ($term) {
  93. $uq->whereRaw('UNACCENT(LOWER(name)) LIKE UNACCENT(?)', [$term]);
  94. })->orWhereHas('partnerAgreement', function ($pq) use ($term) {
  95. $pq->whereRaw('UNACCENT(LOWER(COALESCE(trade_name, company_name))) LIKE UNACCENT(?)', [$term]);
  96. })->orWhereHas('partnerAgreementService', function ($sq) use ($term) {
  97. $sq->whereRaw('UNACCENT(LOWER(name)) LIKE UNACCENT(?)', [$term]);
  98. })->orWhereRaw('UNACCENT(LOWER(order_number)) LIKE UNACCENT(?)', [$term]);
  99. });
  100. }
  101. return $query->paginate($perPage);
  102. }
  103. public function approve(int $id, string $date, string $time): ?Appointment
  104. {
  105. $model = Appointment::find($id);
  106. if (!$model) return null;
  107. $model->update([
  108. 'status' => AppointmentStatusEnum::CONFIRMADO,
  109. 'date' => $date,
  110. 'time' => $time,
  111. ]);
  112. $this->notificationService->createAutoForUser([
  113. 'title' => 'Agendamento confirmado',
  114. 'message' => "Seu agendamento #{$model->order_number} foi confirmado para " . Carbon::parse($date)->format('d/m/Y') . " às {$time}.",
  115. 'recipient' => NotificationRecipientEnum::ASSOCIADO,
  116. 'source' => 'appointment',
  117. 'source_id' => $model->id,
  118. ], $model->user_id);
  119. return $model->fresh(['user', 'partnerAgreement', 'partnerAgreementService']);
  120. }
  121. public function reject(int $id): ?Appointment
  122. {
  123. $model = Appointment::find($id);
  124. if (!$model) return null;
  125. $model->update(['status' => AppointmentStatusEnum::RECUSADO]);
  126. $this->notificationService->createAutoForUser([
  127. 'title' => 'Agendamento recusado',
  128. 'message' => "Seu agendamento #{$model->order_number} foi recusado.",
  129. 'recipient' => NotificationRecipientEnum::ASSOCIADO,
  130. 'source' => 'appointment',
  131. 'source_id' => $model->id,
  132. ], $model->user_id);
  133. return $model->fresh(['user', 'partnerAgreement', 'partnerAgreementService']);
  134. }
  135. public function approveByPartner(int $id, int $userId, string $date, string $time): ?Appointment
  136. {
  137. $model = Appointment::whereHas('partnerAgreement', fn($q) => $q->where('user_id', $userId))->find($id);
  138. if (!$model) return null;
  139. $model->update([
  140. 'status' => AppointmentStatusEnum::CONFIRMADO,
  141. 'date' => $date,
  142. 'time' => $time,
  143. ]);
  144. $this->notificationService->createAutoForUser([
  145. 'title' => 'Agendamento confirmado',
  146. 'message' => "Seu agendamento #{$model->order_number} foi confirmado para " . Carbon::parse($date)->format('d/m/Y') . " às {$time}.",
  147. 'recipient' => NotificationRecipientEnum::ASSOCIADO,
  148. 'source' => 'appointment',
  149. 'source_id' => $model->id,
  150. ], $model->user_id);
  151. return $model->fresh(['user', 'partnerAgreement', 'partnerAgreementService']);
  152. }
  153. public function rejectByPartner(int $id, int $userId): ?Appointment
  154. {
  155. $model = Appointment::whereHas('partnerAgreement', fn($q) => $q->where('user_id', $userId))->find($id);
  156. if (!$model) return null;
  157. $model->update(['status' => AppointmentStatusEnum::RECUSADO]);
  158. $this->notificationService->createAutoForUser([
  159. 'title' => 'Agendamento recusado',
  160. 'message' => "Seu agendamento #{$model->order_number} foi recusado.",
  161. 'recipient' => NotificationRecipientEnum::ASSOCIADO,
  162. 'source' => 'appointment',
  163. 'source_id' => $model->id,
  164. ], $model->user_id);
  165. return $model->fresh(['user', 'partnerAgreement', 'partnerAgreementService']);
  166. }
  167. private function generateOrderNumber(): string
  168. {
  169. do {
  170. $number = 'AGD-' . strtoupper(Str::random(8));
  171. } while (Appointment::where('order_number', $number)->exists());
  172. return $number;
  173. }
  174. }