ADD delivery calendar part2
This commit is contained in:
parent
1753871799
commit
e31f33d9bf
28
app/Enums/OverrideScope.php
Normal file
28
app/Enums/OverrideScope.php
Normal file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum OverrideScope: string
|
||||
{
|
||||
case General = 'general'; // Általános – adott beszállítóra, minden régióra és profitcenterre
|
||||
case Region = 'region'; // Régió-specifikus – adott régióra vonatkozó felülbírálás
|
||||
case ProfitCenter = 'profit_center'; // Profitcenter-specifikus – csak 1 konkrét profitcenterre
|
||||
|
||||
public function label(): string
|
||||
{
|
||||
return match($this) {
|
||||
self::General => 'Általános (minden telephely)',
|
||||
self::Region => 'Régió-specifikus',
|
||||
self::ProfitCenter => 'Profitcenter-specifikus',
|
||||
};
|
||||
}
|
||||
|
||||
public function color(): string
|
||||
{
|
||||
return match($this) {
|
||||
self::General => 'gray',
|
||||
self::Region => 'warning',
|
||||
self::ProfitCenter => 'info',
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -2,10 +2,12 @@
|
||||
|
||||
namespace App\Filament\Resources\DeliveryCalendarOverrides\Schemas;
|
||||
|
||||
use App\Enums\OverrideScope;
|
||||
use Filament\Forms\Components\DatePicker;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Forms\Components\Toggle;
|
||||
use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Schema;
|
||||
|
||||
class DeliveryCalendarOverrideForm
|
||||
@ -19,6 +21,26 @@ public static function configure(Schema $schema): Schema
|
||||
->relationship('supplier', 'name')
|
||||
->searchable()
|
||||
->required(),
|
||||
Select::make('override_scope')
|
||||
->label('Felülbírálás szintje')
|
||||
->options(collect(OverrideScope::cases())->mapWithKeys(
|
||||
fn(OverrideScope $scope) => [$scope->value => $scope->label()]
|
||||
))
|
||||
->default(OverrideScope::General->value)
|
||||
->required()
|
||||
->live(),
|
||||
Select::make('delivery_schedule_id')
|
||||
->label('Szállítási sablon')
|
||||
->relationship('deliverySchedule', 'name')
|
||||
->searchable()
|
||||
->visible(fn(Get $get) => $get('override_scope') === OverrideScope::Region->value)
|
||||
->required(fn(Get $get) => $get('override_scope') === OverrideScope::Region->value),
|
||||
Select::make('profit_center_id')
|
||||
->label('Profitcenter')
|
||||
->relationship('profitCenter', 'name')
|
||||
->searchable()
|
||||
->visible(fn(Get $get) => $get('override_scope') === OverrideScope::ProfitCenter->value)
|
||||
->required(fn(Get $get) => $get('override_scope') === OverrideScope::ProfitCenter->value),
|
||||
DatePicker::make('date')
|
||||
->label('Dátum')
|
||||
->required()
|
||||
|
||||
@ -2,11 +2,15 @@
|
||||
|
||||
namespace App\Filament\Resources\DeliveryCalendarOverrides\Tables;
|
||||
|
||||
use App\Enums\OverrideScope;
|
||||
use Filament\Actions\BulkActionGroup;
|
||||
use Filament\Actions\DeleteBulkAction;
|
||||
use Filament\Actions\EditAction;
|
||||
use Filament\Actions\ForceDeleteBulkAction;
|
||||
use Filament\Actions\RestoreBulkAction;
|
||||
use Filament\Tables\Columns\IconColumn;
|
||||
use Filament\Tables\Columns\TextColumn;
|
||||
use Filament\Tables\Filters\SelectFilter;
|
||||
use Filament\Tables\Filters\TrashedFilter;
|
||||
use Filament\Tables\Table;
|
||||
|
||||
@ -16,22 +20,42 @@ public static function configure(Table $table): Table
|
||||
{
|
||||
return $table
|
||||
->columns([
|
||||
\Filament\Tables\Columns\TextColumn::make('supplier.name')
|
||||
TextColumn::make('supplier.name')
|
||||
->label('Beszállító')
|
||||
->searchable()
|
||||
->sortable(),
|
||||
\Filament\Tables\Columns\TextColumn::make('date')
|
||||
->label('Dátum')
|
||||
->date()
|
||||
TextColumn::make('override_scope')
|
||||
->label('Szint')
|
||||
->badge()
|
||||
->formatStateUsing(fn(OverrideScope $state) => $state->label())
|
||||
->color(fn(OverrideScope $state) => $state->color())
|
||||
->sortable(),
|
||||
\Filament\Tables\Columns\IconColumn::make('is_delivery_day')
|
||||
TextColumn::make('deliverySchedule.name')
|
||||
->label('Szállítási sablon')
|
||||
->placeholder('—')
|
||||
->toggleable(),
|
||||
TextColumn::make('profitCenter.name')
|
||||
->label('Profitcenter')
|
||||
->placeholder('—')
|
||||
->toggleable(),
|
||||
TextColumn::make('date')
|
||||
->label('Dátum')
|
||||
->date('Y-m-d')
|
||||
->sortable(),
|
||||
IconColumn::make('is_delivery_day')
|
||||
->boolean()
|
||||
->label('Szállítási nap'),
|
||||
\Filament\Tables\Columns\TextColumn::make('description')
|
||||
TextColumn::make('description')
|
||||
->label('Megjegyzés')
|
||||
->limit(30),
|
||||
->limit(30)
|
||||
->toggleable(isToggledHiddenByDefault: true),
|
||||
])
|
||||
->filters([
|
||||
SelectFilter::make('override_scope')
|
||||
->label('Felülbírálás szintje')
|
||||
->options(collect(OverrideScope::cases())->mapWithKeys(
|
||||
fn(OverrideScope $scope) => [$scope->value => $scope->label()]
|
||||
)),
|
||||
TrashedFilter::make(),
|
||||
])
|
||||
->recordActions([
|
||||
|
||||
342
app/Filament/Widgets/DeliveryCalendarWidget.php
Normal file
342
app/Filament/Widgets/DeliveryCalendarWidget.php
Normal file
@ -0,0 +1,342 @@
|
||||
<?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;
|
||||
|
||||
class DeliveryCalendarWidget extends FullCalendarWidget
|
||||
{
|
||||
/**
|
||||
* @var ProfitCenterSupplierSchedule|null
|
||||
*/
|
||||
public Model | int | string | null $record = null;
|
||||
|
||||
/**
|
||||
* Inaktív (nem választható) napok listája.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected array $inactiveDates = [];
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
if (!$this->record) {
|
||||
$this->record = ProfitCenterSupplierSchedule::first();
|
||||
}
|
||||
}
|
||||
|
||||
public function fetchEvents(array $info): array
|
||||
{
|
||||
if (!$this->record) {
|
||||
$this->record = ProfitCenterSupplierSchedule::first();
|
||||
}
|
||||
|
||||
if (!$this->record) {
|
||||
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();
|
||||
}
|
||||
|
||||
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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\OverrideScope;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
@ -14,10 +15,21 @@ class DeliveryCalendarOverride extends BaseAuditable
|
||||
protected $casts = [
|
||||
'date' => 'date',
|
||||
'is_delivery_day' => 'boolean',
|
||||
'override_scope' => OverrideScope::class,
|
||||
];
|
||||
|
||||
public function supplier(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Supplier::class);
|
||||
}
|
||||
|
||||
public function profitCenter(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ProfitCenter::class);
|
||||
}
|
||||
|
||||
public function deliverySchedule(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(DeliverySchedule::class);
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,6 +57,8 @@ public function boot(): void
|
||||
});
|
||||
|
||||
\Livewire\Livewire::component('app.filament.pages.price-list-processor', \App\Filament\Pages\PriceListProcessor::class);
|
||||
\Livewire\Livewire::component('app.filament.pages.calendar-test', \App\Filament\Pages\CalendarTest::class);
|
||||
\Livewire\Livewire::component('app.filament.widgets.delivery-calendar-widget', \App\Filament\Widgets\DeliveryCalendarWidget::class);
|
||||
/*
|
||||
\Livewire\Livewire::component('filament.livewire.notifications', \Filament\Livewire\Notifications::class);
|
||||
\Livewire\Livewire::component('filament.livewire.database-notifications', \Filament\Livewire\DatabaseNotifications::class);
|
||||
|
||||
@ -2,11 +2,12 @@
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Enums\OverrideScope;
|
||||
use App\Models\DeliveryCalendarOverride;
|
||||
use App\Models\ProfitCenter;
|
||||
use App\Models\ProfitCenterSupplierSchedule;
|
||||
use App\Models\Supplier;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class DeliveryCalendarService extends ServiceBase
|
||||
@ -18,32 +19,64 @@ public function __construct(
|
||||
|
||||
/**
|
||||
* Eldönti, hogy egy adott Profit Center, Beszállító és Dátum kombináció esetén van-e szállítás.
|
||||
*
|
||||
* A felülbírálás kiértékelése 3 szinten történik (legspecifikusabbtól az általánosig):
|
||||
* 1. Profitcenter-specifikus override (csak erre az 1 PC-re)
|
||||
* 2. Régió-specifikus override (a PC városához/régiójához tartozó)
|
||||
* 3. Általános override (az összes PC-re vonatkozó)
|
||||
* Ha egyetlen szinten sem található override, folytatódik a normál kiértékelés.
|
||||
*/
|
||||
public function isDeliveryDay(ProfitCenter $pc, Supplier $supplier, Carbon $date): bool
|
||||
{
|
||||
$date = $date->startOfDay();
|
||||
|
||||
// 1. Prioritás: Beszállítói felülbírálás (Override)
|
||||
// 1. Prioritás: Profitcenter-specifikus felülbírálás
|
||||
$override = DeliveryCalendarOverride::where('supplier_id', $supplier->id)
|
||||
->whereDate('date', $date)
|
||||
->where('override_scope', OverrideScope::ProfitCenter->value)
|
||||
->where('profit_center_id', $pc->id)
|
||||
->first();
|
||||
|
||||
if ($override) {
|
||||
return $override->is_delivery_day;
|
||||
}
|
||||
|
||||
// 2. Prioritás: Hivatalos ünnepnap (WorkCalendar)
|
||||
// Ha aznap nem hivatalos munkanap van, akkor nincs szállítás (kivéve ha az 1. pont felülbírálta).
|
||||
if (! $this->workCalendarService->isWorkDay($date)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. Prioritás: Heti sablon (Schedule)
|
||||
// PC-hez rendelt szállítási sablon lekérése (2. és 5. prioritáshoz egyaránt szükséges)
|
||||
$assignment = ProfitCenterSupplierSchedule::where('profit_center_id', $pc->id)
|
||||
->where('supplier_id', $supplier->id)
|
||||
->with('deliverySchedule')
|
||||
->first();
|
||||
|
||||
// 2. Prioritás: DeliverySchedule-specifikus felülbírálás (a PC-hez rendelt szállítási sablon alapján)
|
||||
if ($assignment && $assignment->delivery_schedule_id) {
|
||||
$override = DeliveryCalendarOverride::where('supplier_id', $supplier->id)
|
||||
->whereDate('date', $date)
|
||||
->where('override_scope', OverrideScope::Region->value)
|
||||
->where('delivery_schedule_id', $assignment->delivery_schedule_id)
|
||||
->first();
|
||||
|
||||
if ($override) {
|
||||
return $override->is_delivery_day;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Prioritás: Általános felülbírálás (minden PC-re vonatkozik)
|
||||
$override = DeliveryCalendarOverride::where('supplier_id', $supplier->id)
|
||||
->whereDate('date', $date)
|
||||
->where('override_scope', OverrideScope::General->value)
|
||||
->first();
|
||||
|
||||
if ($override) {
|
||||
return $override->is_delivery_day;
|
||||
}
|
||||
|
||||
// 4. Prioritás: Hivatalos ünnepnap (WorkCalendar)
|
||||
// Ha aznap nem hivatalos munkanap van, akkor nincs szállítás (kivéve ha az 1-3. pont felülbírálta).
|
||||
if (! $this->workCalendarService->isWorkDay($date)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 5. Prioritás: Heti sablon (Schedule)
|
||||
if (! $assignment || ! $assignment->deliverySchedule || ! $assignment->deliverySchedule->is_active) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@
|
||||
|
||||
namespace Database\Factories;
|
||||
|
||||
use App\Enums\OverrideScope;
|
||||
use App\Models\DeliveryCalendarOverride;
|
||||
use App\Models\DeliverySchedule;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
@ -19,9 +21,39 @@ public function definition(): array
|
||||
{
|
||||
return [
|
||||
'supplier_id' => \App\Models\Supplier::factory(),
|
||||
'override_scope' => OverrideScope::General,
|
||||
'delivery_schedule_id' => null,
|
||||
'profit_center_id' => null,
|
||||
'date' => $this->faker->date(),
|
||||
'is_delivery_day' => $this->faker->boolean(),
|
||||
'description' => $this->faker->sentence(),
|
||||
];
|
||||
}
|
||||
|
||||
public function general(): static
|
||||
{
|
||||
return $this->state([
|
||||
'override_scope' => OverrideScope::General,
|
||||
'delivery_schedule_id' => null,
|
||||
'profit_center_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function forDeliverySchedule(DeliverySchedule $schedule): static
|
||||
{
|
||||
return $this->state([
|
||||
'override_scope' => OverrideScope::Region,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
'profit_center_id' => null,
|
||||
]);
|
||||
}
|
||||
|
||||
public function forProfitCenter(\App\Models\ProfitCenter $profitCenter): static
|
||||
{
|
||||
return $this->state([
|
||||
'override_scope' => OverrideScope::ProfitCenter,
|
||||
'delivery_schedule_id' => null,
|
||||
'profit_center_id' => $profitCenter->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('delivery_calendar_overrides', function (Blueprint $table) {
|
||||
$table->string('override_scope')->default('general')->after('supplier_id');
|
||||
$table->string('region')->nullable()->after('override_scope');
|
||||
$table->foreignId('profit_center_id')->nullable()->constrained()->nullOnDelete()->after('region');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('delivery_calendar_overrides', function (Blueprint $table) {
|
||||
$table->dropForeign(['profit_center_id']);
|
||||
$table->dropColumn(['override_scope', 'region', 'profit_center_id']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('delivery_calendar_overrides', function (Blueprint $table) {
|
||||
$table->dropColumn('region');
|
||||
$table->foreignId('delivery_schedule_id')->nullable()->constrained()->nullOnDelete()->after('override_scope');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('delivery_calendar_overrides', function (Blueprint $table) {
|
||||
$table->dropForeign(['delivery_schedule_id']);
|
||||
$table->dropColumn('delivery_schedule_id');
|
||||
$table->string('region')->nullable()->after('override_scope');
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -19,6 +19,7 @@
|
||||
['displayName' => 'Profitcenter ütemezés', 'link' => \App\Filament\Resources\ProfitCenterSupplierSchedules\ProfitCenterSupplierScheduleResource::getUrl()],
|
||||
['displayName' => 'Munkanaptárak', 'link' => \App\Filament\Resources\WorkCalendars\WorkCalendarResource::getUrl()],
|
||||
]],
|
||||
['name' => 'calendarTest', 'displayName' => 'Naptár Teszt', 'icon' => 'idopontok', 'link' => \App\Filament\Pages\CalendarTest::getUrl(), 'roles' => ['root','developer','admin']],
|
||||
];
|
||||
@endphp
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Enums\OverrideScope;
|
||||
use App\Models\DeliveryCalendarOverride;
|
||||
use App\Models\DeliverySchedule;
|
||||
use App\Models\ProfitCenter;
|
||||
@ -21,16 +22,13 @@
|
||||
$schedule = DeliverySchedule::factory()->create([
|
||||
'monday' => true,
|
||||
]);
|
||||
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
$monday = Carbon::parse('2026-04-13'); // Monday
|
||||
|
||||
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
|
||||
});
|
||||
|
||||
@ -41,16 +39,13 @@
|
||||
'monday' => true,
|
||||
'tuesday' => false,
|
||||
]);
|
||||
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
$tuesday = Carbon::parse('2026-04-14'); // Tuesday
|
||||
|
||||
expect($service->isDeliveryDay($pc, $supplier, $tuesday))->toBeFalse();
|
||||
});
|
||||
|
||||
@ -58,84 +53,193 @@
|
||||
$pc = ProfitCenter::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$schedule = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
|
||||
$monday = Carbon::parse('2026-04-13'); // Monday
|
||||
|
||||
// Mark this Monday as a holiday
|
||||
WorkCalendar::create([
|
||||
'date' => '2026-04-13',
|
||||
'type' => WorkDayType::Holiday,
|
||||
'data_source' => DataSource::Manual,
|
||||
]);
|
||||
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
|
||||
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeFalse();
|
||||
});
|
||||
|
||||
it('respects supplier overrides over holidays', function () {
|
||||
it('respects general supplier override over holidays', function () {
|
||||
$pc = ProfitCenter::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$schedule = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
|
||||
$monday = Carbon::parse('2026-04-13'); // Monday
|
||||
|
||||
// Mark this Monday as a holiday
|
||||
WorkCalendar::create([
|
||||
'date' => '2026-04-13',
|
||||
'type' => WorkDayType::Holiday,
|
||||
'data_source' => DataSource::Manual,
|
||||
]);
|
||||
|
||||
// Create an override to allow delivery despite the holiday
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::General->value,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => true,
|
||||
]);
|
||||
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
|
||||
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
|
||||
});
|
||||
|
||||
it('respects supplier overrides to block delivery on a normal day', function () {
|
||||
it('respects general supplier override to block delivery on a normal day', function () {
|
||||
$pc = ProfitCenter::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$schedule = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
|
||||
$monday = Carbon::parse('2026-04-13'); // Monday
|
||||
|
||||
// Create an override to block delivery
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::General->value,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => false,
|
||||
]);
|
||||
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
|
||||
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeFalse();
|
||||
});
|
||||
|
||||
it('respects delivery-schedule-specific override over general override', function () {
|
||||
$pc = ProfitCenter::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
$schedule = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
$monday = Carbon::parse('2026-04-13');
|
||||
// Általános tiltás
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::General->value,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => false,
|
||||
]);
|
||||
// Szállítási sablon-specifikus engedélyezés
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::Region->value,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => true,
|
||||
]);
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
// A sablon-specifikus győz az általánossal szemben
|
||||
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
|
||||
});
|
||||
|
||||
it('delivery-schedule override does not affect profit centers with different schedule', function () {
|
||||
$supplier = Supplier::factory()->create();
|
||||
$scheduleA = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
$scheduleB = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
$pcA = ProfitCenter::factory()->create();
|
||||
$pcB = ProfitCenter::factory()->create();
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pcA->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $scheduleA->id,
|
||||
]);
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pcB->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $scheduleB->id,
|
||||
]);
|
||||
$monday = Carbon::parse('2026-04-13');
|
||||
// Csak az A sablont tiltjuk
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::Region->value,
|
||||
'delivery_schedule_id' => $scheduleA->id,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => false,
|
||||
]);
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
expect($service->isDeliveryDay($pcA, $supplier, $monday))->toBeFalse();
|
||||
expect($service->isDeliveryDay($pcB, $supplier, $monday))->toBeTrue();
|
||||
});
|
||||
|
||||
it('respects profit-center-specific override over region and general overrides', function () {
|
||||
$pc = ProfitCenter::factory()->create(['city' => 'Budapest']);
|
||||
$supplier = Supplier::factory()->create();
|
||||
$schedule = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
$monday = Carbon::parse('2026-04-13');
|
||||
// Általános tiltás
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::General->value,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => false,
|
||||
]);
|
||||
// Sablon-specifikus tiltás is
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::Region->value,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => false,
|
||||
]);
|
||||
// De erre a konkrét PC-re engedélyezve van
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::ProfitCenter->value,
|
||||
'profit_center_id' => $pc->id,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => true,
|
||||
]);
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
|
||||
});
|
||||
|
||||
it('profit-center-specific override only affects the targeted profit center', function () {
|
||||
$pc1 = ProfitCenter::factory()->create(['city' => 'Budapest']);
|
||||
$pc2 = ProfitCenter::factory()->create(['city' => 'Budapest']);
|
||||
$supplier = Supplier::factory()->create();
|
||||
$schedule = DeliverySchedule::factory()->create(['monday' => true]);
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc1->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc2->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
$monday = Carbon::parse('2026-04-13');
|
||||
// Csak pc1-re van tiltás
|
||||
DeliveryCalendarOverride::create([
|
||||
'supplier_id' => $supplier->id,
|
||||
'override_scope' => OverrideScope::ProfitCenter->value,
|
||||
'profit_center_id' => $pc1->id,
|
||||
'date' => '2026-04-13',
|
||||
'is_delivery_day' => false,
|
||||
]);
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
expect($service->isDeliveryDay($pc1, $supplier, $monday))->toBeFalse();
|
||||
expect($service->isDeliveryDay($pc2, $supplier, $monday))->toBeTrue();
|
||||
});
|
||||
|
||||
it('calculates available delivery dates in a range', function () {
|
||||
$pc = ProfitCenter::factory()->create();
|
||||
$supplier = Supplier::factory()->create();
|
||||
@ -144,19 +248,15 @@
|
||||
'wednesday' => true,
|
||||
'friday' => true,
|
||||
]);
|
||||
|
||||
ProfitCenterSupplierSchedule::factory()->create([
|
||||
'profit_center_id' => $pc->id,
|
||||
'supplier_id' => $supplier->id,
|
||||
'delivery_schedule_id' => $schedule->id,
|
||||
]);
|
||||
|
||||
$start = Carbon::parse('2026-04-13'); // Monday
|
||||
$end = Carbon::parse('2026-04-19'); // Sunday
|
||||
|
||||
$service = app(DeliveryCalendarService::class);
|
||||
$dates = $service->getAvailableDeliveryDates($pc, $supplier, $start, $end);
|
||||
|
||||
// Should be Mon, Wed, Fri
|
||||
expect($dates)->toHaveCount(3);
|
||||
$dateStrings = $dates->map(fn($d) => $d->toDateString());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user