Andrew Wallo пре 9 месеци
родитељ
комит
963c53245b

+ 93
- 245
app/Models/Accounting/RecurringInvoice.php Прегледај датотеку

21
 use App\Models\Common\Client;
21
 use App\Models\Common\Client;
22
 use App\Models\Setting\CompanyProfile;
22
 use App\Models\Setting\CompanyProfile;
23
 use App\Observers\RecurringInvoiceObserver;
23
 use App\Observers\RecurringInvoiceObserver;
24
+use App\Support\ScheduleHandler;
24
 use App\Utilities\Localization\Timezone;
25
 use App\Utilities\Localization\Timezone;
26
+use CodeWithDennis\SimpleAlert\Components\Forms\SimpleAlert;
25
 use Filament\Actions\Action;
27
 use Filament\Actions\Action;
26
 use Filament\Actions\MountableAction;
28
 use Filament\Actions\MountableAction;
27
 use Filament\Forms;
29
 use Filament\Forms;
293
 
295
 
294
     public function calculateNextWeeklyDate(Carbon $lastDate): ?Carbon
296
     public function calculateNextWeeklyDate(Carbon $lastDate): ?Carbon
295
     {
297
     {
296
-        return $lastDate->copy()->next($this->day_of_week->value);
298
+        return $lastDate->copy()->next($this->day_of_week->name);
297
     }
299
     }
298
 
300
 
299
     public function calculateNextMonthlyDate(Carbon $lastDate): ?Carbon
301
     public function calculateNextMonthlyDate(Carbon $lastDate): ?Carbon
300
     {
302
     {
301
-        return match (true) {
302
-            $lastDate->equalTo($this->start_date) => $lastDate->copy()->day(
303
-                min($this->day_of_month->value, $lastDate->daysInMonth)
304
-            ),
305
-
306
-            default => $lastDate->copy()->addMonth()->day(
307
-                min($this->day_of_month->value, $lastDate->copy()->addMonth()->daysInMonth)
308
-            ),
309
-        };
303
+        return $this->day_of_month->resolveDate($lastDate->copy()->addMonth());
310
     }
304
     }
311
 
305
 
312
     public function calculateNextYearlyDate(Carbon $lastDate): ?Carbon
306
     public function calculateNextYearlyDate(Carbon $lastDate): ?Carbon
313
     {
307
     {
314
-        return match (true) {
315
-            $lastDate->equalTo($this->start_date) => $lastDate->copy()
316
-                ->month($this->month->value)
317
-                ->day(min($this->day_of_month->value, $lastDate->daysInMonth)),
318
-
319
-            default => $lastDate->copy()
320
-                ->addYear()
321
-                ->month($this->month->value)
322
-                ->day(min($this->day_of_month->value, $lastDate->copy()->addYear()->month($this->month->value)->daysInMonth))
323
-        };
308
+        return $this->day_of_month->resolveDate($lastDate->copy()->addYear()->month($this->month->value));
324
     }
309
     }
325
 
310
 
326
     protected function calculateCustomNextDate(Carbon $lastDate): ?Carbon
311
     protected function calculateCustomNextDate(Carbon $lastDate): ?Carbon
330
         return match ($this->interval_type) {
315
         return match ($this->interval_type) {
331
             IntervalType::Day => $lastDate->copy()->addDays($interval),
316
             IntervalType::Day => $lastDate->copy()->addDays($interval),
332
 
317
 
333
-            IntervalType::Week => match (true) {
334
-                $lastDate->equalTo($this->start_date) => $lastDate->copy()->next($this->day_of_week->value),
335
-
336
-                $lastDate->dayOfWeek === $this->day_of_week->value => $lastDate->copy()->addWeeks($interval),
337
-
338
-                default => $lastDate->copy()->next($this->day_of_week->value),
339
-            },
340
-
341
-            IntervalType::Month => match (true) {
342
-                $lastDate->equalTo($this->start_date) => $lastDate->copy()->day(
343
-                    min($this->day_of_month->value, $lastDate->daysInMonth)
344
-                ),
318
+            IntervalType::Week => $lastDate->copy()->addWeeks($interval),
345
 
319
 
346
-                default => $lastDate->copy()->addMonths($interval)->day(
347
-                    min($this->day_of_month->value, $lastDate->copy()->addMonths($interval)->daysInMonth)
348
-                ),
349
-            },
320
+            IntervalType::Month => $this->day_of_month->resolveDate($lastDate->copy()->addMonths($interval)),
350
 
321
 
351
-            IntervalType::Year => match (true) {
352
-                $lastDate->equalTo($this->start_date) => $lastDate->copy()
353
-                    ->month($this->month->value)
354
-                    ->day(min($this->day_of_month->value, $lastDate->daysInMonth)),
355
-
356
-                default => $lastDate->copy()
357
-                    ->addYears($interval)
358
-                    ->month($this->month->value)
359
-                    ->day(min($this->day_of_month->value, $lastDate->copy()->addYears($interval)->month($this->month->value)->daysInMonth))
360
-            },
322
+            IntervalType::Year => $this->day_of_month->resolveDate($lastDate->copy()->addYears($interval)->month($this->month->value)),
361
 
323
 
362
             default => null
324
             default => null
363
         };
325
         };
