From 1e00304eda6bf6f707271ca37b9718665d0d3da2 Mon Sep 17 00:00:00 2001 From: E98Developer Date: Sat, 25 Apr 2026 05:54:05 +0200 Subject: [PATCH] ADD NextDeliveryDateCalculatorService --- app/Filament/Pages/CalendarTest.php | 69 +++++++++++++ .../Widgets/DeliveryCalendarWidget.php | 27 ++++++ .../NextDeliveryDateCalculatorService.php | 97 +++++++++++++++++++ .../filament/pages/calendar-test.blade.php | 60 +++++++++++- 4 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 app/Services/NextDeliveryDateCalculatorService.php diff --git a/app/Filament/Pages/CalendarTest.php b/app/Filament/Pages/CalendarTest.php index bc1734f..ca5cd7e 100644 --- a/app/Filament/Pages/CalendarTest.php +++ b/app/Filament/Pages/CalendarTest.php @@ -5,6 +5,7 @@ use App\Models\ProfitCenter; use App\Models\ProfitCenterSupplierSchedule; use App\Models\Supplier; +use App\Services\NextDeliveryDateCalculatorService; use Filament\Pages\Page; class CalendarTest extends Page @@ -21,8 +22,16 @@ class CalendarTest extends Page public ?int $profitCenterId = null; + public string $selectedDate = ''; + + public string $selectedTime = ''; + public function mount(): void { + $now = now(); + $this->selectedDate = $now->format('Y-m-d'); + $this->selectedTime = $now->format('H:i'); + $first = ProfitCenterSupplierSchedule::first(); if ($first) { @@ -31,6 +40,49 @@ public function mount(): void } } + public function getSupplier(): ?Supplier + { + if (!$this->supplierId) { + return null; + } + + return Supplier::find($this->supplierId); + } + + public function getNextDeliveryDate(): ?string + { + if (! $this->supplierId || ! $this->profitCenterId || ! $this->selectedDate || ! $this->selectedTime) { + return null; + } + + $dt = \Illuminate\Support\Carbon::parse("{$this->selectedDate} {$this->selectedTime}"); + + $result = app(NextDeliveryDateCalculatorService::class)->calculate( + supplierId: $this->supplierId, + profitCenterId: $this->profitCenterId, + orderDateTime: $dt, + ); + + return $result?->translatedFormat('Y. F j., l'); + } + + public function getNextDeliveryDateRaw(): ?string + { + if (! $this->supplierId || ! $this->profitCenterId || ! $this->selectedDate || ! $this->selectedTime) { + return null; + } + + $dt = \Illuminate\Support\Carbon::parse("{$this->selectedDate} {$this->selectedTime}"); + + $result = app(NextDeliveryDateCalculatorService::class)->calculate( + supplierId: $this->supplierId, + profitCenterId: $this->profitCenterId, + orderDateTime: $dt, + ); + + return $result?->format('Y-m-d'); + } + public function getSuppliers(): array { return Supplier::orderBy('name')->pluck('name', 'id')->toArray(); @@ -59,11 +111,28 @@ public function updatedSupplierId(): void } $this->dispatch('calendar-filter-changed', supplierId: $this->supplierId, profitCenterId: $this->profitCenterId); + $this->dispatchNextDeliveryDateChanged(); } public function updatedProfitCenterId(): void { $this->dispatch('calendar-filter-changed', supplierId: $this->supplierId, profitCenterId: $this->profitCenterId); + $this->dispatchNextDeliveryDateChanged(); + } + + public function updatedSelectedDate(): void + { + $this->dispatchNextDeliveryDateChanged(); + } + + public function updatedSelectedTime(): void + { + $this->dispatchNextDeliveryDateChanged(); + } + + protected function dispatchNextDeliveryDateChanged(): void + { + $this->dispatch('next-delivery-date-changed', date: $this->getNextDeliveryDateRaw()); } } diff --git a/app/Filament/Widgets/DeliveryCalendarWidget.php b/app/Filament/Widgets/DeliveryCalendarWidget.php index e443a13..f933a81 100644 --- a/app/Filament/Widgets/DeliveryCalendarWidget.php +++ b/app/Filament/Widgets/DeliveryCalendarWidget.php @@ -30,6 +30,9 @@ class DeliveryCalendarWidget extends FullCalendarWidget public ?int $profitCenterId = null; + /** Következő szállítási nap dátuma (YYYY-MM-DD formátum), kék kiemeléshez. */ + public ?string $nextDeliveryDate = null; + /** * Inaktív (nem választható) napok listája. * @@ -64,6 +67,13 @@ public function onFilterChanged(?int $supplierId, ?int $profitCenterId): void $this->refreshRecords(); } + #[On('next-delivery-date-changed')] + public function onNextDeliveryDateChanged(?string $date): void + { + $this->nextDeliveryDate = $date; + $this->refreshRecords(); + } + protected function loadRecordFromFilter(): void { if ($this->record instanceof ProfitCenterSupplierSchedule) { @@ -171,6 +181,23 @@ public function fetchEvents(array $info): array $current->addDay(); } + // 5. Következő szállítási nap – kék háttér + if ($this->nextDeliveryDate) { + $nextDate = Carbon::parse($this->nextDeliveryDate); + if ($nextDate->between($start, $end)) { + $events[] = [ + 'id' => 'next-delivery-' . $nextDate->format('Y-m-d'), + 'title' => '', + 'start' => $nextDate->format('Y-m-d'), + 'end' => $nextDate->copy()->addDay()->format('Y-m-d'), + 'allDay' => true, + 'display' => 'background', + 'backgroundColor' => '#3B82F6', + 'extendedProps' => ['type' => 'next-delivery'], + ]; + } + } + $this->dispatch('calendar-events-done'); return $events; } diff --git a/app/Services/NextDeliveryDateCalculatorService.php b/app/Services/NextDeliveryDateCalculatorService.php new file mode 100644 index 0000000..93c7aca --- /dev/null +++ b/app/Services/NextDeliveryDateCalculatorService.php @@ -0,0 +1,97 @@ +where('profit_center_id', $profitCenterId) + ->with('deliverySchedule') + ->first(); + + if (! $assignment?->deliverySchedule) { + return null; + } + + $supplier = Supplier::find($supplierId); + $pc = ProfitCenter::find($profitCenterId); + + if (! $supplier || ! $pc) { + return null; + } + + $leadDays = 0; + $startDay = $orderDateTime->copy()->startOfDay(); + + if ($supplier->hasDeliveryConstraint) { + $cutOffHour = (int) $supplier->orderCutOffTime; + $leadDays = (int) ($supplier->deliveryLeadTime / 24); + + // Ha a leadási határidő UTÁN vagyunk, holnap az első számítandó munkanap + if ($orderDateTime->hour >= $cutOffHour) { + $startDay->addDay(); + } + } + + return $this->findNextDeliveryDay($startDay, $supplier, $pc, $leadDays); + } + + /** + * Munkanapokban számol előre ($leadDays darabot), majd az első olyan napot adja vissza, + * amelyik szállítási nap is. + */ + private function findNextDeliveryDay( + Carbon $candidate, + Supplier $supplier, + ProfitCenter $pc, + int $leadDays, + ): ?Carbon { + $workingDaysCounted = 0; + + // Max. 365 nap iteráció (végtelen ciklus-védelem) + for ($i = 0; $i < 365; $i++) { + if ($this->workCalendarService->isWorkDay($candidate)) { + if ($workingDaysCounted >= $leadDays) { + // Átfutási idő letelt – az első szállítási napot keressük + if ($this->deliveryCalendarService->isDeliveryDay($pc, $supplier, $candidate)) { + return $candidate->copy(); + } + } else { + $workingDaysCounted++; + } + } + $candidate->addDay(); + } + + return null; + } +} diff --git a/resources/views/filament/pages/calendar-test.blade.php b/resources/views/filament/pages/calendar-test.blade.php index f810e1f..64c0904 100644 --- a/resources/views/filament/pages/calendar-test.blade.php +++ b/resources/views/filament/pages/calendar-test.blade.php @@ -33,6 +33,62 @@ class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text- + {{-- Szállítási korlátozások --}} +
+

Szállítási korlátozások

+
+ @if ($supplierId && ($supplier = $this->getSupplier())) +
+ Szállítási korlátozás: + @if ($supplier->hasDeliveryConstraint) + Igen + @else + Nem + @endif +
+ @if ($supplier->hasDeliveryConstraint) +
+ Leadási határidő: + {{ $supplier->orderCutOffTime }}:00 +
+
+ Szállítási átfutási idő: + {{ $supplier->deliveryLeadTime }} óra +
+ @endif + @endif +
+ + +
+
+ + +
+ @php($nextDelivery = $this->getNextDeliveryDate()) + @if ($nextDelivery) +
+ Következő szállítási nap: + {{ $nextDelivery }} +
+ @elseif ($supplierId && $profitCenterId) +
+ Nem található következő szállítási nap. +
+ @endif +
+
+ {{-- Jelmagyarázat --}}
Jelmagyarázat: @@ -50,7 +106,7 @@ class="w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text- - Megrendelési határidő + Következő szállítási nap @@ -79,9 +135,11 @@ class="absolute inset-0 z-10 flex items-center justify-center rounded-xl bg-whit
+ @php($nextDeliveryRaw = $this->getNextDeliveryDateRaw()) @livewire(\App\Filament\Widgets\DeliveryCalendarWidget::class, [ 'supplierId' => $supplierId, 'profitCenterId' => $profitCenterId, + 'nextDeliveryDate' => $nextDeliveryRaw, ])