UnitReceivableService.php 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. <?php
  2. namespace App\Services;
  3. use App\Models\StudentContractInstallment;
  4. use Carbon\Carbon;
  5. use Illuminate\Database\Eloquent\Collection;
  6. use Illuminate\Validation\ValidationException;
  7. /**
  8. * Contas a Receber da unidade.
  9. *
  10. * Decisão de modelagem (A): as parcelas de contrato de aluno
  11. * (student_contract_installments) SÃO a Contas a Receber de alunos da unidade.
  12. * A baixa é manual aqui; quando houver Asaas na unidade, a baixa também chega
  13. * pelo webhook (ramo STU_).
  14. */
  15. class UnitReceivableService
  16. {
  17. public function list(int $unitId, array $filters = []): Collection
  18. {
  19. return StudentContractInstallment::with(['student'])
  20. ->where('unit_id', $unitId)
  21. ->when(
  22. isset($filters['status']),
  23. fn ($q) => $q->where('status', $filters['status']),
  24. )
  25. ->when(
  26. isset($filters['student_id']),
  27. fn ($q) => $q->where('student_id', $filters['student_id']),
  28. )
  29. ->when(
  30. isset($filters['type']),
  31. fn ($q) => $q->where('type', $filters['type']),
  32. )
  33. ->orderBy('due_date')
  34. ->orderBy('installment_number')
  35. ->get();
  36. }
  37. public function findForUnit(int $id, int $unitId): ?StudentContractInstallment
  38. {
  39. return StudentContractInstallment::where('id', $id)
  40. ->where('unit_id', $unitId)
  41. ->first();
  42. }
  43. /**
  44. * Baixa manual: marca a parcela como paga.
  45. */
  46. public function settle(StudentContractInstallment $installment, array $data): StudentContractInstallment
  47. {
  48. if ($installment->status === 'paid') {
  49. throw ValidationException::withMessages([
  50. 'status' => 'Esta parcela já está paga.',
  51. ]);
  52. }
  53. if ($installment->status === 'cancelled') {
  54. throw ValidationException::withMessages([
  55. 'status' => 'Esta parcela está cancelada e não pode receber baixa.',
  56. ]);
  57. }
  58. $discount = isset($data['discount']) ? (float) $data['discount'] : (float) $installment->discount;
  59. $fine = isset($data['fine']) ? (float) $data['fine'] : (float) $installment->fine;
  60. $paidValue = isset($data['paid_value'])
  61. ? (float) $data['paid_value']
  62. : round((float) $installment->value - $discount + $fine, 2);
  63. $installment->update([
  64. 'status' => 'paid',
  65. 'discount' => $discount,
  66. 'fine' => $fine,
  67. 'paid_value' => $paidValue,
  68. 'payment_date' => $data['payment_date'] ?? Carbon::today()->format('Y-m-d'),
  69. ]);
  70. return $installment->fresh(['student']);
  71. }
  72. /**
  73. * Reabre uma parcela paga (estorno da baixa manual).
  74. */
  75. public function reopen(StudentContractInstallment $installment): StudentContractInstallment
  76. {
  77. if ($installment->status !== 'paid') {
  78. throw ValidationException::withMessages([
  79. 'status' => 'Só é possível reabrir parcelas que estão pagas.',
  80. ]);
  81. }
  82. $installment->update([
  83. 'status' => 'pending',
  84. 'paid_value' => 0,
  85. 'payment_date' => null,
  86. ]);
  87. return $installment->fresh(['student']);
  88. }
  89. }