411
             ->form([
373
             ->form([
412
                 CustomSection::make('Frequency')
374
                 CustomSection::make('Frequency')
413
                     ->contained(false)
375
                     ->contained(false)
414
-                    ->schema([
415
-                        Forms\Components\Select::make('frequency')
416
-                            ->label('Repeats')
417
-                            ->options(Frequency::class)
418
-                            ->softRequired()
419
-                            ->live()
420
-                            ->afterStateUpdated(function (Forms\Set $set, $state) {
421
-                                $frequency = Frequency::parse($state);
422
-
423
-                                if ($frequency->isDaily()) {
424
-                                    $set('interval_value', null);
425
-                                    $set('interval_type', null);
426
-                                }
427
-
428
-                                if ($frequency->isWeekly()) {
429
-                                    $currentDayOfWeek = now()->dayOfWeek;
430
-                                    $currentDayOfWeek = DayOfWeek::parse($currentDayOfWeek);
431
-                                    $set('day_of_week', $currentDayOfWeek);
432
-                                    $set('interval_value', null);
433
-                                    $set('interval_type', null);
434
-                                }
435
-
436
-                                if ($frequency->isMonthly()) {
437
-                                    $set('day_of_month', DayOfMonth::First);
438
-                                    $set('interval_value', null);
439
-                                    $set('interval_type', null);
440
-                                }
441
-
442
-                                if ($frequency->isYearly()) {
443
-                                    $currentMonth = now()->month;
444
-                                    $currentMonth = Month::parse($currentMonth);
445
-                                    $set('month', $currentMonth);
446
-
447
-                                    $currentDay = now()->dayOfMonth;
448
-                                    $currentDay = DayOfMonth::parse($currentDay);
449
-                                    $set('day_of_month', $currentDay);
450
-
451
-                                    $set('interval_value', null);
452
-                                    $set('interval_type', null);
453
-                                }
454
-
455
-                                if ($frequency->isCustom()) {
456
-                                    $set('interval_value', 1);
457
-                                    $set('interval_type', IntervalType::Month);
458
-
459
-                                    $currentDay = now()->dayOfMonth;
460
-                                    $currentDay = DayOfMonth::parse($currentDay);
461
-                                    $set('day_of_month', $currentDay);
462
-                                }
463
-                            }),
464
-
465
-                        // Custom frequency fields in a nested grid
466
-                        Cluster::make([
467
-                            Forms\Components\TextInput::make('interval_value')
376
+                    ->schema(function (Forms\Get $get) {
377
+                        $frequency = Frequency::parse($get('frequency'));
378
+                        $intervalType = IntervalType::parse($get('interval_type'));
379
+                        $month = Month::parse($get('month'));
380
+                        $dayOfMonth = DayOfMonth::parse($get('day_of_month'));
381
+
382
+                        return [
383
+                            Forms\Components\Select::make('frequency')
384
+                                ->label('Repeats')
385
+                                ->options(Frequency::class)
468
                                 ->softRequired()
386
                                 ->softRequired()
469
-                                ->numeric()
470
-                                ->default(1),
471
-                            Forms\Components\Select::make('interval_type')
472
-                                ->options(IntervalType::class)
473
-                                ->softRequired()
474
-                                ->default(IntervalType::Month)
475
                                 ->live()
387
                                 ->live()
476
                                 ->afterStateUpdated(function (Forms\Set $set, $state) {
388
                                 ->afterStateUpdated(function (Forms\Set $set, $state) {
477
-                                    $intervalType = IntervalType::parse($state);
389
+                                    $handler = new ScheduleHandler($set);
390
+                                    $handler->handleFrequencyChange($state);
391
+                                }),
478
 
392
 
479
-                                    if ($intervalType->isWeek()) {
480
-                                        $currentDayOfWeek = now()->dayOfWeek;
481
-                                        $currentDayOfWeek = DayOfWeek::parse($currentDayOfWeek);
482
-                                        $set('day_of_week', $currentDayOfWeek);
483
-                                    }
393
+                            // Custom frequency fields in a nested grid
394
+                            Cluster::make([
395
+                                Forms\Components\TextInput::make('interval_value')
396
+                                    ->softRequired()
397
+                                    ->numeric()
398
+                                    ->default(1),
399
+                                Forms\Components\Select::make('interval_type')
400
+                                    ->options(IntervalType::class)
401
+                                    ->softRequired()
402
+                                    ->default(IntervalType::Month)
403
+                                    ->live()
404
+                                    ->afterStateUpdated(function (Forms\Set $set, $state) {
405
+                                        $handler = new ScheduleHandler($set);
406
+                                        $handler->handleIntervalTypeChange($state);
407
+                                    }),
408
+                            ])
409
+                                ->live()
410
+                                ->label('Every')
411
+                                ->required()
412
+                                ->markAsRequired(false)
413
+                                ->visible($frequency->isCustom()),
414
+
415
+                            // Specific schedule details
416
+                            Forms\Components\Select::make('month')
417
+                                ->label('Month')
418
+                                ->options(Month::class)
419
+                                ->softRequired()
420
+                                ->visible($frequency->isYearly() || $intervalType?->isYear())
421
+                                ->live()
422
+                                ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) {
423
+                                    $handler = new ScheduleHandler($set, $get);
424
+                                    $handler->handleDateChange('month', $state);
425
+                                }),
484
 
426
 
485
-                                    if ($intervalType->isMonth()) {
486
-                                        $currentDay = now()->dayOfMonth;
487
-                                        $currentDay = DayOfMonth::parse($currentDay);
488
-                                        $set('day_of_month', $currentDay);
427
+                            Forms\Components\Select::make('day_of_month')
428
+                                ->label('Day of Month')
429
+                                ->options(function () use ($month) {
430
+                                    if (! $month) {
431
+                                        return DayOfMonth::class;
489
                                     }
432
                                     }
490
 
433
 
491
-                                    if ($intervalType->isYear()) {
492
-                                        $currentMonth = now()->month;
493
-                                        $currentMonth = Month::parse($currentMonth);
494
-                                        $set('month', $currentMonth);
434
+                                    $daysInMonth = Carbon::createFromDate(null, $month->value)->daysInMonth;
495
 
435
 
496
-                                        $currentDay = now()->dayOfMonth;
497
-                                        $currentDay = DayOfMonth::parse($currentDay);
498
-                                        $set('day_of_month', $currentDay);
499
-                                    }
436
+                                    return collect(DayOfMonth::cases())
437
+                                        ->filter(static fn (DayOfMonth $dayOfMonth) => $dayOfMonth->value <= $daysInMonth || $dayOfMonth->isLast())
438
+                                        ->mapWithKeys(fn (DayOfMonth $dayOfMonth) => [$dayOfMonth->value => $dayOfMonth->getLabel()]);
439
+                                })
440
+                                ->softRequired()
441
+                                ->visible(in_array($frequency, [Frequency::Monthly, Frequency::Yearly]) || in_array($intervalType, [IntervalType::Month, IntervalType::Year]))
442
+                                ->live()
443
+                                ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) {
444
+                                    $handler = new ScheduleHandler($set, $get);
445
+                                    $handler->handleDateChange('day_of_month', $state);
500
                                 }),
446
                                 }),
501
-                        ])
502
-                            ->live()
503
-                            ->label('Every')
504
-                            ->required()
505
-                            ->markAsRequired(false)
506
-                            ->visible(fn (Forms\Get $get) => Frequency::parse($get('frequency'))?->isCustom()),
507
-
508
-                        // Specific schedule details
509
-                        Forms\Components\Select::make('month')
510
-                            ->label('Month')
511
-                            ->options(Month::class)
512
-                            ->softRequired()
513
-                            ->visible(
514
-                                fn (Forms\Get $get) => Frequency::parse($get('frequency'))->isYearly() ||
515
-                                IntervalType::parse($get('interval_type'))?->isYear()
516
-                            )
517
-                            ->live()
518
-                            ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) {
519
-                                $dayOfMonth = DayOfMonth::parse($get('day_of_month'));
520
-                                $frequency = Frequency::parse($get('frequency'));
521
-                                $intervalType = IntervalType::parse($get('interval_type'));
522
-                                $month = Month::parse($state);
523
-
524
-                                if (($frequency->isYearly() || $intervalType?->isYear()) && $month && $dayOfMonth) {
525
-                                    $date = $dayOfMonth->resolveDate(today()->month($month->value))->toImmutable();
526
-
527
-                                    $adjustedStartDate = $date->lt(today())
528
-                                        ? $dayOfMonth->resolveDate($date->addYear()->month($month->value))
529
-                                        : $dayOfMonth->resolveDate($date->month($month->value));
530
-
531
-                                    $adjustedDay = min($dayOfMonth->value, $adjustedStartDate->daysInMonth);
532
 
447
 
533
-                                    $set('day_of_month', $adjustedDay);
448
+                            SimpleAlert::make('dayOfMonthNotice')
449
+                                ->title(function () use ($dayOfMonth) {
450
+                                    return "The invoice will be created on the {$dayOfMonth->getLabel()} day of each month, or on the last day for months ending earlier.";
451
+                                })
452
+                                ->columnSpanFull()
453
+                                ->visible($dayOfMonth?->value > 28),
534
 
454
 
535
-                                    $set('start_date', $adjustedStartDate);
536
-                                }
537
-                            }),
538
-
539
-                        Forms\Components\Select::make('day_of_month')
540
-                            ->label('Day of Month')
541
-                            ->options(function (Forms\Get $get) {
542
-                                $month = Month::parse($get('month')) ?? Month::January;
543
-
544
-                                $daysInMonth = Carbon::createFromDate(null, $month->value)->daysInMonth;
545
-
546
-                                return collect(DayOfMonth::cases())
547
-                                    ->filter(static fn (DayOfMonth $dayOfMonth) => $dayOfMonth->value <= $daysInMonth || $dayOfMonth->isLast())
548
-                                    ->mapWithKeys(fn (DayOfMonth $dayOfMonth) => [$dayOfMonth->value => $dayOfMonth->getLabel()]);
549
-                            })
550
-                            ->softRequired()
551
-                            ->visible(
552
-                                fn (Forms\Get $get) => Frequency::parse($get('frequency'))?->isMonthly() ||
553
-                                Frequency::parse($get('frequency'))?->isYearly() ||
554
-                                IntervalType::parse($get('interval_type'))?->isMonth() ||
555
-                                IntervalType::parse($get('interval_type'))?->isYear()
556
-                            )
557
-                            ->live()
558
-                            ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) {
559
-                                $dayOfMonth = DayOfMonth::parse($state);
560
-                                $frequency = Frequency::parse($get('frequency'));
561
-                                $intervalType = IntervalType::parse($get('interval_type'));
562
-                                $month = Month::parse($get('month'));
563
-
564
-                                if (($frequency->isMonthly() || $intervalType?->isMonth()) && $dayOfMonth) {
565
-                                    $date = $dayOfMonth->resolveDate(today())->toImmutable();
566
-
567
-                                    $adjustedStartDate = $date->lt(today())
568
-                                        ? $dayOfMonth->resolveDate($date->addMonth())
569
-                                        : $dayOfMonth->resolveDate($date);
570
-
571
-                                    $set('start_date', $adjustedStartDate);
572
-                                }
573
-
574
-                                if (($frequency->isYearly() || $intervalType?->isYear()) && $month && $dayOfMonth) {
575
-                                    $date = $dayOfMonth->resolveDate(today()->month($month->value))->toImmutable();
576
-
577
-                                    $adjustedStartDate = $date->lt(today())
578
-                                        ? $dayOfMonth->resolveDate($date->addYear()->month($month->value))
579
-                                        : $dayOfMonth->resolveDate($date->month($month->value));
580
-
581
-                                    $set('start_date', $adjustedStartDate);
582
-                                }
583
-                            }),
584
-
585
-                        Forms\Components\Select::make('day_of_week')
586
-                            ->label('Day of Week')
587
-                            ->options(DayOfWeek::class)
588
-                            ->softRequired()
589
-                            ->visible(
590
-                                fn (Forms\Get $get) => Frequency::parse($get('frequency'))?->isWeekly() ||
591
-                                IntervalType::parse($get('interval_type'))?->isWeek()
592
-                            )
593
-                            ->live()
594
-                            ->afterStateUpdated(function (Forms\Set $set, $state) {
595
-                                $dayOfWeek = DayOfWeek::parse($state);
596
-
597
-                                $adjustedStartDate = today()->is($dayOfWeek->name)
598
-                                    ? today()
599
-                                    : today()->next($dayOfWeek->name);
600
-
601
-                                $set('start_date', $adjustedStartDate);
602
-                            }),
603
-                    ])->columns(2),
455
+                            Forms\Components\Select::make('day_of_week')
456
+                                ->label('Day of Week')
457
+                                ->options(DayOfWeek::class)
458
+                                ->softRequired()
459
+                                ->visible($frequency->isWeekly() || $intervalType?->isWeek())
460
+                                ->live()
461
+                                ->afterStateUpdated(function (Forms\Set $set, $state) {
462
+                                    $handler = new ScheduleHandler($set);
463
+                                    $handler->handleDateChange('day_of_week', $state);
464
+                                }),
465
+                        ];
466
+                    })->columns(2),
604
 
