EV3-357 Árlista feltöltés és feldolgzás újra gondolása phase4 fejléc adatok akciós lehetőség bővítése

This commit is contained in:
E98Developer 2026-08-03 12:09:41 +02:00
parent e49b7515e0
commit a30aa2dd51
4 changed files with 79 additions and 4 deletions

View File

@ -106,6 +106,7 @@ public function getExcelFieldPointer(): array
19 => 'Vevői megnevezés',
20 => 'Megjegyzés',
21 => 'KREL',
22 => 'Akció',
];
private array $excelFieldPointer = [
@ -131,6 +132,7 @@ public function getExcelFieldPointer(): array
'buyerProductName' => 19,
'note' => 20,
'krel' => 21,
'specialOffer' => 22,
];
@ -157,6 +159,7 @@ public function getExcelFieldPointer(): array
'buyerProductName' => ['string'], // 19
'note' => ['string'], // 20
'krel' => ['string'], // 21
'specialOffer' => ['string'], // 22
];
private array $excelFieldConverter = [
@ -165,6 +168,7 @@ public function getExcelFieldPointer(): array
'vat' => ['percentage'],
'note' => ['null'],
'krel' => ['booleanCustom'],
'specialOffer' => ['booleanCustom'],
'hooreycaId' => ['null'],
'HooreycaUnit' => ['null'],
'HooreycaMultiplier' => ['null'],

View File

@ -187,6 +187,15 @@ public function updateStepStatus(
private const HEADER_ROW = 3;
private const DATA_START_ROW = 5;
/**
* Opcionális (visszafelé kompatibilis) oszlopfejlécek indexei.
* Ha egy ilyen oszlop hiányzik a 3. sorból, az nem blokkoló hiba, csak figyelmeztetés,
* és a hozzá tartozó feldolgozás (pl. akciós jelölés) kimarad.
*/
private const OPTIONAL_HEADER_INDEXES = [
22, // Akció (specialOffer)
];
/**
* Előfeldolgozás (Pre-processing) - Strukturális és technikai ellenőrzés
*
@ -384,6 +393,12 @@ private function buildColumnMap(Worksheet $worksheet): array
if (isset($headerByName[$normalizedExpected])) {
$map[$index] = $headerByName[$normalizedExpected];
$usedColumns[$headerByName[$normalizedExpected]] = true;
} elseif (in_array($index, self::OPTIONAL_HEADER_INDEXES, true)) {
// Opcionális oszlop hiánya nem blokkoló, csak figyelmeztetés (visszafelé kompatibilitás)
$warnings[] = $this->buildWarning(
PreProcessErrorCode::COLUMN_MISSING,
"Hiányzó opcionális oszlopfejléc: '{$expectedLabel}' (a " . self::HEADER_ROW . ". sorban nem található); a feldolgozás e nélkül folytatódik."
);
} else {
// Hiányzó kötelező fejléc: blokkoló hiba
$errors[] = $this->buildError(
@ -626,7 +641,9 @@ public function validate(PricelistFile $pricelistFile): bool
PricelistFileLine::insert($dataToInsert);
}
$this->runBusinessValidation($pricelistFile);
// Az "Akció" (specialOffer) opcionális oszlop: csak akkor kezeljük, ha ténylegesen szerepel a fájlban
$hasSpecialOfferColumn = isset($columnMap[22]);
$this->runBusinessValidation($pricelistFile, $hasSpecialOfferColumn);
$duration = round(microtime(true) - $startTime, 2);
@ -897,7 +914,7 @@ protected function validateProducer(array $payload, array $producerLookup): ?str
*
* @param PricelistFile $pricelistFile
*/
protected function runBusinessValidation(PricelistFile $pricelistFile): void
protected function runBusinessValidation(PricelistFile $pricelistFile, bool $hasSpecialOfferColumn = false): void
{
$this->updateStepStatus($pricelistFile, PricelistWorkflowStep::Validation, 'inprogress', 'Üzleti validálás...', 100);
@ -908,7 +925,7 @@ protected function runBusinessValidation(PricelistFile $pricelistFile): void
$producerIdToName = $this->getProducerIdMap();
$groupIdToPath = $this->getProductGroupIdMap();
$pricelistFile->lines()->chunk(1000, function ($lines) use ($groupLookup, $producerLookup, $productLookup, $producerIdToName, $groupIdToPath) {
$pricelistFile->lines()->chunk(1000, function ($lines) use ($groupLookup, $producerLookup, $productLookup, $producerIdToName, $groupIdToPath, $hasSpecialOfferColumn) {
$updates = [];
foreach ($lines as $line) {
@ -1116,6 +1133,25 @@ protected function runBusinessValidation(PricelistFile $pricelistFile): void
];
}
}
// 5. Akciós (specialOffer) módosulás - csak ha az "Akció" oszlop szerepel a fájlban.
// booleanCustom logika: üres érték => false, bármilyen más érték => true.
if ($hasSpecialOfferColumn) {
$specialOfferRaw = $payload[PriceListService::EXPECTED_HEADERS[22]] ?? null;
$newSpecialOffer = strlen(trim((string)$specialOfferRaw)) > 0;
$oldSpecialOffer = (bool)($existingProduct['specialOffer'] ?? false);
if ($newSpecialOffer !== $oldSpecialOffer) {
$isUpdated = true;
$diff['specialOffer'] = [
'old' => (int)$oldSpecialOffer,
'new' => (int)$newSpecialOffer,
'old_label' => $oldSpecialOffer ? 'Akciós' : 'Nem akciós',
'new_label' => $newSpecialOffer ? 'Akciós' : 'Nem akciós',
'label' => PriceListService::EXPECTED_HEADERS[22],
];
}
}
}
$updates[] = [

View File

@ -121,7 +121,7 @@
'icon' => 'price_list',
'link' => '/admin/pricelist-files',
'noAjax' => true,
'roles' => ['developer'],
'roles' => ['developer','admin'],
],
'delivery' => [
'name' => 'delivery',

View File

@ -81,6 +81,41 @@ function makeWorksheetWithHeaderOrder(array $order): Worksheet
expect($result['map'])->toHaveCount(count($expected));
});
test('a hiányzó opcionális "Akció" oszlop csak figyelmeztetést ad, nem blokkol', function () {
$expected = PriceListService::EXPECTED_HEADERS;
$worksheet = (new Spreadsheet())->getActiveSheet();
$col = 1;
foreach ($expected as $fieldIndex => $label) {
if ($fieldIndex === 22) {
// Az "Akció" oszlopot szándékosan kihagyjuk (visszafelé kompatibilis fájl)
continue;
}
$worksheet->setCellValueByColumnAndRow($col, 3, $label);
$col++;
}
$result = invokeBuildColumnMap($worksheet);
$hasBlocker = collect($result['errors'])->contains(fn ($error) => ($error['severity'] ?? '') === 'blocker');
expect($hasBlocker)->toBeFalse();
expect($result['map'])->not->toHaveKey(22);
expect(collect($result['warnings']))->not->toBeEmpty();
});
test('a jelen lévő "Akció" oszlop leképeződik', function () {
$expected = PriceListService::EXPECTED_HEADERS;
$worksheet = makeWorksheetWithHeaderOrder(array_keys($expected));
$result = invokeBuildColumnMap($worksheet);
expect($result['errors'])->toBe([]);
expect($result['map'])->toHaveKey(22);
$value = $worksheet->getCellByColumnAndRow($result['map'][22], 5)->getValue();
expect($value)->toBe('VAL_22');
});
test('hiányzó kötelező fejléc blokkoló hibát ad', function () {
$expected = PriceListService::EXPECTED_HEADERS;