Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

RecurringInvoiceTest.php 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. <?php
  2. use App\Enums\Accounting\EndType;
  3. use App\Enums\Accounting\Frequency;
  4. use App\Enums\Accounting\IntervalType;
  5. use App\Models\Accounting\RecurringInvoice;
  6. use Illuminate\Support\Carbon;
  7. beforeEach(function () {
  8. $this->withOfferings();
  9. });
  10. test('recurring invoice properly handles months with fewer days for monthly frequency', function () {
  11. // Start from January 31st
  12. Carbon::setTestNow('2024-01-31');
  13. RecurringInvoice::unsetEventDispatcher();
  14. // Create a recurring invoice set for the 31st of each month
  15. $recurringInvoice = RecurringInvoice::factory()
  16. ->withLineItems()
  17. ->withSchedule(
  18. frequency: Frequency::Monthly,
  19. startDate: Carbon::now(),
  20. )
  21. ->approved()
  22. ->create();
  23. // First invoice should be the start date
  24. expect($recurringInvoice->calculateNextDate())
  25. ->toBeInstanceOf(Carbon::class)
  26. ->toDateString()->toBe('2024-01-31');
  27. // Now set last_date to simulate first invoice being generated
  28. $recurringInvoice->update(['last_date' => '2024-01-31']);
  29. $recurringInvoice->refresh();
  30. expect($recurringInvoice->calculateNextDate())
  31. ->toBeInstanceOf(Carbon::class)
  32. ->toDateString()->toBe('2024-02-29');
  33. // Update last_date to Feb 29 and check next date (should be March 31)
  34. $recurringInvoice->update(['last_date' => '2024-02-29']);
  35. $recurringInvoice->refresh();
  36. expect($recurringInvoice->calculateNextDate())
  37. ->toBeInstanceOf(Carbon::class)
  38. ->toDateString()->toBe('2024-03-31');
  39. // Update last_date to March 31 and check next date (should be April 30)
  40. $recurringInvoice->update(['last_date' => '2024-03-31']);
  41. $recurringInvoice->refresh();
  42. expect($recurringInvoice->calculateNextDate())
  43. ->toBeInstanceOf(Carbon::class)
  44. ->toDateString()->toBe('2024-04-30');
  45. // Update last_date to April 30 and check next date (should be May 31)
  46. $recurringInvoice->update(['last_date' => '2024-04-30']);
  47. $recurringInvoice->refresh();
  48. expect($recurringInvoice->calculateNextDate())
  49. ->toBeInstanceOf(Carbon::class)
  50. ->toDateString()->toBe('2024-05-31');
  51. });
  52. test('recurring invoice properly handles months with fewer days for yearly frequency', function () {
  53. // Start from January 31st
  54. Carbon::setTestNow('2024-02-29');
  55. RecurringInvoice::unsetEventDispatcher();
  56. // Create a recurring invoice set for the 31st of each month
  57. $recurringInvoice = RecurringInvoice::factory()
  58. ->withLineItems()
  59. ->withSchedule(
  60. frequency: Frequency::Yearly,
  61. startDate: Carbon::now(),
  62. )
  63. ->approved()
  64. ->create();
  65. // First invoice should be the start date
  66. expect($recurringInvoice->calculateNextDate())
  67. ->toBeInstanceOf(Carbon::class)
  68. ->toDateString()->toBe('2024-02-29');
  69. // Next date should be Feb 28, 2025 (non-leap year)
  70. $recurringInvoice->update(['last_date' => '2024-02-29']);
  71. $recurringInvoice->refresh();
  72. expect($recurringInvoice->calculateNextDate())
  73. ->toBeInstanceOf(Carbon::class)
  74. ->toDateString()->toBe('2025-02-28');
  75. // Next date should be Feb 29, 2026 (leap year)
  76. $recurringInvoice->update(['last_date' => '2025-02-28']);
  77. $recurringInvoice->refresh();
  78. expect($recurringInvoice->calculateNextDate())
  79. ->toBeInstanceOf(Carbon::class)
  80. ->toDateString()->toBe('2026-02-28');
  81. });
  82. test('recurring invoice properly handles weekly frequency and custom weekly intervals', function () {
  83. Carbon::setTestNow('2024-01-31'); // Wednesday
  84. RecurringInvoice::unsetEventDispatcher();
  85. // Test regular weekly frequency
  86. $recurringInvoice = RecurringInvoice::factory()
  87. ->withLineItems()
  88. ->withSchedule(
  89. frequency: Frequency::Weekly,
  90. startDate: Carbon::now(),
  91. )
  92. ->approved()
  93. ->create();
  94. // First invoice should be the start date
  95. expect($recurringInvoice->calculateNextDate())
  96. ->toBeInstanceOf(Carbon::class)
  97. ->toDateString()->toBe('2024-01-31');
  98. // Next date should be that Friday
  99. $recurringInvoice->update(['last_date' => '2024-01-31']);
  100. $recurringInvoice->refresh();
  101. expect($recurringInvoice->calculateNextDate())
  102. ->toBeInstanceOf(Carbon::class)
  103. ->toDateString()->toBe('2024-02-07');
  104. // Test custom weekly frequency (every 2 weeks)
  105. $recurringInvoice = RecurringInvoice::factory()
  106. ->withLineItems()
  107. ->withCustomSchedule(
  108. startDate: Carbon::now(), // Wednesday
  109. endType: EndType::Never,
  110. intervalType: IntervalType::Week,
  111. intervalValue: 2,
  112. )
  113. ->approved()
  114. ->create();
  115. // First invoice should be the start date
  116. expect($recurringInvoice->calculateNextDate())
  117. ->toBeInstanceOf(Carbon::class)
  118. ->toDateString()->toBe('2024-01-31');
  119. // Next date should be two weeks from start, on Friday
  120. $recurringInvoice->update(['last_date' => '2024-01-31']);
  121. $recurringInvoice->refresh();
  122. expect($recurringInvoice->calculateNextDate())
  123. ->toBeInstanceOf(Carbon::class)
  124. ->toDateString()->toBe('2024-02-14');
  125. });
  126. test('recurring invoice generates correct sequence of invoices across different month lengths', function () {
  127. Carbon::setTestNow('2024-01-31');
  128. $recurringInvoice = RecurringInvoice::factory()
  129. ->withLineItems()
  130. ->withSchedule(
  131. frequency: Frequency::Monthly,
  132. startDate: Carbon::now(),
  133. )
  134. ->approved()
  135. ->create();
  136. // Generate first invoice
  137. $recurringInvoice->generateDueInvoices();
  138. $invoices = $recurringInvoice->invoices()
  139. ->orderBy('date')
  140. ->get();
  141. expect($invoices)->toHaveCount(1)
  142. ->and($invoices->pluck('date')->map->toDateString()->toArray())->toBe([
  143. '2024-01-31',
  144. ]);
  145. // Move time forward to February (leap year)
  146. Carbon::setTestNow('2024-02-29');
  147. $recurringInvoice->generateDueInvoices();
  148. $invoices = $recurringInvoice->invoices()
  149. ->orderBy('date')
  150. ->get();
  151. expect($invoices)->toHaveCount(2)
  152. ->and($invoices->pluck('date')->map->toDateString()->toArray())->toBe([
  153. '2024-01-31',
  154. '2024-02-29',
  155. ]);
  156. // Move time forward to March
  157. Carbon::setTestNow('2024-03-31');
  158. $recurringInvoice->generateDueInvoices();
  159. $invoices = $recurringInvoice->invoices()
  160. ->orderBy('date')
  161. ->get();
  162. expect($invoices)->toHaveCount(3)
  163. ->and($invoices->pluck('date')->map->toDateString()->toArray())->toBe([
  164. '2024-01-31',
  165. '2024-02-29',
  166. '2024-03-31',
  167. ]);
  168. });