467
 
605
                 CustomSection::make('Dates & Time')
468
                 CustomSection::make('Dates & Time')
606
                     ->contained(false)
469
                     ->contained(false)
611
                             ->live()
474
                             ->live()
612
                             ->minDate(today())
475
                             ->minDate(today())
613
                             ->closeOnDateSelection()
476
                             ->closeOnDateSelection()
614
-                            ->afterStateUpdated(function (Forms\Set $set, $state) {
615
-                                $startDate = Carbon::parse($state);
616
-
617
-                                $dayOfWeek = DayOfWeek::parse($startDate->dayOfWeek);
618
-
619
-                                $set('day_of_week', $dayOfWeek);
477
+                            ->afterStateUpdated(function (Forms\Set $set, Forms\Get $get, $state) {
478
+                                $handler = new ScheduleHandler($set, $get);
479
+                                $handler->handleDateChange('start_date', $state);
620
                             }),
480
                             }),
621
 
481
 
622
                         Forms\Components\Group::make(function (Forms\Get $get) {
482
                         Forms\Components\Group::make(function (Forms\Get $get) {
630
                                 ->afterStateUpdated(function (Forms\Set $set, $state) {
490
                                 ->afterStateUpdated(function (Forms\Set $set, $state) {
631
                                     $endType = EndType::parse($state);
491
                                     $endType = EndType::parse($state);
632
 
492
 
633
-                                    if ($endType?->isNever()) {
634
-                                        $set('max_occurrences', null);
635
-                                        $set('end_date', null);
636
-                                    }
637
-
638
-                                    if ($endType?->isAfter()) {
639
-                                        $set('max_occurrences', 1);
640
-                                        $set('end_date', null);
641
-                                    }
642
-
643
-                                    if ($endType?->isOn()) {
644
-                                        $set('max_occurrences', null);
645
-                                        $set('end_date', now()->addMonth()->startOfMonth());
646
-                                    }
493
+                                    $set('max_occurrences', $endType?->isAfter() ? 1 : null);
494
+                                    $set('end_date', $endType?->isOn() ? now()->addMonth()->startOfMonth() : null);
647
                                 });
495
                                 });
648
 
496
 
649
                             $endType = EndType::parse($get('end_type'));
497
                             $endType = EndType::parse($get('end_type'));

+ 273
- 0
app/Support/ScheduleHandler.php Прегледај датотеку

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

+ 21
- 18
composer.lock Прегледај датотеку

497
         },
497
         },
498
         {
498
         {
499
             "name": "aws/aws-sdk-php",
499
             "name": "aws/aws-sdk-php",
500
-            "version": "3.336.8",
500
+            "version": "3.336.9",
501
             "source": {
501
             "source": {
502
                 "type": "git",
502
                 "type": "git",
503
                 "url": "https://github.com/aws/aws-sdk-php.git",
503
                 "url": "https://github.com/aws/aws-sdk-php.git",
504
-                "reference": "933da0d1b9b1ac9b37d5e32e127d4581b1aabaf6"
504
+                "reference": "bbc76138ed66f593dc2ae529c95fe1f794e6d77f"
505
             },
505
             },
506
             "dist": {
506
             "dist": {
507
                 "type": "zip",
507
                 "type": "zip",
508
-                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/933da0d1b9b1ac9b37d5e32e127d4581b1aabaf6",
509
-                "reference": "933da0d1b9b1ac9b37d5e32e127d4581b1aabaf6",
508
+                "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/bbc76138ed66f593dc2ae529c95fe1f794e6d77f",
509
+                "reference": "bbc76138ed66f593dc2ae529c95fe1f794e6d77f",
510
                 "shasum": ""
510
                 "shasum": ""
511
             },
511
             },
512
             "require": {
512
             "require": {
589
             "support": {
589
             "support": {
590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
590
                 "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
591
                 "issues": "https://github.com/aws/aws-sdk-php/issues",
592
-                "source": "https://github.com/aws/aws-sdk-php/tree/3.336.8"
592
+                "source": "https://github.com/aws/aws-sdk-php/tree/3.336.9"
593
             },
593
             },
594
-            "time": "2025-01-03T19:06:11+00:00"
594
+            "time": "2025-01-06T19:06:42+00:00"
595
         },
595
         },
596
         {
596
         {
597
             "name": "aws/aws-sdk-php-laravel",
597
             "name": "aws/aws-sdk-php-laravel",
2986
         },
2986
         },
2987
         {
2987
         {
2988
             "name": "knplabs/knp-snappy",
2988
             "name": "knplabs/knp-snappy",
2989
-            "version": "v1.5.0",
2989
+            "version": "v1.5.1",
2990
             "source": {
2990
             "source": {
2991
                 "type": "git",
2991
                 "type": "git",
2992
                 "url": "https://github.com/KnpLabs/snappy.git",
2992
                 "url": "https://github.com/KnpLabs/snappy.git",
2993
-                "reference": "98468898b50c09f26d56d905b79b0f52a2215da6"
2993
+                "reference": "3dd138e9e47de91cd2e056c5e6e1a0dd72547ee7"
2994
             },
2994
             },
2995
             "dist": {
2995
             "dist": {
2996
                 "type": "zip",
2996
                 "type": "zip",
2997
-                "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/98468898b50c09f26d56d905b79b0f52a2215da6",
2998
-                "reference": "98468898b50c09f26d56d905b79b0f52a2215da6",
2997
+                "url": "https://api.github.com/repos/KnpLabs/snappy/zipball/3dd138e9e47de91cd2e056c5e6e1a0dd72547ee7",
2998
+                "reference": "3dd138e9e47de91cd2e056c5e6e1a0dd72547ee7",
2999
                 "shasum": ""
2999
                 "shasum": ""
3000
             },
3000
             },
3001
             "require": {
3001
             "require": {
3047
             ],
3047
             ],
3048
             "support": {
3048
             "support": {
3049
                 "issues": "https://github.com/KnpLabs/snappy/issues",
3049
                 "issues": "https://github.com/KnpLabs/snappy/issues",
3050
-                "source": "https://github.com/KnpLabs/snappy/tree/v1.5.0"
3050
+                "source": "https://github.com/KnpLabs/snappy/tree/v1.5.1"
3051
             },
3051
             },
3052
-            "time": "2023-12-18T09:12:11+00:00"
3052
+            "time": "2025-01-06T16:53:26+00:00"
3053
         },
3053
         },
3054
         {
3054
         {
3055
             "name": "laravel/framework",
3055
             "name": "laravel/framework",
11528
         },
11528
         },
11529
         {
11529
         {
11530
             "name": "sebastian/comparator",
11530
             "name": "sebastian/comparator",
11531
-            "version": "6.2.1",
11531
+            "version": "6.3.0",
11532
             "source": {
11532
             "source": {
11533
                 "type": "git",
11533
                 "type": "git",
11534
                 "url": "https://github.com/sebastianbergmann/comparator.git",
11534
                 "url": "https://github.com/sebastianbergmann/comparator.git",
11535
-                "reference": "43d129d6a0f81c78bee378b46688293eb7ea3739"
11535
+                "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115"
11536
             },
11536
             },
11537
             "dist": {
11537
             "dist": {
11538
                 "type": "zip",
11538
                 "type": "zip",
11539
-                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/43d129d6a0f81c78bee378b46688293eb7ea3739",
11540
-                "reference": "43d129d6a0f81c78bee378b46688293eb7ea3739",
11539
+                "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/d4e47a769525c4dd38cea90e5dcd435ddbbc7115",
11540
+                "reference": "d4e47a769525c4dd38cea90e5dcd435ddbbc7115",
11541
                 "shasum": ""
11541
                 "shasum": ""
11542
             },
11542
             },
11543
             "require": {
11543
             "require": {
11550
             "require-dev": {
11550
             "require-dev": {
11551
                 "phpunit/phpunit": "^11.4"
11551
                 "phpunit/phpunit": "^11.4"
11552
             },
11552
             },
11553
+            "suggest": {
11554
+                "ext-bcmath": "For comparing BcMath\\Number objects"
11555
+            },
11553
             "type": "library",
11556
             "type": "library",
11554
             "extra": {
11557
             "extra": {
11555
                 "branch-alias": {
11558
                 "branch-alias": {
11593
             "support": {
11596
             "support": {
11594
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
11597
                 "issues": "https://github.com/sebastianbergmann/comparator/issues",
11595
                 "security": "https://github.com/sebastianbergmann/comparator/security/policy",
11598
                 "security": "https://github.com/sebastianbergmann/comparator/security/policy",
11596
-                "source": "https://github.com/sebastianbergmann/comparator/tree/6.2.1"
11599
+                "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.0"
11597
             },
11600
             },
11598
             "funding": [
11601
             "funding": [
11599
                 {
11602
                 {
11601
                     "type": "github"
11604
                     "type": "github"
11602
                 }
11605
                 }
11603
             ],
11606
             ],
11604
-            "time": "2024-10-31T05:30:08+00:00"
11607
+            "time": "2025-01-06T10:28:19+00:00"
11605
         },
11608
         },
11606
         {
11609
         {
11607
             "name": "sebastian/complexity",
11610
             "name": "sebastian/complexity",

+ 82
- 82
package-lock.json Прегледај датотеку

575
             }
575
             }
576
         },
576
         },
577
         "node_modules/@rollup/rollup-android-arm-eabi": {
577
         "node_modules/@rollup/rollup-android-arm-eabi": {
578
-            "version": "4.29.2",
579
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.2.tgz",
580
-            "integrity": "sha512-s/8RiF4bdmGnc/J0N7lHAr5ZFJj+NdJqJ/Hj29K+c4lEdoVlukzvWXB9XpWZCdakVT0YAw8iyIqUP2iFRz5/jA==",
578
+            "version": "4.30.0",
579
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.0.tgz",
580
+            "integrity": "sha512-qFcFto9figFLz2g25DxJ1WWL9+c91fTxnGuwhToCl8BaqDsDYMl/kOnBXAyAqkkzAWimYMSWNPWEjt+ADAHuoQ==",
581
             "cpu": [
581
             "cpu": [
582
                 "arm"
582
                 "arm"
583
             ],
583
             ],
589
             ]
589
             ]
590
         },
590
         },
591
         "node_modules/@rollup/rollup-android-arm64": {
591
         "node_modules/@rollup/rollup-android-arm64": {
592
-            "version": "4.29.2",
593
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.2.tgz",
594
-            "integrity": "sha512-mKRlVj1KsKWyEOwR6nwpmzakq6SgZXW4NUHNWlYSiyncJpuXk7wdLzuKdWsRoR1WLbWsZBKvsUCdCTIAqRn9cA==",
592
+            "version": "4.30.0",
593
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.0.tgz",
594
+            "integrity": "sha512-vqrQdusvVl7dthqNjWCL043qelBK+gv9v3ZiqdxgaJvmZyIAAXMjeGVSqZynKq69T7062T5VrVTuikKSAAVP6A==",
595
             "cpu": [
595
             "cpu": [
596
                 "arm64"
596
                 "arm64"
597
             ],
597
             ],
603
             ]
603
             ]
604
         },
604
         },
605
         "node_modules/@rollup/rollup-darwin-arm64": {
605
         "node_modules/@rollup/rollup-darwin-arm64": {
606
-            "version": "4.29.2",
607
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.2.tgz",
608
-            "integrity": "sha512-vJX+vennGwygmutk7N333lvQ/yKVAHnGoBS2xMRQgXWW8tvn46YWuTDOpKroSPR9BEW0Gqdga2DHqz8Pwk6X5w==",
606
+            "version": "4.30.0",
607
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.0.tgz",
608
+            "integrity": "sha512-617pd92LhdA9+wpixnzsyhVft3szYiN16aNUMzVkf2N+yAk8UXY226Bfp36LvxYTUt7MO/ycqGFjQgJ0wlMaWQ==",
609
             "cpu": [
609
             "cpu": [
610
                 "arm64"
610
                 "arm64"
611
             ],
611
             ],
617
             ]
617
             ]
618
         },
618
         },
619
         "node_modules/@rollup/rollup-darwin-x64": {
619
         "node_modules/@rollup/rollup-darwin-x64": {
620
-            "version": "4.29.2",
621
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.2.tgz",
622
-            "integrity": "sha512-e2rW9ng5O6+Mt3ht8fH0ljfjgSCC6ffmOipiLUgAnlK86CHIaiCdHCzHzmTkMj6vEkqAiRJ7ss6Ibn56B+RE5w==",
620
+            "version": "4.30.0",
621
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.0.tgz",
622
+            "integrity": "sha512-Y3b4oDoaEhCypg8ajPqigKDcpi5ZZovemQl9Edpem0uNv6UUjXv7iySBpGIUTSs2ovWOzYpfw9EbFJXF/fJHWw==",
623
             "cpu": [
623
             "cpu": [
624
                 "x64"
624
                 "x64"
625
             ],
625
             ],
631
             ]
631
             ]
632
         },
632
         },
