- PricelistExecutionJob + új PricelistRevertJob: $tries=1, $timeout, failed() hook. A service catch ága csak PHP exceptiont fog el; worker timeout vagy memórialimit esetén a fájl inprogress-ben ragadna, döntési gomb nélkül. - heartbeat backstop a kill -9 esetére, ahol a failed() sem fut: minden chunk ír a rekordba, így az updated_at a szívverés (isExecutionStuck). Ezzel garantált, hogy minden kísérlet véges időn belül terminális állapotba jut - enélkül a kényszerlezárás sem nyílna ki soha. - kompenzáló visszaállítás R1-R4: árak törlése, termékek visszaállítása a snapshotból, létrehozott termékek kivonása (soft delete, NEM fizikai törlés, mert lehet rájuk hivatkozás), árlista + fájl lezárása - konfliktuskezelés: a végrehajtás óta kézzel módosított terméket kihagyjuk és jelentjük, nem írjuk felül vakon - FIX phase5/3: a snapshot csak az írás ELŐTTI updated_at-et tárolta, amihez képest a termék a végrehajtás után mindig eltér - a konfliktus-ellenőrzés így minden sort kihagyott volna. Most a saját írásunk utáni updated_at is bekerül. - kényszerlezárás: csak legalább egy terminális hibába futott visszaállítási kísérlet után, flag + developer szerepkör mögött, kötelező indoklással - döntéstámogató panel: mi történt már meg az importból, hogy a felhasználó ne vakon válasszon a Folytatás és a Visszavonás között Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
79 lines
2.2 KiB
PHP
79 lines
2.2 KiB
PHP
<?php
|
|
|
|
namespace App\Enums;
|
|
|
|
use App\Jobs\PricelistPreProcessJob;
|
|
use App\Jobs\PricelistValidationJob;
|
|
use App\Jobs\PricelistExecutionJob;
|
|
|
|
enum PricelistWorkflowStep: string
|
|
{
|
|
case Preprocessing = 'preprocess';
|
|
case Validation = 'validation';
|
|
case Approval = 'approval';
|
|
case Execution = 'execution';
|
|
|
|
/**
|
|
* Magyar megnevezés (UI megjelenítéshez)
|
|
*/
|
|
public function label(): string
|
|
{
|
|
return match($this) {
|
|
self::Preprocessing => 'Előfeldolgozás',
|
|
self::Validation => 'Validálás',
|
|
self::Approval => 'Jóváhagyás',
|
|
self::Execution => 'Végrehajtás',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* A lépéshez tartozó Job osztály neve
|
|
*/
|
|
public function jobClass(): ?string
|
|
{
|
|
return match($this) {
|
|
self::Preprocessing => PricelistPreProcessJob::class,
|
|
self::Validation => PricelistValidationJob::class,
|
|
self::Execution => PricelistExecutionJob::class,
|
|
self::Approval => null, // Manuális lépésnél nincs automatikus job
|
|
};
|
|
}
|
|
|
|
/**
|
|
* A lépéshez tartozó Job példány visszaadása
|
|
*/
|
|
public function getJob(\App\Models\PricelistFile $file): ?object
|
|
{
|
|
$jobClass = $this->jobClass();
|
|
return $jobClass ? new $jobClass($file) : null;
|
|
}
|
|
|
|
/**
|
|
* Státusz színek (UI megjelenítéshez)
|
|
*/
|
|
public function color(string $status): string
|
|
{
|
|
return match ($status) {
|
|
'pending' => 'gray',
|
|
'inprogress' => 'primary',
|
|
'completed' => 'success',
|
|
'failed' => 'danger',
|
|
'rejected' => 'warning', // manuális elutasítás - nem hiba, hanem szabályos lezárás
|
|
'reverted' => 'warning', // a végrehajtás kompenzáló visszaállítással visszavonva
|
|
default => 'gray',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Segédfüggvény az alapértelmezett workflow struktúra legenerálásához
|
|
*/
|
|
public static function defaultSteps(): array
|
|
{
|
|
return array_map(fn($step) => [
|
|
'name' => $step->value,
|
|
'label' => $step->label(),
|
|
'status' => 'pending',
|
|
], self::cases());
|
|
}
|
|
}
|