d2d.emegrendeles.hu/app/Filament/Widgets/DeliveryCalendarWidget.php
2026-04-24 18:09:57 +02:00

388 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Filament\Widgets;
use App\Enums\OverrideScope;
use App\Models\ProfitCenterSupplierSchedule;
use App\Models\DeliveryCalendarOverride;
use App\Models\WorkCalendar;
use App\Enums\WorkDayType;
use App\Services\DeliveryCalendarService;
use App\Services\WorkCalendarService;
use Illuminate\Support\Carbon;
use Saade\FilamentFullCalendar\Widgets\FullCalendarWidget;
use Illuminate\Database\Eloquent\Model;
use Filament\Actions\Action;
use Filament\Forms\Components\Hidden;
use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\Toggle;
use Filament\Forms\Components\TextInput;
use Livewire\Attributes\On;
class DeliveryCalendarWidget extends FullCalendarWidget
{
/**
* @var ProfitCenterSupplierSchedule|null
*/
public Model | int | string | null $record = null;
public ?int $supplierId = null;
public ?int $profitCenterId = null;
/**
* Inaktív (nem választható) napok listája.
*
* @var array<string>
*/
protected array $inactiveDates = [];
public function mount(): void
{
$this->loadRecordFromFilter();
}
public function updatedSupplierId(): void
{
$this->loadRecordFromFilter();
$this->refreshRecords();
}
public function updatedProfitCenterId(): void
{
$this->loadRecordFromFilter();
$this->refreshRecords();
}
#[On('calendar-filter-changed')]
public function onFilterChanged(?int $supplierId, ?int $profitCenterId): void
{
$this->supplierId = $supplierId;
$this->profitCenterId = $profitCenterId;
$this->record = null;
$this->loadRecordFromFilter();
$this->refreshRecords();
}
protected function loadRecordFromFilter(): void
{
if ($this->record instanceof ProfitCenterSupplierSchedule) {
return;
}
if ($this->supplierId && $this->profitCenterId) {
$this->record = ProfitCenterSupplierSchedule::where('supplier_id', $this->supplierId)
->where('profit_center_id', $this->profitCenterId)
->first();
return;
}
if (!$this->record) {
$this->record = ProfitCenterSupplierSchedule::first();
}
}
public function fetchEvents(array $info): array
{
if (!($this->record instanceof ProfitCenterSupplierSchedule)) {
$this->loadRecordFromFilter();
}
if (!$this->record) {
$this->dispatch('calendar-events-done');
return $this->getDemoEvents($info);
}
/** @var DeliveryCalendarService $service */
$service = app(DeliveryCalendarService::class);
/** @var WorkCalendarService $workService */
$workService = app(WorkCalendarService::class);
$start = Carbon::parse($info['start']);
$end = Carbon::parse($info['end']);
$events = [];
// 1. Szállítási napok zöld háttér
$deliveryDates = $service->getAvailableDeliveryDates(
$this->record->profitCenter,
$this->record->supplier,
$start,
$end
);
foreach ($deliveryDates as $date) {
$events[] = [
'id' => 'delivery-' . $date->format('Y-m-d'),
'title' => '',
'start' => $date->format('Y-m-d'),
'end' => $date->addDay()->format('Y-m-d'),
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#4CAF50',
'extendedProps' => ['type' => 'delivery'],
];
}
// 2. Munkaszüneti napok piros háttér
$workCalendarEntries = $workService->getCalendarEntries($start, $end);
foreach ($workCalendarEntries as $entry) {
if ($entry->type === WorkDayType::Holiday) {
$events[] = [
'id' => 'holiday-' . $entry->date->format('Y-m-d'),
'title' => '',
'start' => $entry->date->format('Y-m-d'),
'end' => $entry->date->copy()->addDay()->format('Y-m-d'),
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#EF4444',
'extendedProps' => ['type' => 'holiday'],
];
} elseif ($entry->type === WorkDayType::WorkingDay) {
// 3. Áthelyezett munkanapok narancssárga háttér
$events[] = [
'id' => 'transferred-' . $entry->date->format('Y-m-d'),
'title' => '',
'start' => $entry->date->format('Y-m-d'),
'end' => $entry->date->copy()->addDay()->format('Y-m-d'),
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#F59E0B',
'extendedProps' => ['type' => 'transferred'],
];
}
}
// 4. Hétvégék szürke háttér (inaktív napok)
$current = $start->copy();
while ($current->lte($end)) {
if ($current->isWeekend()) {
$events[] = [
'id' => 'weekend-' . $current->format('Y-m-d'),
'title' => '',
'start' => $current->format('Y-m-d'),
'end' => $current->copy()->addDay()->format('Y-m-d'),
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#E5E7EB',
'extendedProps' => ['type' => 'inactive'],
];
}
$current->addDay();
}
$this->dispatch('calendar-events-done');
return $events;
}
/**
* Demo események generálása, ha nincs valós adat.
*
* @param array{start: string, end: string} $info
* @return array<int, array<string, mixed>>
*/
protected function getDemoEvents(array $info): array
{
$start = Carbon::parse($info['start']);
$end = Carbon::parse($info['end']);
$events = [];
$current = $start->copy();
while ($current->lte($end)) {
$dayOfWeek = $current->dayOfWeek;
$dayOfMonth = $current->day;
$dateStr = $current->format('Y-m-d');
$nextDateStr = $current->copy()->addDay()->format('Y-m-d');
if ($current->isWeekend()) {
// Hétvégék szürke háttér (inaktív)
$events[] = [
'id' => 'weekend-' . $dateStr,
'title' => '',
'start' => $dateStr,
'end' => $nextDateStr,
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#E5E7EB',
'extendedProps' => ['type' => 'inactive'],
];
} elseif ($dayOfWeek === Carbon::MONDAY || $dayOfWeek === Carbon::WEDNESDAY || $dayOfWeek === Carbon::FRIDAY) {
// Hétfő, szerda, péntek zöld háttér (szállítási napok)
$events[] = [
'id' => 'delivery-' . $dateStr,
'title' => '',
'start' => $dateStr,
'end' => $nextDateStr,
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#4CAF50',
'extendedProps' => ['type' => 'delivery'],
];
}
// Néhány speciális nap bemutatóként
if ($dayOfMonth === 15) {
// Minden hónap 15-e narancssárga (áthelyezett munkanap)
$events[] = [
'id' => 'special-orange-' . $dateStr,
'title' => '',
'start' => $dateStr,
'end' => $nextDateStr,
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#F59E0B',
'extendedProps' => ['type' => 'transferred'],
];
}
if ($dayOfMonth === 1) {
// Minden hónap 1-je piros (ünnepnap)
$events[] = [
'id' => 'special-red-' . $dateStr,
'title' => '',
'start' => $dateStr,
'end' => $nextDateStr,
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#EF4444',
'extendedProps' => ['type' => 'holiday'],
];
}
if ($dayOfMonth === 10 || $dayOfMonth === 20) {
// 10-e és 20-a kék (megrendelési határidő)
$events[] = [
'id' => 'special-blue-' . $dateStr,
'title' => '',
'start' => $dateStr,
'end' => $nextDateStr,
'allDay' => true,
'display' => 'background',
'backgroundColor' => '#3B82F6',
'extendedProps' => ['type' => 'deadline'],
];
}
$current->addDay();
}
return $events;
}
public function onDateSelect(string $start, ?string $end, bool $allDay, ?array $view, ?array $resource): void
{
$this->mountAction('manageOverride', [
'date' => Carbon::parse($start)->format('Y-m-d'),
]);
}
public function onEventClick(array $event): void
{
$date = data_get($event, 'start');
if (!$date) {
return;
}
$this->mountAction('manageOverride', [
'date' => Carbon::parse($date)->format('Y-m-d'),
]);
}
protected function headerActions(): array
{
return [
Action::make('manageOverride')
->label('Felülbírálás kezelése')
->modalHeading(fn (array $arguments) => "Szállítás felülbírálása" . (isset($arguments['date']) ? ": " . $arguments['date'] : ""))
->form(fn (array $arguments) => [
Placeholder::make('info')
->hiddenLabel()
->content('A háttérben látható naptárban egyszerre több hónapot is áttekinthet. Itt egy konkrét nap módosítását végezheti el.'),
\Filament\Forms\Components\DatePicker::make('date')
->label('Dátum')
->required()
->default($arguments['date'] ?? null)
->disabled(fn () => isset($arguments['date']))
->dehydrated(),
Toggle::make('is_delivery_day')
->label('Szállítási nap?')
->default(function () use ($arguments) {
$date = $arguments['date'] ?? null;
if (!$date) {
return true;
}
$override = DeliveryCalendarOverride::where('supplier_id', $this->record->supplier_id)
->whereDate('date', $date)
->where('override_scope', OverrideScope::ProfitCenter->value)
->where('profit_center_id', $this->record->profit_center_id)
->first();
if ($override) {
return $override->is_delivery_day;
}
return app(DeliveryCalendarService::class)->isDeliveryDay(
$this->record->profitCenter,
$this->record->supplier,
Carbon::parse($date)
);
}),
TextInput::make('description')
->label('Indoklás / Megjegyzés')
->default(fn () => isset($arguments['date'])
? DeliveryCalendarOverride::where('supplier_id', $this->record->supplier_id)
->whereDate('date', $arguments['date'])
->where('override_scope', OverrideScope::ProfitCenter->value)
->where('profit_center_id', $this->record->profit_center_id)
->first()?->description
: null
),
])
->action(function (array $data) {
DeliveryCalendarOverride::updateOrCreate(
[
'supplier_id' => $this->record->supplier_id,
'override_scope' => OverrideScope::ProfitCenter->value,
'profit_center_id' => $this->record->profit_center_id,
'date' => $data['date'],
],
[
'is_delivery_day' => (bool) $data['is_delivery_day'],
'description' => $data['description'],
]
);
$this->refreshRecords();
}),
];
}
public function config(): array
{
return [
'initialView' => 'multiMonthYear',
'views' => [
'multiMonthYear' => [
'duration' => ['months' => 6],
],
],
'multiMonthMaxColumns' => 6,
'headerToolbar' => [
'left' => 'prev,next today',
'center' => 'title',
'right' => 'multiMonthYear',
],
'locale' => 'hu',
'firstDay' => 1,
'height' => 'auto',
'contentHeight' => 'auto',
'selectable' => true,
'editable' => false,
'dayMaxEvents' => false,
'fixedWeekCount' => false,
];
}
}