633
         "node_modules/@rollup/rollup-freebsd-arm64": {
633
         "node_modules/@rollup/rollup-freebsd-arm64": {
634
-            "version": "4.29.2",
635
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.2.tgz",
636
-            "integrity": "sha512-/xdNwZe+KesG6XJCK043EjEDZTacCtL4yurMZRLESIgHQdvtNyul3iz2Ab03ZJG0pQKbFTu681i+4ETMF9uE/Q==",
634
+            "version": "4.30.0",
635
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.0.tgz",
636
+            "integrity": "sha512-3REQJ4f90sFIBfa0BUokiCdrV/E4uIjhkWe1bMgCkhFXbf4D8YN6C4zwJL881GM818qVYE9BO3dGwjKhpo2ABA==",
637
             "cpu": [
637
             "cpu": [
638
                 "arm64"
638
                 "arm64"
639
             ],
639
             ],
645
             ]
645
             ]
646
         },
646
         },
647
         "node_modules/@rollup/rollup-freebsd-x64": {
647
         "node_modules/@rollup/rollup-freebsd-x64": {
648
-            "version": "4.29.2",
649
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.2.tgz",
650
-            "integrity": "sha512-eXKvpThGzREuAbc6qxnArHh8l8W4AyTcL8IfEnmx+bcnmaSGgjyAHbzZvHZI2csJ+e0MYddl7DX0X7g3sAuXDQ==",
648
+            "version": "4.30.0",
649
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.0.tgz",
650
+            "integrity": "sha512-ZtY3Y8icbe3Cc+uQicsXG5L+CRGUfLZjW6j2gn5ikpltt3Whqjfo5mkyZ86UiuHF9Q3ZsaQeW7YswlHnN+lAcg==",
651
             "cpu": [
651
             "cpu": [
652
                 "x64"
652
                 "x64"
653
             ],
653
             ],
659
             ]
659
             ]
