Egy beszállítóhoz egyszerre legfeljebb egy nyitott végrehajtás tartozhat: egy execution_failed fájl után a termékek félig frissített állapotban vannak, egy új import erre a kevert alapra rétegződne rá (és a validálás is ehhez számolná a diffeket); két párhuzamos végrehajtás pedig nem determinisztikus eredményt adna. - új PricelistGuard service: egyetlen igazságforrás a blokkoláshoz - mind a NÉGY belépési pont véd: modern Filament create, régebbi PriceListProcessor oldal, legacy Admin\PriceListController import, konzol parancs. A legacy import a legfontosabb - az közvetlenül ír a products táblába, megkerülve a modult, és a beszállítókat ma még nagyrészt ott kezelik. - az `inprogress` önmagában nem blokkol: az előfeldolgozás és a validálás egyetlen terméket sem ír, csak a már elindult végrehajtás számít - a beszállító nem tűnik el a select listából, hanem konkrét magyarázatot kap a felhasználó arról, melyik fájl blokkol és miért - blokkolt beszállítónál másik fájl jóváhagyása sem indítható Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
118 lines
3.9 KiB
PHP
118 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Pages;
|
|
|
|
use Filament\Pages\Page;
|
|
use Filament\Forms\Components\Select;
|
|
use Filament\Forms\Components\DatePicker;
|
|
use Filament\Forms\Components\Textarea;
|
|
use Filament\Forms\Components\FileUpload;
|
|
use Filament\Schemas\Schema;
|
|
use Filament\Forms\Contracts\HasForms;
|
|
use Filament\Forms\Concerns\InteractsWithForms;
|
|
use App\Models\Supplier;
|
|
use App\Models\PricelistFile;
|
|
use App\Filament\Resources\PricelistFiles\PricelistFileResource;
|
|
use App\Jobs\PricelistPreProcessJob;
|
|
use Filament\Notifications\Notification;
|
|
use Filament\Actions\Action;
|
|
|
|
use Illuminate\Contracts\Support\Htmlable;
|
|
|
|
class PriceListProcessor extends Page implements HasForms
|
|
{
|
|
use InteractsWithForms;
|
|
|
|
protected static string | \BackedEnum | null $navigationIcon = 'heroicon-o-document-text';
|
|
|
|
protected string $view = 'filament.pages.price-list-processor';
|
|
|
|
protected static ?string $title = 'Árlista feldolgozó';
|
|
|
|
protected static ?string $navigationLabel = 'Árlista feldolgozó';
|
|
|
|
protected static bool $shouldRegisterNavigation = false;
|
|
|
|
public ?array $data = [];
|
|
|
|
public function mount(): void
|
|
{
|
|
$this->form->fill();
|
|
}
|
|
|
|
public function form(Schema $form): Schema
|
|
{
|
|
return $form
|
|
->schema([
|
|
Select::make('supplier_id')
|
|
->label('Beszállító')
|
|
->options(Supplier::query()->pluck('name', 'id'))
|
|
->required()
|
|
->searchable(),
|
|
DatePicker::make('available_date')
|
|
->label('Életbelépés dátuma')
|
|
->required()
|
|
->native(false)
|
|
->displayFormat('Y.m.d'),
|
|
Textarea::make('note')
|
|
->label('Megjegyzés')
|
|
->rows(3),
|
|
FileUpload::make('filename')
|
|
->label('Fájl kiválasztása')
|
|
->required()
|
|
->acceptedFileTypes(['application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'text/csv'])
|
|
->disk('public')
|
|
->directory('pricelist-uploads')
|
|
->preserveFilenames(),
|
|
])
|
|
->statePath('data');
|
|
}
|
|
|
|
protected function getFormActions(): array
|
|
{
|
|
return [
|
|
Action::make('save')
|
|
->label('Feltöltés és feldolgozás indítása')
|
|
->submit('save')
|
|
->color('primary'),
|
|
];
|
|
}
|
|
|
|
public function save()
|
|
{
|
|
$data = $this->form->getState();
|
|
|
|
// Ugyanaz a védelem, mint a modern felületen: enélkül ez az oldal megkerülné a
|
|
// beszállítói blokkolást, hiszen ugyanúgy PricelistFile-t hoz létre és láncot indít.
|
|
if ($blockingFile = app(\App\Services\PricelistGuard::class)->blockingFileFor($data['supplier_id'] ?? null)) {
|
|
Notification::make()
|
|
->title('A beszállítóhoz jelenleg nem vihető fel árlista')
|
|
->body(app(\App\Services\PricelistGuard::class)->blockingMessage($blockingFile))
|
|
->danger()
|
|
->persistent()
|
|
->send();
|
|
|
|
return;
|
|
}
|
|
|
|
$pricelistFile = PricelistFile::create([
|
|
'filename' => $data['filename'],
|
|
'supplier_id' => $data['supplier_id'],
|
|
'available_date' => $data['available_date'],
|
|
'note' => $data['note'],
|
|
]);
|
|
|
|
app(\App\Services\PricelistFileProcessService::class)->dispatchInitialChain($pricelistFile);
|
|
|
|
Notification::make()
|
|
->title('Sikeres feltöltés')
|
|
->body('Az árlista fájl rögzítve lett és a feldolgozás elindult.')
|
|
->success()
|
|
->send();
|
|
|
|
$this->form->fill();
|
|
|
|
return redirect()->to(PricelistFileResource::getUrl('view', ['record' => $pricelistFile]));
|
|
}
|
|
}
|