You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. <?php
  2. namespace App\Support;
  3. use App\Enums\Accounting\DayOfMonth;
  4. use App\Enums\Accounting\DayOfWeek;
  5. use App\Enums\Accounting\Frequency;
  6. use App\Enums\Accounting\IntervalType;
  7. use App\Enums\Accounting\Month;
  8. use Carbon\CarbonImmutable;
  9. use Filament\Forms\Get;
  10. use Filament\Forms\Set;
  11. use Illuminate\Support\Carbon;
  12. class ScheduleHandler
  13. {
  14. protected CarbonImmutable $today;
  15. protected Set $set;
  16. protected ?Get $get;
  17. public function __construct(Set $set, ?Get $get = null)
  18. {
  19. $this->today = company_today()->toImmutable();
  20. $this->set = $set;
  21. $this->get = $get;
  22. }
  23. protected function setMany(Set $set, array $values): void
  24. {
  25. foreach ($values as $key => $value) {
  26. $set($key, $value);
  27. }
  28. }
  29. public function handleFrequencyChange(mixed $state): void
  30. {
  31. $frequency = Frequency::parse($state);
  32. match (true) {
  33. $frequency->isDaily() => $this->handleDaily(),
  34. $frequency->isWeekly() => $this->handleWeekly(),
  35. $frequency->isMonthly() => $this->handleMonthly(),
  36. $frequency->isYearly() => $this->handleYearly(),
  37. $frequency->isCustom() => $this->handleCustom(),
  38. default => null,
  39. };
  40. }
  41. public function handleIntervalTypeChange(mixed $state): void
  42. {
  43. $intervalType = IntervalType::parse($state);
  44. match (true) {
  45. $intervalType->isWeek() => $this->handleWeeklyInterval(),
  46. $intervalType->isMonth() => $this->handleMonthlyInterval(),
  47. $intervalType->isYear() => $this->handleYearlyInterval(),
  48. default => null,
  49. };
  50. }
  51. public function handleDateChange(?string $component, mixed $state): void
  52. {
  53. match ($component) {
  54. 'start_date' => $this->syncComponentsToStartDate(Carbon::parse($state)),
  55. 'month' => $this->handleMonthChange($state),
  56. 'day_of_month' => $this->handleDayOfMonthChange($state),
  57. 'day_of_week' => $this->handleDayOfWeekChange($state),
  58. default => null,
  59. };
  60. }
  61. protected function handleDaily(): void
  62. {
  63. $this->setMany($this->set, [
  64. 'interval_value' => null,
  65. 'interval_type' => null,
  66. 'day_of_month' => null,
  67. 'start_date' => $this->today->toDateString(),
  68. ]);
  69. }
  70. protected function handleWeekly(): void
  71. {
  72. $currentDayOfWeek = DayOfWeek::parse($this->today->dayOfWeek);
  73. $this->setMany($this->set, [
  74. 'day_of_week' => $currentDayOfWeek,
  75. 'start_date' => $this->today->toDateString(),
  76. 'interval_value' => null,
  77. 'interval_type' => null,
  78. 'day_of_month' => null,
  79. ]);
  80. }
  81. protected function handleMonthly(): void
  82. {
  83. $dayOfMonth = DayOfMonth::First;
  84. $date = $dayOfMonth->resolveDate($this->today);
  85. $adjustedStartDate = $date->lt($this->today)
  86. ? $dayOfMonth->resolveDate($date->addMonth())
  87. : $dayOfMonth->resolveDate($date);
  88. $this->setMany($this->set, [
  89. 'month' => null,
  90. 'day_of_month' => $dayOfMonth,
  91. 'start_date' => $adjustedStartDate->toDateString(),
  92. 'interval_value' => null,
  93. 'interval_type' => null,
  94. ]);
  95. }
  96. protected function handleYearly(): void
  97. {
  98. $currentMonth = Month::parse($this->today->month);
  99. $currentDayOfMonth = DayOfMonth::parse($this->today->day);
  100. $this->setMany($this->set, [
  101. 'month' => $currentMonth,
  102. 'day_of_month' => $currentDayOfMonth,
  103. 'start_date' => $this->today->toDateString(),
  104. 'interval_value' => null,
  105. 'interval_type' => null,
  106. ]);
  107. }
  108. protected function handleCustom(): void
  109. {
  110. $dayOfMonth = DayOfMonth::First;
  111. $date = $dayOfMonth->resolveDate($this->today);
  112. $adjustedStartDate = $date->lt($this->today)
  113. ? $dayOfMonth->resolveDate($date->addMonth())
  114. : $dayOfMonth->resolveDate($date);
  115. $this->setMany($this->set, [
  116. 'interval_value' => 1,
  117. 'interval_type' => IntervalType::Month,
  118. 'month' => null,
  119. 'day_of_month' => $dayOfMonth,
  120. 'start_date' => $adjustedStartDate->toDateString(),
  121. ]);
  122. }
  123. protected function handleWeeklyInterval(): void
  124. {
  125. $currentDayOfWeek = DayOfWeek::parse($this->today->dayOfWeek);
  126. $this->setMany($this->set, [
  127. 'day_of_week' => $currentDayOfWeek,
  128. 'start_date' => $this->today->toDateString(),
  129. ]);
  130. }
  131. protected function handleMonthlyInterval(): void
  132. {
  133. $dayOfMonth = DayOfMonth::First;
  134. $date = $dayOfMonth->resolveDate($this->today);
  135. $adjustedStartDate = $date->lt($this->today)
  136. ? $dayOfMonth->resolveDate($date->addMonth())
  137. : $dayOfMonth->resolveDate($date);
  138. $this->setMany($this->set, [
  139. 'month' => null,
  140. 'day_of_month' => $dayOfMonth,
  141. 'start_date' => $adjustedStartDate->toDateString(),
  142. ]);
  143. }
  144. protected function handleYearlyInterval(): void
  145. {
  146. $currentMonth = Month::parse($this->today->month);
  147. $currentDayOfMonth = DayOfMonth::parse($this->today->day);
  148. $this->setMany($this->set, [
  149. 'month' => $currentMonth,
  150. 'day_of_month' => $currentDayOfMonth,
  151. 'start_date' => $this->today->toDateString(),
  152. ]);
  153. }
  154. protected function syncComponentsToStartDate(Carbon $startDate): void
  155. {
  156. $frequency = Frequency::parse(($this->get)('frequency'));
  157. $intervalType = IntervalType::parse(($this->get)('interval_type'));
  158. if ($frequency->isWeekly() || $intervalType?->isWeek()) {
  159. ($this->set)('day_of_week', DayOfWeek::parse($startDate->dayOfWeek));
  160. }
  161. if ($frequency->isMonthly() || $intervalType?->isMonth() ||
  162. $frequency->isYearly() || $intervalType?->isYear()) {
  163. ($this->set)('day_of_month', $startDate->day);
  164. }
  165. if ($frequency->isYearly() || $intervalType?->isYear()) {
  166. ($this->set)('month', Month::parse($startDate->month));
  167. }
  168. }
  169. protected function handleMonthChange(mixed $state): void
  170. {
  171. if (! $this->get) {
  172. return;
  173. }
  174. $dayOfMonth = DayOfMonth::parse(($this->get)('day_of_month'));
  175. $frequency = Frequency::parse(($this->get)('frequency'));
  176. $intervalType = IntervalType::parse(($this->get)('interval_type'));
  177. $month = Month::parse($state);
  178. if (($frequency->isYearly() || $intervalType?->isYear()) && $month && $dayOfMonth) {
  179. $date = $dayOfMonth->resolveDate($this->today->month($month->value));
  180. $adjustedStartDate = $date->lt($this->today)
  181. ? $dayOfMonth->resolveDate($date->addYear()->month($month->value))
  182. : $dayOfMonth->resolveDate($date->month($month->value));
  183. $adjustedDay = min($dayOfMonth->value, $adjustedStartDate->daysInMonth);
  184. $this->setMany($this->set, [
  185. 'day_of_month' => $adjustedDay,
  186. 'start_date' => $adjustedStartDate->toDateString(),
  187. ]);
  188. }
  189. }
  190. protected function handleDayOfMonthChange(mixed $state): void
  191. {
  192. if (! $this->get) {
  193. return;
  194. }
  195. $dayOfMonth = DayOfMonth::parse($state);
  196. $frequency = Frequency::parse(($this->get)('frequency'));
  197. $intervalType = IntervalType::parse(($this->get)('interval_type'));
  198. $month = Month::parse(($this->get)('month'));
  199. if (($frequency->isMonthly() || $intervalType?->isMonth()) && $dayOfMonth) {
  200. $date = $dayOfMonth->resolveDate($this->today);
  201. $adjustedStartDate = $date->lt($this->today)
  202. ? $dayOfMonth->resolveDate($date->addMonth())
  203. : $dayOfMonth->resolveDate($date);
  204. ($this->set)('start_date', $adjustedStartDate->toDateString());
  205. }
  206. if (($frequency->isYearly() || $intervalType?->isYear()) && $month && $dayOfMonth) {
  207. $date = $dayOfMonth->resolveDate($this->today->month($month->value));
  208. $adjustedStartDate = $date->lt($this->today)
  209. ? $dayOfMonth->resolveDate($date->addYear()->month($month->value))
  210. : $dayOfMonth->resolveDate($date->month($month->value));
  211. ($this->set)('start_date', $adjustedStartDate->toDateString());
  212. }
  213. }
  214. protected function handleDayOfWeekChange(mixed $state): void
  215. {
  216. $dayOfWeek = DayOfWeek::parse($state);
  217. $adjustedStartDate = $this->today->is($dayOfWeek->name)
  218. ? $this->today
  219. : $this->today->next($dayOfWeek->name);
  220. ($this->set)('start_date', $adjustedStartDate->toDateString());
  221. }
  222. }