660
         },
660
         },
661
         "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
661
         "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
662
-            "version": "4.29.2",
663
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.2.tgz",
664
-            "integrity": "sha512-h4VgxxmzmtXLLYNDaUcQevCmPYX6zSj4SwKuzY7SR5YlnCBYsmvfYORXgiU8axhkFCDtQF3RW5LIXT8B14Qykg==",
662
+            "version": "4.30.0",
663
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.0.tgz",
664
+            "integrity": "sha512-bsPGGzfiHXMhQGuFGpmo2PyTwcrh2otL6ycSZAFTESviUoBOuxF7iBbAL5IJXc/69peXl5rAtbewBFeASZ9O0g==",
665
             "cpu": [
665
             "cpu": [
666
                 "arm"
666
                 "arm"
667
             ],
667
             ],
673
             ]
673
             ]
674
         },
674
         },
675
         "node_modules/@rollup/rollup-linux-arm-musleabihf": {
675
         "node_modules/@rollup/rollup-linux-arm-musleabihf": {
676
-            "version": "4.29.2",
677
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.2.tgz",
678
-            "integrity": "sha512-EObwZ45eMmWZQ1w4N7qy4+G1lKHm6mcOwDa+P2+61qxWu1PtQJ/lz2CNJ7W3CkfgN0FQ7cBUy2tk6D5yR4KeXw==",
676
+            "version": "4.30.0",
677
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.0.tgz",
678
+            "integrity": "sha512-kvyIECEhs2DrrdfQf++maCWJIQ974EI4txlz1nNSBaCdtf7i5Xf1AQCEJWOC5rEBisdaMFFnOWNLYt7KpFqy5A==",
679
             "cpu": [
679
             "cpu": [
680
                 "arm"
680
                 "arm"
681
             ],
681
             ],
687
             ]
687
             ]
