ADD DeliveryCalendar phase1

This commit is contained in:
E98Developer 2026-04-15 06:42:55 +02:00
parent 0581fee616
commit 9fa6a7b056
37 changed files with 1313 additions and 1 deletions

View File

@ -0,0 +1,68 @@
<?php
namespace App\Filament\Resources\DeliveryCalendarOverrides;
use App\Filament\Resources\DeliveryCalendarOverrides\Pages\CreateDeliveryCalendarOverride;
use App\Filament\Resources\DeliveryCalendarOverrides\Pages\EditDeliveryCalendarOverride;
use App\Filament\Resources\DeliveryCalendarOverrides\Pages\ListDeliveryCalendarOverrides;
use App\Filament\Resources\DeliveryCalendarOverrides\Schemas\DeliveryCalendarOverrideForm;
use App\Filament\Resources\DeliveryCalendarOverrides\Tables\DeliveryCalendarOverridesTable;
use App\Models\DeliveryCalendarOverride;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class DeliveryCalendarOverrideResource extends Resource
{
protected static ?string $model = DeliveryCalendarOverride::class;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-exclamation-triangle';
protected static string|\UnitEnum|null $navigationGroup = 'Szállítási naptár';
protected static ?string $navigationLabel = 'Beszállítói felülbírálások';
protected static ?string $modelLabel = 'Beszállítói felülbírálás';
protected static ?string $pluralLabel = 'Beszállítói felülbírálások';
protected static ?string $breadcrumb = 'Beszállítói felülbírálások';
public static function form(Schema $schema): Schema
{
return DeliveryCalendarOverrideForm::configure($schema);
}
public static function table(Table $table): Table
{
return DeliveryCalendarOverridesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListDeliveryCalendarOverrides::route('/'),
'create' => CreateDeliveryCalendarOverride::route('/create'),
'edit' => EditDeliveryCalendarOverride::route('/{record}/edit'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\DeliveryCalendarOverrides\Pages;
use App\Filament\Resources\DeliveryCalendarOverrides\DeliveryCalendarOverrideResource;
use Filament\Resources\Pages\CreateRecord;
class CreateDeliveryCalendarOverride extends CreateRecord
{
protected static string $resource = DeliveryCalendarOverrideResource::class;
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Filament\Resources\DeliveryCalendarOverrides\Pages;
use App\Filament\Resources\DeliveryCalendarOverrides\DeliveryCalendarOverrideResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\RestoreAction;
use Filament\Resources\Pages\EditRecord;
class EditDeliveryCalendarOverride extends EditRecord
{
protected static string $resource = DeliveryCalendarOverrideResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
ForceDeleteAction::make(),
RestoreAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DeliveryCalendarOverrides\Pages;
use App\Filament\Resources\DeliveryCalendarOverrides\DeliveryCalendarOverrideResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListDeliveryCalendarOverrides extends ListRecords
{
protected static string $resource = DeliveryCalendarOverrideResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Filament\Resources\DeliveryCalendarOverrides\Schemas;
use Filament\Forms\Components\DatePicker;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class DeliveryCalendarOverrideForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('supplier_id')
->label('Beszállító')
->relationship('supplier', 'name')
->searchable()
->required(),
DatePicker::make('date')
->label('Dátum')
->required()
->native(false)
->displayFormat('Y-m-d'),
Toggle::make('is_delivery_day')
->label('Szállítási nap?')
->default(true),
TextInput::make('description')
->label('Indoklás / Megjegyzés')
->maxLength(255),
]);
}
}

View File

@ -0,0 +1,48 @@
<?php
namespace App\Filament\Resources\DeliveryCalendarOverrides\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
class DeliveryCalendarOverridesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
\Filament\Tables\Columns\TextColumn::make('supplier.name')
->label('Beszállító')
->searchable()
->sortable(),
\Filament\Tables\Columns\TextColumn::make('date')
->label('Dátum')
->date()
->sortable(),
\Filament\Tables\Columns\IconColumn::make('is_delivery_day')
->boolean()
->label('Szállítási nap'),
\Filament\Tables\Columns\TextColumn::make('description')
->label('Megjegyzés')
->limit(30),
])
->filters([
TrashedFilter::make(),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
ForceDeleteBulkAction::make(),
RestoreBulkAction::make(),
]),
]);
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Filament\Resources\DeliverySchedules;
use App\Filament\Resources\DeliverySchedules\Pages\CreateDeliverySchedule;
use App\Filament\Resources\DeliverySchedules\Pages\EditDeliverySchedule;
use App\Filament\Resources\DeliverySchedules\Pages\ListDeliverySchedules;
use App\Filament\Resources\DeliverySchedules\Schemas\DeliveryScheduleForm;
use App\Filament\Resources\DeliverySchedules\Tables\DeliverySchedulesTable;
use App\Models\DeliverySchedule;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class DeliveryScheduleResource extends Resource
{
protected static ?string $model = DeliverySchedule::class;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-calendar-days';
protected static string|\UnitEnum|null $navigationGroup = 'Szállítási naptár';
protected static ?string $navigationLabel = 'Szállítási sablonok';
protected static ?string $modelLabel = 'Szállítási sablon';
protected static ?string $pluralLabel = 'Szállítási sablonok';
protected static ?string $breadcrumb = 'Szállítási sablonok';
public static function form(Schema $schema): Schema
{
return DeliveryScheduleForm::configure($schema);
}
public static function table(Table $table): Table
{
return DeliverySchedulesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListDeliverySchedules::route('/'),
'create' => CreateDeliverySchedule::route('/create'),
'edit' => EditDeliverySchedule::route('/{record}/edit'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\DeliverySchedules\Pages;
use App\Filament\Resources\DeliverySchedules\DeliveryScheduleResource;
use Filament\Resources\Pages\CreateRecord;
class CreateDeliverySchedule extends CreateRecord
{
protected static string $resource = DeliveryScheduleResource::class;
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Filament\Resources\DeliverySchedules\Pages;
use App\Filament\Resources\DeliverySchedules\DeliveryScheduleResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\RestoreAction;
use Filament\Resources\Pages\EditRecord;
class EditDeliverySchedule extends EditRecord
{
protected static string $resource = DeliveryScheduleResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
ForceDeleteAction::make(),
RestoreAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\DeliverySchedules\Pages;
use App\Filament\Resources\DeliverySchedules\DeliveryScheduleResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListDeliverySchedules extends ListRecords
{
protected static string $resource = DeliveryScheduleResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@ -0,0 +1,39 @@
<?php
namespace App\Filament\Resources\DeliverySchedules\Schemas;
use Filament\Schemas\Components\Section;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Schema;
class DeliveryScheduleForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Section::make('Sablon adatai')
->schema([
TextInput::make('name')
->label('Sablon neve')
->required()
->maxLength(255),
Toggle::make('is_active')
->label('Aktív')
->default(true),
]),
Section::make('Szállítási napok')
->columns(7)
->schema([
Toggle::make('monday')->label('Hétfő')->default(false),
Toggle::make('tuesday')->label('Kedd')->default(false),
Toggle::make('wednesday')->label('Szerda')->default(false),
Toggle::make('thursday')->label('Csütörtök')->default(false),
Toggle::make('friday')->label('Péntek')->default(false),
Toggle::make('saturday')->label('Szombat')->default(false),
Toggle::make('sunday')->label('Vasárnap')->default(false),
]),
]);
}
}

View File

@ -0,0 +1,49 @@
<?php
namespace App\Filament\Resources\DeliverySchedules\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
class DeliverySchedulesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
\Filament\Tables\Columns\TextColumn::make('name')
->label('Név')
->searchable()
->sortable(),
\Filament\Tables\Columns\IconColumn::make('monday')->boolean()->label('H'),
\Filament\Tables\Columns\IconColumn::make('tuesday')->boolean()->label('K'),
\Filament\Tables\Columns\IconColumn::make('wednesday')->boolean()->label('Sze'),
\Filament\Tables\Columns\IconColumn::make('thursday')->boolean()->label('Cs'),
\Filament\Tables\Columns\IconColumn::make('friday')->boolean()->label('P'),
\Filament\Tables\Columns\IconColumn::make('saturday')->boolean()->label('Szo'),
\Filament\Tables\Columns\IconColumn::make('sunday')->boolean()->label('V'),
\Filament\Tables\Columns\IconColumn::make('is_active')
->boolean()
->label('Aktív')
->sortable(),
])
->filters([
TrashedFilter::make(),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
ForceDeleteBulkAction::make(),
RestoreBulkAction::make(),
]),
]);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\ProfitCenterSupplierSchedules\Pages;
use App\Filament\Resources\ProfitCenterSupplierSchedules\ProfitCenterSupplierScheduleResource;
use Filament\Resources\Pages\CreateRecord;
class CreateProfitCenterSupplierSchedule extends CreateRecord
{
protected static string $resource = ProfitCenterSupplierScheduleResource::class;
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Filament\Resources\ProfitCenterSupplierSchedules\Pages;
use App\Filament\Resources\ProfitCenterSupplierSchedules\ProfitCenterSupplierScheduleResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\RestoreAction;
use Filament\Resources\Pages\EditRecord;
class EditProfitCenterSupplierSchedule extends EditRecord
{
protected static string $resource = ProfitCenterSupplierScheduleResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
ForceDeleteAction::make(),
RestoreAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\ProfitCenterSupplierSchedules\Pages;
use App\Filament\Resources\ProfitCenterSupplierSchedules\ProfitCenterSupplierScheduleResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListProfitCenterSupplierSchedules extends ListRecords
{
protected static string $resource = ProfitCenterSupplierScheduleResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@ -0,0 +1,68 @@
<?php
namespace App\Filament\Resources\ProfitCenterSupplierSchedules;
use App\Filament\Resources\ProfitCenterSupplierSchedules\Pages\CreateProfitCenterSupplierSchedule;
use App\Filament\Resources\ProfitCenterSupplierSchedules\Pages\EditProfitCenterSupplierSchedule;
use App\Filament\Resources\ProfitCenterSupplierSchedules\Pages\ListProfitCenterSupplierSchedules;
use App\Filament\Resources\ProfitCenterSupplierSchedules\Schemas\ProfitCenterSupplierScheduleForm;
use App\Filament\Resources\ProfitCenterSupplierSchedules\Tables\ProfitCenterSupplierSchedulesTable;
use App\Models\ProfitCenterSupplierSchedule;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class ProfitCenterSupplierScheduleResource extends Resource
{
protected static ?string $model = ProfitCenterSupplierSchedule::class;
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-link';
protected static string|\UnitEnum|null $navigationGroup = 'Szállítási naptár';
protected static ?string $navigationLabel = 'Beszállítói menetrendek';
protected static ?string $modelLabel = 'Beszállítói menetrend';
protected static ?string $pluralLabel = 'Beszállítói menetrendek';
protected static ?string $breadcrumb = 'Beszállítói menetrendek';
public static function form(Schema $schema): Schema
{
return ProfitCenterSupplierScheduleForm::configure($schema);
}
public static function table(Table $table): Table
{
return ProfitCenterSupplierSchedulesTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListProfitCenterSupplierSchedules::route('/'),
'create' => CreateProfitCenterSupplierSchedule::route('/create'),
'edit' => EditProfitCenterSupplierSchedule::route('/{record}/edit'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@ -0,0 +1,31 @@
<?php
namespace App\Filament\Resources\ProfitCenterSupplierSchedules\Schemas;
use Filament\Forms\Components\Select;
use Filament\Schemas\Schema;
class ProfitCenterSupplierScheduleForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
Select::make('profit_center_id')
->label('Profit Center')
->relationship('profitCenter', 'name')
->searchable()
->required(),
Select::make('supplier_id')
->label('Beszállító')
->relationship('supplier', 'name')
->searchable()
->required(),
Select::make('delivery_schedule_id')
->label('Szállítási sablon')
->relationship('deliverySchedule', 'name')
->searchable()
->required(),
]);
}
}

View File

@ -0,0 +1,46 @@
<?php
namespace App\Filament\Resources\ProfitCenterSupplierSchedules\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
class ProfitCenterSupplierSchedulesTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
\Filament\Tables\Columns\TextColumn::make('profitCenter.name')
->label('Profit Center')
->searchable()
->sortable(),
\Filament\Tables\Columns\TextColumn::make('supplier.name')
->label('Beszállító')
->searchable()
->sortable(),
\Filament\Tables\Columns\TextColumn::make('deliverySchedule.name')
->label('Szállítási sablon')
->searchable()
->sortable(),
])
->filters([
TrashedFilter::make(),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
ForceDeleteBulkAction::make(),
RestoreBulkAction::make(),
]),
]);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Filament\Resources\WorkCalendars\Pages;
use App\Filament\Resources\WorkCalendars\WorkCalendarResource;
use Filament\Resources\Pages\CreateRecord;
class CreateWorkCalendar extends CreateRecord
{
protected static string $resource = WorkCalendarResource::class;
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Filament\Resources\WorkCalendars\Pages;
use App\Filament\Resources\WorkCalendars\WorkCalendarResource;
use Filament\Actions\DeleteAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\RestoreAction;
use Filament\Resources\Pages\EditRecord;
class EditWorkCalendar extends EditRecord
{
protected static string $resource = WorkCalendarResource::class;
protected function getHeaderActions(): array
{
return [
DeleteAction::make(),
ForceDeleteAction::make(),
RestoreAction::make(),
];
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Filament\Resources\WorkCalendars\Pages;
use App\Filament\Resources\WorkCalendars\WorkCalendarResource;
use Filament\Actions\CreateAction;
use Filament\Resources\Pages\ListRecords;
class ListWorkCalendars extends ListRecords
{
protected static string $resource = WorkCalendarResource::class;
protected function getHeaderActions(): array
{
return [
CreateAction::make(),
];
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace App\Filament\Resources\WorkCalendars\Schemas;
use Filament\Schemas\Schema;
class WorkCalendarForm
{
public static function configure(Schema $schema): Schema
{
return $schema
->components([
//
]);
}
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Filament\Resources\WorkCalendars\Tables;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\EditAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
class WorkCalendarsTable
{
public static function configure(Table $table): Table
{
return $table
->columns([
//
])
->filters([
TrashedFilter::make(),
])
->recordActions([
EditAction::make(),
])
->toolbarActions([
BulkActionGroup::make([
DeleteBulkAction::make(),
ForceDeleteBulkAction::make(),
RestoreBulkAction::make(),
]),
]);
}
}

View File

@ -0,0 +1,58 @@
<?php
namespace App\Filament\Resources\WorkCalendars;
use App\Filament\Resources\WorkCalendars\Pages\CreateWorkCalendar;
use App\Filament\Resources\WorkCalendars\Pages\EditWorkCalendar;
use App\Filament\Resources\WorkCalendars\Pages\ListWorkCalendars;
use App\Filament\Resources\WorkCalendars\Schemas\WorkCalendarForm;
use App\Filament\Resources\WorkCalendars\Tables\WorkCalendarsTable;
use App\Models\WorkCalendar;
use BackedEnum;
use Filament\Resources\Resource;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;
class WorkCalendarResource extends Resource
{
protected static ?string $model = WorkCalendar::class;
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedRectangleStack;
public static function form(Schema $schema): Schema
{
return WorkCalendarForm::configure($schema);
}
public static function table(Table $table): Table
{
return WorkCalendarsTable::configure($table);
}
public static function getRelations(): array
{
return [
//
];
}
public static function getPages(): array
{
return [
'index' => ListWorkCalendars::route('/'),
'create' => CreateWorkCalendar::route('/create'),
'edit' => EditWorkCalendar::route('/{record}/edit'),
];
}
public static function getRecordRouteBindingEloquentQuery(): Builder
{
return parent::getRecordRouteBindingEloquentQuery()
->withoutGlobalScopes([
SoftDeletingScope::class,
]);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class DeliveryCalendarOverride extends BaseAuditable
{
use SoftDeletes;
protected $guarded = ['id', 'created_at', 'updated_at'];
protected $casts = [
'date' => 'date',
'is_delivery_day' => 'boolean',
];
public function supplier(): BelongsTo
{
return $this->belongsTo(Supplier::class);
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\SoftDeletes;
class DeliverySchedule extends BaseAuditable
{
use SoftDeletes;
protected $guarded = ['id', 'created_at', 'updated_at'];
protected $casts = [
'monday' => 'boolean',
'tuesday' => 'boolean',
'wednesday' => 'boolean',
'thursday' => 'boolean',
'friday' => 'boolean',
'saturday' => 'boolean',
'sunday' => 'boolean',
'is_active' => 'boolean',
];
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
class ProfitCenterSupplierSchedule extends BaseAuditable
{
use SoftDeletes;
protected $guarded = ['id', 'created_at', 'updated_at'];
public function profitCenter(): BelongsTo
{
return $this->belongsTo(ProfitCenter::class);
}
public function supplier(): BelongsTo
{
return $this->belongsTo(Supplier::class);
}
public function deliverySchedule(): BelongsTo
{
return $this->belongsTo(DeliverySchedule::class);
}
}

View File

@ -0,0 +1,76 @@
<?php
namespace App\Services;
use App\Models\DeliveryCalendarOverride;
use App\Models\ProfitCenter;
use App\Models\ProfitCenterSupplierSchedule;
use App\Models\Supplier;
use Carbon\Carbon;
use Illuminate\Support\Collection;
class DeliveryCalendarService extends ServiceBase
{
public function __construct(
protected WorkCalendarService $workCalendarService
) {
}
/**
* Eldönti, hogy egy adott Profit Center, Beszállító és Dátum kombináció esetén van-e szállítá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)
$override = DeliveryCalendarOverride::where('supplier_id', $supplier->id)
->whereDate('date', $date)
->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)
$assignment = ProfitCenterSupplierSchedule::where('profit_center_id', $pc->id)
->where('supplier_id', $supplier->id)
->with('deliverySchedule')
->first();
if (! $assignment || ! $assignment->deliverySchedule || ! $assignment->deliverySchedule->is_active) {
return false;
}
$dayOfWeek = strtolower($date->format('l')); // 'monday', 'tuesday', etc.
return (bool) $assignment->deliverySchedule->{$dayOfWeek};
}
/**
* Visszaadja az elérhető szállítási napokat egy adott időszakban.
*
* @return Collection<Carbon>
*/
public function getAvailableDeliveryDates(ProfitCenter $pc, Supplier $supplier, Carbon $start, Carbon $end): Collection
{
$dates = collect();
$current = $start->copy()->startOfDay();
$end = $end->copy()->startOfDay();
while ($current <= $end) {
if ($this->isDeliveryDay($pc, $supplier, $current)) {
$dates->push($current->copy());
}
$current->addDay();
}
return $dates;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace Database\Factories;
use App\Models\DeliveryCalendarOverride;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<DeliveryCalendarOverride>
*/
class DeliveryCalendarOverrideFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'supplier_id' => \App\Models\Supplier::factory(),
'date' => $this->faker->date(),
'is_delivery_day' => $this->faker->boolean(),
'description' => $this->faker->sentence(),
];
}
}

View File

@ -0,0 +1,32 @@
<?php
namespace Database\Factories;
use App\Models\DeliverySchedule;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<DeliverySchedule>
*/
class DeliveryScheduleFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => $this->faker->word(),
'monday' => false,
'tuesday' => false,
'wednesday' => false,
'thursday' => false,
'friday' => false,
'saturday' => false,
'sunday' => false,
'is_active' => true,
];
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace Database\Factories;
use App\Models\ProfitCenter;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<ProfitCenter>
*/
class ProfitCenterFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'name' => fake()->name(),
'hooreycaId' => fake()->uuid(),
'postCode' => '1234',
'city' => fake()->city(),
'street' => fake()->streetAddress(),
'note' => fake()->sentence(),
];
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace Database\Factories;
use App\Models\ProfitCenterSupplierSchedule;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<ProfitCenterSupplierSchedule>
*/
class ProfitCenterSupplierScheduleFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition(): array
{
return [
'profit_center_id' => \App\Models\ProfitCenter::factory(),
'supplier_id' => \App\Models\Supplier::factory(),
'delivery_schedule_id' => \App\Models\DeliverySchedule::factory(),
];
}
}

View File

@ -12,7 +12,13 @@ class SupplierFactory extends Factory
public function definition(): array public function definition(): array
{ {
return [ return [
// 'name' => fake()->company(),
'hooreycaId' => fake()->uuid(),
'nameId' => fake()->word(),
'orderEmail' => fake()->safeEmail(),
'address' => fake()->address(),
'phone' => fake()->phoneNumber(),
'note' => fake()->sentence(),
]; ];
} }
} }

View File

@ -0,0 +1,38 @@
<?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::create('delivery_schedules', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->boolean('monday')->default(false);
$table->boolean('tuesday')->default(false);
$table->boolean('wednesday')->default(false);
$table->boolean('thursday')->default(false);
$table->boolean('friday')->default(false);
$table->boolean('saturday')->default(false);
$table->boolean('sunday')->default(false);
$table->boolean('is_active')->default(true);
$table->userIdFields();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('delivery_schedules');
}
};

View File

@ -0,0 +1,32 @@
<?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::create('profit_center_supplier_schedules', function (Blueprint $table) {
$table->id();
$table->foreignId('profit_center_id')->constrained()->onDelete('cascade');
$table->foreignId('supplier_id')->constrained()->onDelete('cascade');
$table->foreignId('delivery_schedule_id')->constrained()->onDelete('cascade');
$table->userIdFields();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('profit_center_supplier_schedules');
}
};

View File

@ -0,0 +1,33 @@
<?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::create('delivery_calendar_overrides', function (Blueprint $table) {
$table->id();
$table->foreignId('supplier_id')->constrained()->onDelete('cascade');
$table->date('date');
$table->boolean('is_delivery_day');
$table->string('description')->nullable();
$table->userIdFields();
$table->timestamps();
$table->softDeletes();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('delivery_calendar_overrides');
}
};

View File

@ -0,0 +1,166 @@
<?php
use App\Models\DeliveryCalendarOverride;
use App\Models\DeliverySchedule;
use App\Models\ProfitCenter;
use App\Models\ProfitCenterSupplierSchedule;
use App\Models\Supplier;
use App\Models\WorkCalendar;
use App\Enums\WorkDayType;
use App\Enums\DataSource;
use App\Services\DeliveryCalendarService;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
uses(TestCase::class, RefreshDatabase::class);
it('returns true for a scheduled delivery 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,
]);
$service = app(DeliveryCalendarService::class);
$monday = Carbon::parse('2026-04-13'); // Monday
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeTrue();
});
it('returns false for a non-scheduled delivery day', function () {
$pc = ProfitCenter::factory()->create();
$supplier = Supplier::factory()->create();
$schedule = DeliverySchedule::factory()->create([
'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();
});
it('respects official holidays (WorkCalendar)', 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,
]);
$service = app(DeliveryCalendarService::class);
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeFalse();
});
it('respects supplier overrides 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,
'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 () {
$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,
'date' => '2026-04-13',
'is_delivery_day' => false,
]);
$service = app(DeliveryCalendarService::class);
expect($service->isDeliveryDay($pc, $supplier, $monday))->toBeFalse();
});
it('calculates available delivery dates in a range', function () {
$pc = ProfitCenter::factory()->create();
$supplier = Supplier::factory()->create();
$schedule = DeliverySchedule::factory()->create([
'monday' => true,
'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());
expect($dateStrings)->toContain('2026-04-13');
expect($dateStrings)->toContain('2026-04-15');
expect($dateStrings)->toContain('2026-04-17');
});