AppointmentGuideService.php 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. namespace App\Services;
  3. use App\Enums\AppointmentStatusEnum;
  4. use App\Models\Appointment;
  5. use App\Models\CompanySetting;
  6. use Barryvdh\DomPDF\Facade\Pdf;
  7. use Barryvdh\DomPDF\PDF as PdfWrapper;
  8. use Carbon\Carbon;
  9. class AppointmentGuideService
  10. {
  11. private const DEFAULT_VALIDITY_DAYS = 30;
  12. public function canIssue(Appointment $appointment): bool
  13. {
  14. $released = in_array($appointment->status, [
  15. AppointmentStatusEnum::CONFIRMADO,
  16. AppointmentStatusEnum::CONCLUIDO,
  17. ], true);
  18. if (!$released) {
  19. return false;
  20. }
  21. if ($appointment->isExame()) {
  22. return $appointment->exams->isNotEmpty();
  23. }
  24. return $appointment->date !== null && $appointment->time !== null;
  25. }
  26. public function issue(Appointment $appointment, ?int $issuedByUserId = null): Appointment
  27. {
  28. if ($appointment->guide_issued_at) {
  29. return $appointment;
  30. }
  31. $appointment->update([
  32. 'guide_issued_at' => now(),
  33. 'guide_valid_until' => now()->addDays($this->validityDays())->toDateString(),
  34. 'guide_issued_by_user_id' => $issuedByUserId,
  35. 'service_price' => $appointment->service_price ?? $this->servicePrice($appointment),
  36. ]);
  37. return $appointment->fresh([
  38. 'user',
  39. 'userDependent',
  40. 'partnerAgreement',
  41. 'partnerAgreementService',
  42. 'exams.partnerAgreementService',
  43. ]);
  44. }
  45. public function pdf(Appointment $appointment, ?int $issuedByUserId = null): PdfWrapper
  46. {
  47. $appointment = $this->issue($appointment, $issuedByUserId);
  48. $view = $appointment->isExame()
  49. ? 'pdf.appointment_exam_guide'
  50. : 'pdf.appointment_guide';
  51. return Pdf::loadView($view, ['guide' => $this->data($appointment)])
  52. ->setPaper('a4');
  53. }
  54. public function fileName(Appointment $appointment): string
  55. {
  56. return "guia_{$appointment->order_number}.pdf";
  57. }
  58. /**
  59. * @return array<string, mixed>
  60. */
  61. public function data(Appointment $appointment): array
  62. {
  63. $price = $appointment->service_price ?? $this->servicePrice($appointment);
  64. return [
  65. 'order_number' => $appointment->order_number,
  66. 'type' => $appointment->type?->value,
  67. 'holder_name' => $appointment->user?->name,
  68. 'holder_badge' => $appointment->user?->registration,
  69. 'holder_cpf' => $appointment->user?->cpf,
  70. 'dependent_name' => $appointment->userDependent?->name,
  71. // O nome do médico está embutido no nome do serviço cadastrado no convênio.
  72. 'doctor_name' => $appointment->partnerAgreementService?->name,
  73. 'exams' => $this->exams($appointment),
  74. 'clinic_name' => $appointment->partnerAgreement?->company_name,
  75. 'clinic_address' => $this->clinicAddress($appointment),
  76. 'clinic_phone' => $appointment->partnerAgreement?->phone,
  77. 'date' => $appointment->date?->format('d/m/Y'),
  78. 'time' => $appointment->time ? Carbon::parse($appointment->time)->format('H:i') : null,
  79. 'issued_at' => $appointment->guide_issued_at?->format('d/m/Y'),
  80. 'valid_until' => $appointment->guide_valid_until?->format('d/m/Y'),
  81. 'price' => $this->money($price),
  82. 'observations' => $appointment->observations,
  83. ];
  84. }
  85. /**
  86. * @return array<int, array<string, string|null>>
  87. */
  88. private function exams(Appointment $appointment): array
  89. {
  90. if (!$appointment->isExame()) {
  91. return [];
  92. }
  93. return $appointment->exams
  94. ->map(fn($exam) => [
  95. 'name' => $exam->partnerAgreementService?->name,
  96. 'price' => $this->money($exam->service_price),
  97. ])
  98. ->all();
  99. }
  100. private function money(string|float|null $value): ?string
  101. {
  102. return $value !== null ? 'R$ ' . number_format((float) $value, 2, ',', '.') : null;
  103. }
  104. private function servicePrice(Appointment $appointment): ?string
  105. {
  106. if ($appointment->isExame()) {
  107. return (string) $appointment->exams->sum(fn($exam) => (float) $exam->service_price);
  108. }
  109. $service = $appointment->partnerAgreementService;
  110. return $service?->associate_price ?? $service?->price;
  111. }
  112. private function clinicAddress(Appointment $appointment): ?string
  113. {
  114. $partner = $appointment->partnerAgreement;
  115. if (!$partner) {
  116. return null;
  117. }
  118. $parts = array_filter([$partner->address, $partner->neighborhood]);
  119. return $parts ? implode(' - ', $parts) : null;
  120. }
  121. private function validityDays(): int
  122. {
  123. $days = (int) (CompanySetting::query()->value('guide_validity_days') ?? 0);
  124. return $days > 0 ? $days : self::DEFAULT_VALIDITY_DAYS;
  125. }
  126. }