688
         },
688
         },
689
         "node_modules/@rollup/rollup-linux-arm64-gnu": {
689
         "node_modules/@rollup/rollup-linux-arm64-gnu": {
690
-            "version": "4.29.2",
691
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.2.tgz",
692
-            "integrity": "sha512-Z7zXVHEXg1elbbYiP/29pPwlJtLeXzjrj4241/kCcECds8Zg9fDfURWbZHRIKrEriAPS8wnVtdl4ZJBvZr325w==",
690
+            "version": "4.30.0",
691
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.0.tgz",
692
+            "integrity": "sha512-CFE7zDNrokaotXu+shwIrmWrFxllg79vciH4E/zeK7NitVuWEaXRzS0mFfFvyhZfn8WfVOG/1E9u8/DFEgK7WQ==",
693
             "cpu": [
693
             "cpu": [
694
                 "arm64"
694
                 "arm64"
695
             ],
695
             ],
701
             ]
701
             ]
702
         },
702
         },
703
         "node_modules/@rollup/rollup-linux-arm64-musl": {
703
         "node_modules/@rollup/rollup-linux-arm64-musl": {
704
-            "version": "4.29.2",
705
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.2.tgz",
706
-            "integrity": "sha512-TF4kxkPq+SudS/r4zGPf0G08Bl7+NZcFrUSR3484WwsHgGgJyPQRLCNrQ/R5J6VzxfEeQR9XRpc8m2t7lD6SEQ==",
704
+            "version": "4.30.0",
705
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.0.tgz",
706
+            "integrity": "sha512-MctNTBlvMcIBP0t8lV/NXiUwFg9oK5F79CxLU+a3xgrdJjfBLVIEHSAjQ9+ipofN2GKaMLnFFXLltg1HEEPaGQ==",
707
             "cpu": [
707
             "cpu": [
708
                 "arm64"
708
                 "arm64"
709
             ],
709
             ],
715
             ]
715
             ]
716
         },
716
         },
717
         "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
717
         "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
718
-            "version": "4.29.2",
719
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.2.tgz",
720
-            "integrity": "sha512-kO9Fv5zZuyj2zB2af4KA29QF6t7YSxKrY7sxZXfw8koDQj9bx5Tk5RjH+kWKFKok0wLGTi4bG117h31N+TIBEg==",
718
+            "version": "4.30.0",
719
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.0.tgz",
720
+            "integrity": "sha512-fBpoYwLEPivL3q368+gwn4qnYnr7GVwM6NnMo8rJ4wb0p/Y5lg88vQRRP077gf+tc25akuqd+1Sxbn9meODhwA==",
721
             "cpu": [
721
             "cpu": [
722
                 "loong64"
722
                 "loong64"
723
             ],
723
             ],
729
             ]
729
             ]
730
         },
730
         },
731
         "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
731
         "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
732
-            "version": "4.29.2",
733
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.2.tgz",
734
-            "integrity": "sha512-gIh776X7UCBaetVJGdjXPFurGsdWwHHinwRnC5JlLADU8Yk0EdS/Y+dMO264OjJFo7MXQ5PX4xVFbxrwK8zLqA==",
732
+            "version": "4.30.0",
733
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.0.tgz",
734
+            "integrity": "sha512-1hiHPV6dUaqIMXrIjN+vgJqtfkLpqHS1Xsg0oUfUVD98xGp1wX89PIXgDF2DWra1nxAd8dfE0Dk59MyeKaBVAw==",
735
             "cpu": [
735
             "cpu": [
736
                 "ppc64"
736
                 "ppc64"
737
             ],
737
             ],
743
             ]
743
             ]
744
         },
744
         },
745
         "node_modules/@rollup/rollup-linux-riscv64-gnu": {
745
         "node_modules/@rollup/rollup-linux-riscv64-gnu": {
746
-            "version": "4.29.2",
747
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.2.tgz",
748
-            "integrity": "sha512-YgikssQ5UNq1GoFKZydMEkhKbjlUq7G3h8j6yWXLBF24KyoA5BcMtaOUAXq5sydPmOPEqB6kCyJpyifSpCfQ0w==",
746
+            "version": "4.30.0",
747
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.0.tgz",
748
+            "integrity": "sha512-U0xcC80SMpEbvvLw92emHrNjlS3OXjAM0aVzlWfar6PR0ODWCTQtKeeB+tlAPGfZQXicv1SpWwRz9Hyzq3Jx3g==",
749
             "cpu": [
749
             "cpu": [
750
                 "riscv64"
750
                 "riscv64"
751
             ],
751
             ],
757
             ]
757
             ]
758
         },
758
         },
759
         "node_modules/@rollup/rollup-linux-s390x-gnu": {
759
         "node_modules/@rollup/rollup-linux-s390x-gnu": {
760
-            "version": "4.29.2",
761
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.2.tgz",
762
-            "integrity": "sha512-9ouIR2vFWCyL0Z50dfnon5nOrpDdkTG9lNDs7MRaienQKlTyHcDxplmk3IbhFlutpifBSBr2H4rVILwmMLcaMA==",
760
+            "version": "4.30.0",
761
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.0.tgz",
762
+            "integrity": "sha512-VU/P/IODrNPasgZDLIFJmMiLGez+BN11DQWfTVlViJVabyF3JaeaJkP6teI8760f18BMGCQOW9gOmuzFaI1pUw==",
763
             "cpu": [
763
             "cpu": [
764
                 "s390x"
764
                 "s390x"
765
             ],
765
             ],
771
             ]
771
             ]
772
         },
772
         },
773
         "node_modules/@rollup/rollup-linux-x64-gnu": {
773
         "node_modules/@rollup/rollup-linux-x64-gnu": {
774
-            "version": "4.29.2",
775
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.2.tgz",
776
-            "integrity": "sha512-ckBBNRN/F+NoSUDENDIJ2U9UWmIODgwDB/vEXCPOMcsco1niTkxTXa6D2Y/pvCnpzaidvY2qVxGzLilNs9BSzw==",
774
+            "version": "4.30.0",
775
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.0.tgz",
776
+            "integrity": "sha512-laQVRvdbKmjXuFA3ZiZj7+U24FcmoPlXEi2OyLfbpY2MW1oxLt9Au8q9eHd0x6Pw/Kw4oe9gwVXWwIf2PVqblg==",
777
             "cpu": [
777
             "cpu": [
778
                 "x64"
778
                 "x64"
779
             ],
779
             ],
785
             ]
785
             ]
786
         },
786
         },
787
         "node_modules/@rollup/rollup-linux-x64-musl": {
787
         "node_modules/@rollup/rollup-linux-x64-musl": {
788
-            "version": "4.29.2",
789
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.2.tgz",
790
-            "integrity": "sha512-jycl1wL4AgM2aBFJFlpll/kGvAjhK8GSbEmFT5v3KC3rP/b5xZ1KQmv0vQQ8Bzb2ieFQ0kZFPRMbre/l3Bu9JA==",
788
+            "version": "4.30.0",
789
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.0.tgz",
790
+            "integrity": "sha512-3wzKzduS7jzxqcOvy/ocU/gMR3/QrHEFLge5CD7Si9fyHuoXcidyYZ6jyx8OPYmCcGm3uKTUl+9jUSAY74Ln5A==",
791
             "cpu": [
791
             "cpu": [
792
                 "x64"
792
                 "x64"
793
             ],
793
             ],
799
             ]
799
             ]
800
         },
800
         },
801
         "node_modules/@rollup/rollup-win32-arm64-msvc": {
801
         "node_modules/@rollup/rollup-win32-arm64-msvc": {
802
-            "version": "4.29.2",
803
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.2.tgz",
804
-            "integrity": "sha512-S2V0LlcOiYkNGlRAWZwwUdNgdZBfvsDHW0wYosYFV3c7aKgEVcbonetZXsHv7jRTTX+oY5nDYT4W6B1oUpMNOg==",
802
+            "version": "4.30.0",
803
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.0.tgz",
804
+            "integrity": "sha512-jROwnI1+wPyuv696rAFHp5+6RFhXGGwgmgSfzE8e4xfit6oLRg7GyMArVUoM3ChS045OwWr9aTnU+2c1UdBMyw==",
805
             "cpu": [
805
             "cpu": [
806
                 "arm64"
806
                 "arm64"
807
             ],
807
             ],
813
             ]
813
             ]
814
         },
814
         },
815
         "node_modules/@rollup/rollup-win32-ia32-msvc": {
815
         "node_modules/@rollup/rollup-win32-ia32-msvc": {
816
-            "version": "4.29.2",
817
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.2.tgz",
818
-            "integrity": "sha512-pW8kioj9H5f/UujdoX2atFlXNQ9aCfAxFRaa+mhczwcsusm6gGrSo4z0SLvqLF5LwFqFTjiLCCzGkNK/LE0utQ==",
816
+            "version": "4.30.0",
817
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.0.tgz",
818
+            "integrity": "sha512-duzweyup5WELhcXx5H1jokpr13i3BV9b48FMiikYAwk/MT1LrMYYk2TzenBd0jj4ivQIt58JWSxc19y4SvLP4g==",
819
             "cpu": [
819
             "cpu": [
820
                 "ia32"
820
                 "ia32"
821
             ],
821
             ],
827
             ]
827
             ]
828
         },
828
         },
829
         "node_modules/@rollup/rollup-win32-x64-msvc": {
829
         "node_modules/@rollup/rollup-win32-x64-msvc": {
830
-            "version": "4.29.2",
831
-            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.2.tgz",
832
-            "integrity": "sha512-p6fTArexECPf6KnOHvJXRpAEq0ON1CBtzG/EY4zw08kCHk/kivBc5vUEtnCFNCHOpJZ2ne77fxwRLIKD4wuW2Q==",
830
+            "version": "4.30.0",
831
+            "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.0.tgz",
832
+            "integrity": "sha512-DYvxS0M07PvgvavMIybCOBYheyrqlui6ZQBHJs6GqduVzHSZ06TPPvlfvnYstjODHQ8UUXFwt5YE+h0jFI8kwg==",
833
             "cpu": [
833
             "cpu": [
834
                 "x64"
834
                 "x64"
835
             ],
835
             ],
1235
             "license": "MIT"
1235
             "license": "MIT"
1236
         },
1236
         },
1237
         "node_modules/electron-to-chromium": {
1237
         "node_modules/electron-to-chromium": {
1238
-            "version": "1.5.76",
1239
-            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.76.tgz",
1240
-            "integrity": "sha512-CjVQyG7n7Sr+eBXE86HIulnL5N8xZY1sgmOPGuq/F0Rr0FJq63lg0kEtOIDfZBk44FnDLf6FUJ+dsJcuiUDdDQ==",
1238
+            "version": "1.5.77",
1239
+            "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.77.tgz",
1240
+            "integrity": "sha512-AnJSrt5JpRVgY6dgd5yccguLc5A7oMSF0Kt3fcW+Hp5WTuFbl5upeSFZbMZYy2o7jhmIhU8Ekrd82GhyXUqUUg==",
1241
             "dev": true,
1241
             "dev": true,
1242
             "license": "ISC"
1242
             "license": "ISC"
1243
         },
1243
         },
2242
             }
2242
             }
2243
         },
2243
         },
2244
         "node_modules/rollup": {
2244
         "node_modules/rollup": {
2245
-            "version": "4.29.2",
2246
-            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.2.tgz",
2247
-            "integrity": "sha512-tJXpsEkzsEzyAKIaB3qv3IuvTVcTN7qBw1jL4SPPXM3vzDrJgiLGFY6+HodgFaUHAJ2RYJ94zV5MKRJCoQzQeA==",
2245
+            "version": "4.30.0",
2246
+            "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.0.tgz",
2247
+            "integrity": "sha512-sDnr1pcjTgUT69qBksNF1N1anwfbyYG6TBQ22b03bII8EdiUQ7J0TlozVaTMjT/eEJAO49e1ndV7t+UZfL1+vA==",
2248
             "dev": true,
2248
             "dev": true,
2249
             "license": "MIT",
2249
             "license": "MIT",
2250
             "dependencies": {
2250
             "dependencies": {
2258
                 "npm": ">=8.0.0"
2258
                 "npm": ">=8.0.0"
2259
             },
2259
             },
2260
             "optionalDependencies": {
2260
             "optionalDependencies": {
2261
-                "@rollup/rollup-android-arm-eabi": "4.29.2",
2262
-                "@rollup/rollup-android-arm64": "4.29.2",
2263
-                "@rollup/rollup-darwin-arm64": "4.29.2",
2264
-                "@rollup/rollup-darwin-x64": "4.29.2",
2265
-                "@rollup/rollup-freebsd-arm64": "4.29.2",
2266
-                "@rollup/rollup-freebsd-x64": "4.29.2",
2267
-                "@rollup/rollup-linux-arm-gnueabihf": "4.29.2",
2268
-                "@rollup/rollup-linux-arm-musleabihf": "4.29.2",
2269
-                "@rollup/rollup-linux-arm64-gnu": "4.29.2",
2270
-                "@rollup/rollup-linux-arm64-musl": "4.29.2",
2271
-                "@rollup/rollup-linux-loongarch64-gnu": "4.29.2",
2272
-                "@rollup/rollup-linux-powerpc64le-gnu": "4.29.2",
2273
-                "@rollup/rollup-linux-riscv64-gnu": "4.29.2",
2274
-                "@rollup/rollup-linux-s390x-gnu": "4.29.2",
2275
-                "@rollup/rollup-linux-x64-gnu": "4.29.2",
2276
-                "@rollup/rollup-linux-x64-musl": "4.29.2",
2277
-                "@rollup/rollup-win32-arm64-msvc": "4.29.2",
2278
-                "@rollup/rollup-win32-ia32-msvc": "4.29.2",
2279
-                "@rollup/rollup-win32-x64-msvc": "4.29.2",
2261
+                "@rollup/rollup-android-arm-eabi": "4.30.0",
2262
+                "@rollup/rollup-android-arm64": "4.30.0",
2263
+                "@rollup/rollup-darwin-arm64": "4.30.0",
2264
+                "@rollup/rollup-darwin-x64": "4.30.0",
2265
+                "@rollup/rollup-freebsd-arm64": "4.30.0",
2266
+                "@rollup/rollup-freebsd-x64": "4.30.0",
2267
+                "@rollup/rollup-linux-arm-gnueabihf": "4.30.0",
2268
+                "@rollup/rollup-linux-arm-musleabihf": "4.30.0",
2269
+                "@rollup/rollup-linux-arm64-gnu": "4.30.0",
2270
+                "@rollup/rollup-linux-arm64-musl": "4.30.0",
2271
+                "@rollup/rollup-linux-loongarch64-gnu": "4.30.0",
2272
+                "@rollup/rollup-linux-powerpc64le-gnu": "4.30.0",
2273
+                "@rollup/rollup-linux-riscv64-gnu": "4.30.0",
2274
+                "@rollup/rollup-linux-s390x-gnu": "4.30.0",
2275
+                "@rollup/rollup-linux-x64-gnu": "4.30.0",
2276
+                "@rollup/rollup-linux-x64-musl": "4.30.0",
2277
+                "@rollup/rollup-win32-arm64-msvc": "4.30.0",
2278
+                "@rollup/rollup-win32-ia32-msvc": "4.30.0",
2279
+                "@rollup/rollup-win32-x64-msvc": "4.30.0",
2280
                 "fsevents": "~2.3.2"
2280
                 "fsevents": "~2.3.2"
2281
             }
2281
             }
2282
         },
2282
         },

+ 29
- 0
tests/Feature/Accounting/RecurringInvoiceTest.php Прегледај датотеку

1
+<?php
2
+
3
+use App\Enums\Accounting\IntervalType;
4
+use App\Models\Accounting\RecurringInvoice;
5
+
6
+test('example', function () {
7
+    $recurringInvoice = RecurringInvoice::factory()
8
+        ->custom(IntervalType::Week, 2)
9
+        ->create([
10
+            'start_date' => today(),
11
+            'day_of_week' => today()->dayOfWeek,
12
+        ]);
13
+
14
+    $recurringInvoice->refresh();
15
+
16
+    $nextInvoiceDate = $recurringInvoice->calculateNextDate();
17
+
18
+    expect($nextInvoiceDate)->toEqual(today());
19
+
20
+    $recurringInvoice->update([
21
+        'last_date' => $nextInvoiceDate,
22
+    ]);
23
+
24
+    $recurringInvoice->refresh();
25
+
26
+    $nextInvoiceDate = $recurringInvoice->calculateNextDate();
27
+
28
+    expect($nextInvoiceDate)->toEqual(today()->addWeeks(2));
29
+});

Loading…
Откажи
Сачувај