conn = $conn;
$this->primaryWarehouse = self::PRIMARY_WAREHOUSE_CODE;
$this->warehouseConfig = $this->loadWarehouseStructure();
}
/**
* Fő generáló metódus
*/
public static function generate($conn, $inputData, $coderclass = null) {
$generator = new self($conn);
return $generator->processPickingList($inputData, $coderclass);
}
/**
* Picking list feldolgozás
*/
private function processPickingList($inputData, $coderclass) {
$orders = [];
$reason = '';
$orderDate = '';
// Input típus meghatározása
if (isset($inputData['manual']) && is_array($inputData['manual'])) {
$orders = $this->buildManualOrders($inputData['manual']);
} else {
if ($coderclass === null) {
return ['result' => 'error', 'message' => 'CoderClass szükséges reason alapú lekérdezéshez'];
}
$encodedData = htmlspecialchars($inputData['reason'] ?? '');
$decodedData = $coderclass->decode($encodedData, 'SZ4TUN4');
$dataParts = explode('|', $decodedData);
if (count($dataParts) != 2) {
return ['result' => 'error', 'message' => 'Érvénytelen kiszedési lista azonosító'];
}
$reason = $dataParts[0];
$orderDate = $dataParts[1];
$orders = $this->loadOrders($reason, $orderDate);
}
// Készletek betöltése
$boxStock = $this->loadBoxStock();
$foilStock = $this->loadFoilStock();
// Picking listák generálása
$allPickingLists = [];
foreach ($orders as $key => $orderData) {
$localBoxStock = $boxStock;
$localFoilStock = $foilStock;
$orderPrimaryWarehouse = $orderData['primary_warehouse'] ?? $this->primaryWarehouse;
$this->prioritizeStock($localBoxStock, $orderPrimaryWarehouse);
$this->prioritizeFoilStock($localFoilStock, $orderPrimaryWarehouse);
$pickingList = $this->generatePickingList($orderData, $localBoxStock, $localFoilStock);
$this->formatPositionForSort($pickingList);
$this->sortPickingList($pickingList);
$icon = $this->determineIcon($pickingList);
if (!empty($icon)) {
$icon = $orderData['overal_order_id'] . ' ' . $icon;
}
$allPickingLists[] = [
'overal_order_id' => $orderData['overal_order_id'],
'order_id' => $orderData['order_id'],
'order_name' => $orderData['order_name'],
'order_mail' => $orderData['order_mail'],
'receipt_method' => $orderData['receipt_method'],
'order_note' => $orderData['order_note'],
'picking_list' => $pickingList
];
}
$this->sortOrders($allPickingLists);
return [
'result' => 'ok',
'reason' => $reason,
'date' => $orderDate,
'all_picking_lists' => $allPickingLists
];
}
// ========================================================================
// ADATBETÖLTŐ METÓDUSOK
// ========================================================================
private function loadWarehouseStructure() {
$config = [];
$sql = "SELECT warehouse_id, location, name, code FROM warehouse_structure WHERE status=1";
$result = $this->conn->query($sql);
if ($result) {
while ($row = $result->fetch_assoc()) {
$config[intval($row['warehouse_id'])] = [
'location' => $row['location'],
'name' => $row['name'],
'code' => $row['code']
];
}
}
return $config;
}
private function buildManualOrders($manualData) {
$manualItems = [];
foreach ($manualData as $entry) {
$itemId = $entry['item_id'] ?? '';
$amount = intval($entry['amount'] ?? 0);
$primarySource = intval($entry['primary_source'] ?? 0);
$amountType = intval($entry['amount_type'] ?? 0);
if (empty($itemId) || $amount <= 0) continue;
$key = $itemId . '_' . $primarySource . '_' . $amountType;
if (!isset($manualItems[$key])) {
$manualItems[$key] = [
'item_id' => $itemId,
'amount' => 0,
'primary_source' => $primarySource,
'amount_type' => $amountType
];
}
$manualItems[$key]['amount'] += $amount;
}
$orders = [];
$orders['manual'] = [
'overal_order_id' => 'Manuális kiszedés',
'order_id' => '',
'order_name' => 'Manuális kiszedés',
'order_mail' => '',
'receipt_method' => '',
'order_note' => '',
'items' => [],
'totalneed' => 0,
'primary_warehouse' => $this->primaryWarehouse
];
foreach ($manualItems as $item) {
$orders['manual']['items'][] = [
'item_id' => $item['item_id'],
'need' => $item['amount'],
'taken_out' => 0,
'ordered' => $item['amount'],
'amount_type' => $item['amount_type'],
'primary_source' => $item['primary_source']
];
$orders['manual']['totalneed'] += $item['amount'];
}
return $orders;
}
private function loadOrders($reason, $orderDate) {
$orders = [];
$sql = "SELECT
item_id,
SUM(amount) AS ordered,
SUM(taken_out) AS taken_out,
SUM(amount) - SUM(taken_out) AS need,
IFNULL(order_id, '') AS order_id,
IFNULL(order_name, '') AS order_name,
IFNULL(order_mail, '') AS order_mail,
MAX(reason) AS reason,
primary_source,
primary_warehouse,
MAX(amount_type) AS amount_type,
GROUP_CONCAT(DISTINCT IFNULL(note, '') SEPARATOR ' ') AS note,
GROUP_CONCAT(DISTINCT IFNULL(receipt_method, '') SEPARATOR ' ') AS receipt_method
FROM warehouse_reservation
WHERE reason = ?
AND DATE(FROM_UNIXTIME(date_create)) = ?
AND is_active = 1
GROUP BY item_id, order_id, order_name, order_mail, primary_source, amount_type, primary_warehouse
ORDER BY amount_type DESC, item_id";
$stmt = $this->conn->prepare($sql);
$stmt->bind_param("ss", $reason, $orderDate);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
$hasOrder = !empty($row['order_id']) || !empty($row['order_name']) || !empty($row['order_mail']);
if ($hasOrder) {
$key = $row['order_id'] . '~' . $row['order_name'] . '~' . $row['order_mail'];
$label = $row['order_name'] . ' - (' . $row['order_id'] . ')';
} else {
$key = 'maradek';
$label = '!&maradek&! ';
}
if (!isset($orders[$key])) {
$orders[$key] = [
'overal_order_id' => $label,
'order_id' => strval($row['order_id']),
'order_name' => $row['order_name'],
'order_mail' => $row['order_mail'],
'receipt_method' => '',
'order_note' => '',
'items' => [],
'totalneed' => 0,
'primary_warehouse' => $row['primary_warehouse'] ?? $this->primaryWarehouse
];
}
if (!empty($row['receipt_method'])) {
if (empty($orders[$key]['receipt_method']) || strpos($orders[$key]['receipt_method'], $row['receipt_method']) === false) {
$orders[$key]['receipt_method'] = trim($orders[$key]['receipt_method'] . ' ' . $row['receipt_method']);
}
}
if (!empty($row['note'])) {
if (empty($orders[$key]['order_note']) || strpos($orders[$key]['order_note'], $row['note']) === false) {
$orders[$key]['order_note'] = trim($orders[$key]['order_note'] . ' ' . $row['note']);
}
}
$need = intval($row['need']);
$orders[$key]['items'][] = [
'item_id' => $row['item_id'],
'need' => $need,
'taken_out' => intval($row['taken_out']),
'ordered' => intval($row['ordered']),
'amount_type' => intval($row['amount_type']),
'primary_source' => intval($row['primary_source'])
];
$orders[$key]['totalneed'] += max(0, $need);
}
$stmt->close();
return $orders;
}
private function loadBoxStock() {
$stock = [];
$sql = "SELECT item_id, wid, position AS pos, amount, warehouse_id
FROM warehouse
WHERE amount > 0
ORDER BY item_id,
CAST(SUBSTRING_INDEX(position, ':', 1) AS UNSIGNED) DESC,
CAST(SUBSTRING_INDEX(position, ':', -1) AS UNSIGNED) ASC,
amount ASC";
$result = $this->conn->query($sql);
if ($result) {
while ($row = $result->fetch_assoc()) {
$stock[$row['item_id']][] = [
'wid' => intval($row['wid']),
'pos' => $row['pos'],
'amount' => intval($row['amount']),
'warehouse_id' => intval($row['warehouse_id'])
];
}
}
return $stock;
}
private function loadFoilStock() {
$stock = [];
$sql = "SELECT item_id, wid, place AS pos, right_db, left_db
FROM warehouse_foil
WHERE (right_db > 0 OR left_db > 0)
AND is_active = 1
ORDER BY item_id, right_db ASC";
$result = $this->conn->query($sql);
if ($result) {
while ($row = $result->fetch_assoc()) {
$stock[$row['item_id']][] = [
'wid' => 'F' . intval($row['wid']),
'pos' => $row['pos'],
'amount' => min(intval($row['right_db']), intval($row['left_db'])),
'warehouse_id' => 'FOIL',
'right_db' => intval($row['right_db']),
'left_db' => intval($row['left_db'])
];
}
}
return $stock;
}
/**
* Dobozos raktár priorizálása rendelésenként
*/
private function prioritizeStock(&$stock, $primaryWarehouse = null) {
$primary = $primaryWarehouse ?? $this->primaryWarehouse;
foreach ($stock as $itemId => &$bins) {
usort($bins, function($a, $b) use ($primary) {
$aCode = $this->warehouseConfig[$a['warehouse_id']]['code'] ?? '';
$bCode = $this->warehouseConfig[$b['warehouse_id']]['code'] ?? '';
$aIsMain = (strpos($aCode, $primary) === 0) ? 1 : 0;
$bIsMain = (strpos($bCode, $primary) === 0) ? 1 : 0;
if ($aIsMain !== $bIsMain) {
return $bIsMain - $aIsMain;
}
return 0;
});
}
unset($bins);
}
/**
* Fóliás raktár priorizálása rendelésenként
*/
private function prioritizeFoilStock(&$stock, $primaryWarehouse = null) {
$primary = $primaryWarehouse ?? $this->primaryWarehouse;
foreach ($stock as $itemId => &$bins) {
usort($bins, function($a, $b) use ($primary) {
$aIsMain = (strpos($a['pos'], $primary) === 0) ? 1 : 0;
$bIsMain = (strpos($b['pos'], $primary) === 0) ? 1 : 0;
if ($aIsMain !== $bIsMain) {
return $bIsMain - $aIsMain;
}
return 0;
});
}
unset($bins);
}
// ========================================================================
// KISZEDÉSI LOGIKA
// ========================================================================
private function generatePickingList($orderData, $boxStock, $foilStock) {
$pickingList = [];
$localBoxStock = $boxStock;
$localFoilStock = $foilStock;
foreach ($orderData['items'] as $item) {
$itemId = $item['item_id'];
$need = $item['need'];
$takenOut = $item['taken_out'];
$ordered = $item['ordered'];
$amountType = $item['amount_type'];
$primarySource = $item['primary_source'];
if ($takenOut > 0) {
$pickingList[] = [
'wid' => 0,
'item_id' => $itemId,
'pos' => '00',
'code' => '',
'amount' => $takenOut . ' / ' . $ordered,
'amount_type' => $amountType,
'location' => '',
'type' => 'taken'
];
}
if ($need <= 0) continue;
$setInfo = $this->splitSetItemId($itemId);
if ($setInfo === false) {
$picks = $this->pickSimpleItem($itemId, $need, $amountType, $primarySource, $localBoxStock, $localFoilStock);
$pickingList = array_merge($pickingList, $picks);
} else {
if ($this->isCLSet($itemId)) {
$picks = $this->pickCLSet($itemId, $setInfo, $need, $amountType, $localBoxStock);
$pickingList = array_merge($pickingList, $picks);
} else {
$picks = $this->pickNormalSet($itemId, $setInfo, $need, $amountType, $primarySource, $localBoxStock, $localFoilStock);
$pickingList = array_merge($pickingList, $picks);
}
}
if ($need > 0) {
$pickingList[] = [
'wid' => -1,
'item_id' => $itemId,
'pos' => '00',
'code' => '',
'amount' => $need,
'amount_type' => $amountType,
'location' => '',
'type' => 'missing'
];
}
}
return $pickingList;
}
private function pickSimpleItem($itemId, &$need, $amountType, $primarySource, &$boxStock, &$foilStock) {
$picks = [];
$sources = ($primarySource === 1) ? ['foil', 'box'] : ['box', 'foil'];
foreach ($sources as $sourceType) {
if ($need <= 0) break;
if ($amountType !== 0 && $sourceType !== 'foil') {
continue;
}
if ($sourceType === 'box' && isset($boxStock[$itemId])) {
$picks = array_merge($picks, $this->pickFromBoxStock($itemId, $need, $amountType, $boxStock));
}
if ($sourceType === 'foil' && isset($foilStock[$itemId])) {
$picks = array_merge($picks, $this->pickFromFoilStock($itemId, $need, $amountType, $foilStock));
}
}
return $picks;
}
private function pickFromBoxStock($itemId, &$need, $amountType, &$stock) {
$picks = [];
while ($need > 0 && isset($stock[$itemId]) && !empty($stock[$itemId])) {
$bin = &$stock[$itemId][0];
$take = min($bin['amount'], $need);
$picks[] = [
'wid' => $bin['wid'],
'item_id' => $itemId,
'pos' => $this->formatWarehousePosition($bin['pos'], $bin['warehouse_id']),
'code' => $this->warehouseConfig[$bin['warehouse_id']]['code'] ?? '',
'amount' => $take,
'amount_type' => $amountType,
'location' => ($this->warehouseConfig[$bin['warehouse_id']]['location'] ?? '') . ' / ' . ($this->warehouseConfig[$bin['warehouse_id']]['name'] ?? ''),
'type' => 'stock'
];
$bin['amount'] -= $take;
$need -= $take;
if ($bin['amount'] <= 0) {
array_shift($stock[$itemId]);
}
}
return $picks;
}
private function pickFromFoilStock($itemId, &$need, $amountType, &$stock) {
$picks = [];
while ($need > 0 && isset($stock[$itemId]) && !empty($stock[$itemId])) {
$bin = &$stock[$itemId][0];
if ($amountType === 0) {
$take = min($bin['amount'], $need);
} elseif ($amountType === 1) {
$take = min($bin['right_db'], $need);
} elseif ($amountType === 2) {
$take = min($bin['left_db'], $need);
} else {
$take = 0;
}
if ($take <= 0) {
array_shift($stock[$itemId]);
continue;
}
$picks[] = [
'wid' => $bin['wid'],
'item_id' => $itemId,
'pos' => $bin['pos'],
'code' => '',
'amount' => $take,
'amount_type' => $amountType,
'location' => self::FOIL_WAREHOUSE_LABEL,
'type' => 'foil'
];
if ($amountType === 0) {
$bin['right_db'] -= $take;
$bin['left_db'] -= $take;
} elseif ($amountType === 1) {
$bin['right_db'] -= $take;
} elseif ($amountType === 2) {
$bin['left_db'] -= $take;
}
$bin['amount'] = min($bin['right_db'], $bin['left_db']);
$need -= $take;
if ($bin['right_db'] <= 0 && $bin['left_db'] <= 0) {
array_shift($stock[$itemId]);
}
}
return $picks;
}
private function pickCLSet($itemId, $setInfo, &$need, $amountType, &$boxStock) {
$picks = [];
$item1 = $setInfo['item1'];
$item2 = $setInfo['item2'];
$available1 = 0;
$available2 = 0;
if (isset($boxStock[$item1])) {
foreach ($boxStock[$item1] as $bin) {
$available1 += $bin['amount'];
}
}
if (isset($boxStock[$item2])) {
foreach ($boxStock[$item2] as $bin) {
$available2 += $bin['amount'];
}
}
$maxCanTake = min($available1, $available2, $need);
if ($maxCanTake > 0) {
$tempNeed = $maxCanTake;
while ($tempNeed > 0 && !empty($boxStock[$item1]) && !empty($boxStock[$item2])) {
$bin1 = &$boxStock[$item1][0];
$bin2 = &$boxStock[$item2][0];
$take = min($bin1['amount'], $bin2['amount'], $tempNeed);
$pos1 = $this->formatWarehousePosition($bin1['pos'], $bin1['warehouse_id']);
$pos2 = $this->formatWarehousePosition($bin2['pos'], $bin2['warehouse_id']);
$picks[] = [
'wid' => $bin1['wid'] . '/' . $bin2['wid'],
'item_id' => $itemId,
'pos' => $pos1 . '
' . $pos2, // + helyett
'code' => '',
'amount' => $take,
'amount_type' => $amountType,
'location' => ($this->warehouseConfig[$bin1['warehouse_id']]['location'] ?? '') . ' / ' . ($this->warehouseConfig[$bin1['warehouse_id']]['name'] ?? '') . '
' . ($this->warehouseConfig[$bin2['warehouse_id']]['location'] ?? '') . ' / ' . ($this->warehouseConfig[$bin2['warehouse_id']]['name'] ?? ''),
'type' => 'stock'
];
$bin1['amount'] -= $take;
$bin2['amount'] -= $take;
$tempNeed -= $take;
if ($bin1['amount'] <= 0) {
array_shift($boxStock[$item1]);
}
if ($bin2['amount'] <= 0) {
array_shift($boxStock[$item2]);
}
}
$need -= $maxCanTake;
}
return $picks;
}
private function pickNormalSet($itemId, $setInfo, &$need, $amountType, $primarySource, &$boxStock, &$foilStock) {
$picks = [];
$item1 = $setInfo['item1'];
$item2 = $setInfo['item2'];
$sources = ($primarySource === 1) ? ['foil', 'box', 'hybrid'] : ['box', 'foil', 'hybrid'];
foreach ($sources as $sourceType) {
if ($need <= 0) break;
if ($sourceType === 'box' && isset($boxStock[$itemId])) {
while ($need > 0 && !empty($boxStock[$itemId])) {
$bin = &$boxStock[$itemId][0];
$take = min($bin['amount'], $need);
$picks[] = [
'wid' => $bin['wid'],
'item_id' => $itemId,
'pos' => $this->formatWarehousePosition($bin['pos'], $bin['warehouse_id']),
'code' => $this->warehouseConfig[$bin['warehouse_id']]['code'] ?? '',
'amount' => $take,
'amount_type' => $amountType,
'location' => ($this->warehouseConfig[$bin['warehouse_id']]['location'] ?? '') . ' / ' . ($this->warehouseConfig[$bin['warehouse_id']]['name'] ?? ''),
'type' => 'stock'
];
$bin['amount'] -= $take;
$need -= $take;
if ($bin['amount'] <= 0) {
array_shift($boxStock[$itemId]);
}
}
}
if ($sourceType === 'foil' && $need > 0) {
$picks = array_merge($picks, $this->pickSetFromFoil($itemId, $item1, $item2, $need, $amountType, $foilStock));
}
if ($sourceType === 'hybrid' && $need > 0) {
$picks = array_merge($picks, $this->pickSetHybrid($itemId, $item1, $item2, $need, $amountType, $boxStock, $foilStock));
}
}
return $picks;
}
private function pickSetFromFoil($itemId, $item1, $item2, &$need, $amountType, &$foilStock) {
$picks = [];
$available1 = 0;
$available2 = 0;
if (isset($foilStock[$item1])) {
foreach ($foilStock[$item1] as $bin) {
$available1 += $bin['amount'];
}
}
if (isset($foilStock[$item2])) {
foreach ($foilStock[$item2] as $bin) {
$available2 += $bin['amount'];
}
}
$maxCanTake = min($available1, $available2, $need);
if ($maxCanTake > 0) {
$tempNeed = $maxCanTake;
while ($tempNeed > 0 && !empty($foilStock[$item1]) && !empty($foilStock[$item2])) {
$bin1 = &$foilStock[$item1][0];
$bin2 = &$foilStock[$item2][0];
$take = min($bin1['amount'], $bin2['amount'], $tempNeed);
if ($take > 0) {
$picks[] = [
'wid' => $bin1['wid'] . '/' . $bin2['wid'],
'item_id' => $itemId,
'pos' => $bin1['pos'] . '
' . $bin2['pos'], // + helyett
'code' => '',
'amount' => $take,
'amount_type' => $amountType,
'location' => self::FOIL_WAREHOUSE_LABEL,
'type' => 'foil'
];
$bin1['amount'] -= $take;
$bin2['amount'] -= $take;
$bin1['right_db'] -= $take;
$bin1['left_db'] -= $take;
$bin2['right_db'] -= $take;
$bin2['left_db'] -= $take;
$tempNeed -= $take;
}
if ($bin1['amount'] <= 0) {
array_shift($foilStock[$item1]);
}
if ($bin2['amount'] <= 0) {
array_shift($foilStock[$item2]);
}
}
$need -= $maxCanTake;
}
return $picks;
}
private function pickSetHybrid($itemId, $item1, $item2, &$need, $amountType, &$boxStock, &$foilStock) {
$picks = [];
// item1 dobozból, item2 fóliásból
$availableBox1 = 0;
$availableFoil2 = 0;
if (isset($boxStock[$item1])) {
foreach ($boxStock[$item1] as $bin) {
$availableBox1 += $bin['amount'];
}
}
if (isset($foilStock[$item2])) {
foreach ($foilStock[$item2] as $bin) {
$availableFoil2 += $bin['amount'];
}
}
$maxCanTake1 = min($availableBox1, $availableFoil2, $need);
if ($maxCanTake1 > 0) {
$tempNeed = $maxCanTake1;
while ($tempNeed > 0 && !empty($boxStock[$item1]) && !empty($foilStock[$item2])) {
$bin1 = &$boxStock[$item1][0];
$bin2 = &$foilStock[$item2][0];
$take = min($bin1['amount'], $bin2['amount'], $tempNeed);
if ($take > 0) {
$pos1 = $this->formatWarehousePosition($bin1['pos'], $bin1['warehouse_id']);
$picks[] = [
'wid' => $bin1['wid'] . '/' . $bin2['wid'],
'item_id' => $itemId,
'pos' => $pos1 . '
' . $bin2['pos'], // + helyett
'code' => '',
'amount' => $take,
'amount_type' => $amountType,
'location' => ($this->warehouseConfig[$bin1['warehouse_id']]['location'] ?? '') . ' / ' . ($this->warehouseConfig[$bin1['warehouse_id']]['name'] ?? '') . '
' . self::FOIL_WAREHOUSE_LABEL,
'type' => 'hybrid'
];
$bin1['amount'] -= $take;
$bin2['amount'] -= $take;
$bin2['right_db'] -= $take;
$bin2['left_db'] -= $take;
$tempNeed -= $take;
}
if ($bin1['amount'] <= 0) {
array_shift($boxStock[$item1]);
}
if ($bin2['amount'] <= 0) {
array_shift($foilStock[$item2]);
}
}
$need -= $maxCanTake1;
}
// item1 fóliásból, item2 dobozból
if ($need > 0) {
$availableFoil1 = 0;
$availableBox2 = 0;
if (isset($foilStock[$item1])) {
foreach ($foilStock[$item1] as $bin) {
$availableFoil1 += $bin['amount'];
}
}
if (isset($boxStock[$item2])) {
foreach ($boxStock[$item2] as $bin) {
$availableBox2 += $bin['amount'];
}
}
$maxCanTake2 = min($availableFoil1, $availableBox2, $need);
if ($maxCanTake2 > 0) {
$tempNeed = $maxCanTake2;
while ($tempNeed > 0 && !empty($foilStock[$item1]) && !empty($boxStock[$item2])) {
$bin1 = &$foilStock[$item1][0];
$bin2 = &$boxStock[$item2][0];
$take = min($bin1['amount'], $bin2['amount'], $tempNeed);
if ($take > 0) {
$pos2 = $this->formatWarehousePosition($bin2['pos'], $bin2['warehouse_id']);
$picks[] = [
'wid' => $bin1['wid'] . '/' . $bin2['wid'],
'item_id' => $itemId,
'pos' => $bin1['pos'] . '
' . $pos2, // + helyett
'code' => '',
'amount' => $take,
'amount_type' => $amountType,
'location' => self::FOIL_WAREHOUSE_LABEL . '
' . ($this->warehouseConfig[$bin2['warehouse_id']]['location'] ?? '') . ' / ' . ($this->warehouseConfig[$bin2['warehouse_id']]['name'] ?? ''),
'type' => 'hybrid'
];
$bin1['amount'] -= $take;
$bin1['right_db'] -= $take;
$bin1['left_db'] -= $take;
$bin2['amount'] -= $take;
$tempNeed -= $take;
}
if ($bin1['amount'] <= 0) {
array_shift($foilStock[$item1]);
}
if ($bin2['amount'] <= 0) {
array_shift($boxStock[$item2]);
}
}
$need -= $maxCanTake2;
}
}
return $picks;
}
// ========================================================================
// SEGÉD METÓDUSOK
// ========================================================================
/**
* Szett item_id szétbontása
* Ha van prefix (betű), akkor vezető nullák maradnak
* Ha nincs prefix, akkor vezető nullák eltávolítása
*/
private function splitSetItemId($itemId) {
// Ellenőrzés: tartalmaz-e '+' jelet
if (strpos($itemId, '+') === false) {
return false;
}
$parts = explode('+', $itemId, 2);
$first = trim($parts[0]);
$second = trim($parts[1]);
// Prefix detektálás (nem számjegy karakterek az elején)
$prefix = '';
$firstNumeric = $first;
if (preg_match('/^([^0-9]{1,2})(.*)$/', $first, $matches)) {
// Van prefix (pl. CL, FR, LR)
$prefix = $matches[1];
$firstNumeric = $matches[2];
// Prefix esetén vezető nullák MARADNAK
$item1 = $prefix . $firstNumeric;
$item2 = $prefix . $second;
} else {
// Nincs prefix - csak számok
// Vezető nullák ELTÁVOLÍTÁSA
$item1 = (string)intval($first);
$item2 = (string)intval($second);
}
return ['item1' => $item1, 'item2' => $item2];
}
private function isCLSet($itemId) {
return substr($itemId, 0, 2) === self::CL_SET_PREFIX;
}
private function formatWarehousePosition($position, $warehouseId) {
$parts = explode(':', $position);
if (count($parts) === 2) {
$letter = $this->numberToLetter(intval($parts[0]));
$number = $this->padZero($parts[1]);
$code = $this->warehouseConfig[$warehouseId]['code'] ?? '';
return $code . $letter . $number;
}
return $position;
}
private function numberToLetter($n) {
if ($n < 1 || $n > 26) return null;
return chr(64 + $n);
}
private function padZero($str) {
return str_pad(strval($str), 2, '0', STR_PAD_LEFT);
}
private function formatPositionForSort(&$pickingList) {
foreach ($pickingList as &$entry) {
if (strpos($entry['pos'], ',') !== false) {
list($row, $col) = explode(',', $entry['pos']);
$entry['pos'] = $col . '~' . $row;
}
}
unset($entry);
}
private function sortPickingList(&$pickingList) {
$typeOrder = [
'foil' => 1,
'stock' => 2,
'hybrid' => 2,
'taken' => 3,
'missing' => 4
];
usort($pickingList, function($a, $b) use ($typeOrder) {
$aType = $a['type'] ?? 'stock';
$bType = $b['type'] ?? 'stock';
$aPriority = $typeOrder[$aType] ?? 3;
$bPriority = $typeOrder[$bType] ?? 3;
if ($aPriority != $bPriority) {
return $aPriority - $bPriority;
}
if ($aType === 'taken' || $aType === 'missing') {
return strcmp($a['item_id'], $b['item_id']);
}
// Lokáció természetes rendezés
$locCmp = strnatcmp($a['location'], $b['location']);
if ($locCmp != 0) {
return $locCmp;
}
// Pozíció természetes rendezés
if (in_array($aType, ['stock', 'hybrid'])) {
if (strpos($a['pos'], '~') !== false && strpos($b['pos'], '~') !== false) {
list($aCol, $aRow) = explode('~', $a['pos']);
list($bCol, $bRow) = explode('~', $b['pos']);
if (intval($aRow) != intval($bRow)) {
return intval($aRow) - intval($bRow);
}
if (intval($aCol) != intval($bCol)) {
return intval($aCol) - intval($bCol);
}
}
}
// Természetes rendezés pozíción (FŐ01, FŐ02, ... FŐ10)
$posCmp = strnatcmp($a['pos'], $b['pos']);
if ($posCmp != 0) {
return $posCmp;
}
return strcmp($a['item_id'], $b['item_id']);
});
}
private function sortOrders(&$orders) {
$typeOrder = [
'foil' => 1,
'stock' => 2,
'hybrid' => 2,
'taken' => 3,
'missing' => 4
];
usort($orders, function($a, $b) use ($typeOrder) {
if (empty($a['picking_list']) || empty($b['picking_list'])) {
return 0;
}
$aFirst = $a['picking_list'][0];
$bFirst = $b['picking_list'][0];
$aType = $aFirst['type'] ?? 'stock';
$bType = $bFirst['type'] ?? 'stock';
$aPriority = $typeOrder[$aType] ?? 3;
$bPriority = $typeOrder[$bType] ?? 3;
if ($aPriority != $bPriority) {
return $aPriority - $bPriority;
}
// Természetes rendezés lokáción
$locCmp = strnatcmp($aFirst['location'], $bFirst['location']);
if ($locCmp != 0) {
return $locCmp;
}
// Pozíció rendezés
if (in_array($aType, ['stock', 'hybrid'])) {
if (strpos($aFirst['pos'], '~') !== false && strpos($bFirst['pos'], '~') !== false) {
list($aCol, $aRow) = explode('~', $aFirst['pos']);
list($bCol, $bRow) = explode('~', $bFirst['pos']);
if (intval($aRow) != intval($bRow)) {
return intval($aRow) - intval($bRow);
}
if (intval($aCol) != intval($bCol)) {
return intval($aCol) - intval($bCol);
}
}
}
// Természetes rendezés pozíción
return strnatcmp($aFirst['pos'], $bFirst['pos']);
});
}
private function determineIcon($pickingList) {
foreach ($pickingList as $entry) {
if ($entry['wid'] != 0) {
return '✓';
}
}
return '';
}
}
/**
* Raktárból Eltávolítás Osztály
*
* Funkció: Kiszedett termékek eltávolítása a raktárból és lefoglalás frissítése
*
*/
class WarehouseRemover {
private $conn;
/**
* Konstruktor
*/
public function __construct($conn) {
$this->conn = $conn;
}
/**
* Statikus hívás
*/
public static function remove($conn, $inputData, $coderclass) {
$remover = new self($conn);
return $remover->processRemoval($inputData, $coderclass);
}
/**
* Eltávolítás feldolgozás
*/
private function processRemoval($inputData, $coderclass) {
// Input adatok kinyerése és tisztítása
$wid = htmlspecialchars($inputData['wid'] ?? '');
$amount = htmlspecialchars($inputData['amount'] ?? '');
$item_id = htmlspecialchars(str_replace(' ', '+', $inputData['item_id'] ?? ''));
$corrigate = htmlspecialchars($inputData['corrigate'] ?? 'false');
$overal_order_id = $inputData['overal_order_id'] ?? '';
$encoded_reason = htmlspecialchars($inputData['reason'] ?? '');
// Order ID és order name feldolgozása
$order_info = $this->parseOrderInfo($overal_order_id);
$order_name = $order_info['order_name'];
$order_id = $order_info['order_id'];
// Reason dekódolás
$decoded_data = $coderclass->decode($encoded_reason, 'SZ4TUN4');
$data_parts = explode('|', $decoded_data);
if (count($data_parts) != 2) {
return ['result' => 'error', 'message' => 'Érvénytelen kiszedési lista azonosító'];
}
$reason = $data_parts[0];
$order_date = $data_parts[1];
// Amount type feldolgozása
$amount_info = $this->parseAmount($amount);
$amount_type = $amount_info['amount_type'];
$amount_value = $amount_info['amount'];
// WID lista feldolgozása és szétválogatása
$wid_info = $this->parseWids($wid);
$foil_wids = $wid_info['foil_wids'];
$box_wids = $wid_info['box_wids'];
// Raktár ellenőrzés
$warehouse_check = $this->checkWarehouseStock($foil_wids, $box_wids, $amount_value, $amount_type);
if (!$warehouse_check['success']) {
return $warehouse_check;
}
$warehouse_foil_list = $warehouse_check['foil_list'];
$warehouse_box_list = $warehouse_check['box_list'];
// Lefoglalás ellenőrzés
$reservation_check = $this->checkReservation($item_id, $order_date, $reason, $order_name, $order_id, $amount_type, $amount_value);
if (!$reservation_check['success']) {
return $reservation_check;
}
$reserv_id = $reservation_check['reserv_id'];
$new_taken_out = $reservation_check['new_taken_out'];
// Lefoglalás frissítése
$this->updateReservation($reserv_id, $new_taken_out);
// Raktár frissítése
$update_result = $this->updateWarehouseStock(
$foil_wids,
$box_wids,
$warehouse_foil_list,
$warehouse_box_list,
$amount_value,
$amount_type,
$corrigate
);
return [
'result' => 'ok',
'reset' => $update_result['reset'],
'message' => $update_result['message']
];
}
/**
* Order info feldolgozás
*/
private function parseOrderInfo($overal_order_id) {
$order_name = '';
$order_id = '';
if ($overal_order_id != '!&maradek&! ') {
$last_dash_pos = strrpos($overal_order_id, ' - ');
if ($last_dash_pos !== false) {
$order_name = htmlspecialchars(substr($overal_order_id, 0, $last_dash_pos));
$order_part = substr($overal_order_id, $last_dash_pos + 3);
$order_id = substr($order_part, 1, -1);
} else {
$order_name = htmlspecialchars($overal_order_id);
}
}
return ['order_name' => $order_name, 'order_id' => $order_id];
}
/**
* Amount feldolgozás (J/B prefix kezelése)
*/
private function parseAmount($amount) {
$amount_type = 0;
if (substr($amount, 0, 1) == "J") {
$amount_type = 1;
$amount = substr($amount, 1);
} else if (substr($amount, 0, 1) == "B") {
$amount_type = 2;
$amount = substr($amount, 1);
}
return ['amount_type' => $amount_type, 'amount' => intval($amount)];
}
/**
* WID lista feldolgozása és szétválogatása
*/
private function parseWids($wid) {
$wid_list = explode('/', $wid);
$foil_wids = [];
$box_wids = [];
foreach ($wid_list as $single_wid) {
if (substr($single_wid, 0, 1) == "F") {
$foil_wids[] = substr($single_wid, 1);
} else {
$box_wids[] = $single_wid;
}
}
return ['foil_wids' => $foil_wids, 'box_wids' => $box_wids];
}
/**
* Raktár készlet ellenőrzés
*/
private function checkWarehouseStock($foil_wids, $box_wids, $amount, $amount_type) {
$warehouse_foil_list = [];
$warehouse_box_list = [];
// Fóliás raktár ellenőrzés
foreach ($foil_wids as $foil_wid) {
$stmt = $this->conn->prepare("SELECT * FROM warehouse_foil WHERE wid = ? AND is_active = 1");
$stmt->bind_param("i", $foil_wid);
$stmt->execute();
$result = $stmt->get_result();
$warehouse_foil = $result->fetch_assoc();
$stmt->close();
if ($warehouse_foil == null) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Érvénytelen fóliás raktár azonosító (WID: F' . $foil_wid . ')'
];
}
// Mennyiség ellenőrzés
if ($amount_type == 1) {
$inWarehouse = intval($warehouse_foil['right_db']);
} else if ($amount_type == 2) {
$inWarehouse = intval($warehouse_foil['left_db']);
} else {
$inWarehouse = min(intval($warehouse_foil['right_db']), intval($warehouse_foil['left_db']));
}
if ($inWarehouse < $amount) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Érvénytelen raktár bejegyzés, a fóliás raktár szerint nincs ennyi termék a polcon (van: ' . $inWarehouse . ', kell: ' . $amount . ')'
];
}
$warehouse_foil_list[] = $warehouse_foil;
}
// Dobozos raktár ellenőrzés
foreach ($box_wids as $box_wid) {
$stmt = $this->conn->prepare("SELECT * FROM warehouse WHERE wid = ?");
$stmt->bind_param("i", $box_wid);
$stmt->execute();
$result = $stmt->get_result();
$warehouse_box = $result->fetch_assoc();
$stmt->close();
if ($warehouse_box == null) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Érvénytelen dobozos raktár azonosító (WID: ' . $box_wid . ')'
];
}
if (intval($warehouse_box['amount']) < $amount) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Érvénytelen raktár bejegyzés, a dobozos raktár szerint nincs ennyi termék a polcon (van: ' . $warehouse_box['amount'] . ', kell: ' . $amount . ')'
];
}
$warehouse_box_list[] = $warehouse_box;
}
return [
'success' => true,
'foil_list' => $warehouse_foil_list,
'box_list' => $warehouse_box_list
];
}
/**
* Lefoglalás ellenőrzés
*/
private function checkReservation($item_id, $order_date, $reason, $order_name, $order_id, $amount_type, $amount) {
$stmt = $this->conn->prepare("SELECT * FROM warehouse_reservation
WHERE DATE(FROM_UNIXTIME(date_create)) = ?
AND item_id = ?
AND reason = ?
AND order_name = ?
AND order_id = ?
AND is_active = 1
AND amount_type = ?");
$stmt->bind_param("sssssi", $order_date, $item_id, $reason, $order_name, $order_id, $amount_type);
$stmt->execute();
$result = $stmt->get_result();
$reservation_sql = $result->fetch_assoc();
$stmt->close();
if ($reservation_sql == null) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Érvénytelen rendelési azonosító (item: ' . $item_id . ', order: ' . $order_name . ', date: ' . $order_date . ')'
];
}
$reserv_id = $reservation_sql['reserv_id'];
$current_taken_out = intval($reservation_sql['taken_out']);
$ordered_amount = intval($reservation_sql['amount']);
$new_taken_out = $current_taken_out + $amount;
if ($new_taken_out > $ordered_amount) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Hiba történt a mennyiségek megadásakor! Több terméket akart kiszedni mint amennyi a rendelésben szerepel. (Rendelt: ' . $ordered_amount . ', már kiszedve: ' . $current_taken_out . ', most kiszedni kívánt: ' . $amount . ')'
];
}
if ($new_taken_out < 0) {
return [
'success' => false,
'result' => 'error',
'reset' => 'true',
'message' => 'Hiba történt a mennyiségek megadásakor, negatív érték nem megengedett!'
];
}
return [
'success' => true,
'reserv_id' => $reserv_id,
'new_taken_out' => $new_taken_out
];
}
/**
* Lefoglalás frissítése
*/
private function updateReservation($reserv_id, $new_taken_out) {
$stmt = $this->conn->prepare("UPDATE warehouse_reservation SET taken_out = ? WHERE reserv_id = ?");
$stmt->bind_param("ii", $new_taken_out, $reserv_id);
$stmt->execute();
$stmt->close();
}
/**
* Raktár készlet frissítése
*/
private function updateWarehouseStock($foil_wids, $box_wids, $warehouse_foil_list, $warehouse_box_list, $amount, $amount_type, $corrigate) {
$reset = 'false';
$message = '';
// Fóliás raktár frissítése
foreach ($foil_wids as $idx => $foil_wid) {
$warehouse_foil = $warehouse_foil_list[$idx];
// Mennyiség számítás
if ($amount_type == 1) {
$left_db = 0;
$right_db = -$amount;
} else if ($amount_type == 2) {
$left_db = -$amount;
$right_db = 0;
} else {
$left_db = -$amount;
$right_db = -$amount;
}
// Korrigálás
if ($corrigate == 'true') {
if ($amount_type == 1) {
$left_db = 0;
$right_db = -intval($warehouse_foil['right_db']);
} else if ($amount_type == 2) {
$left_db = -intval($warehouse_foil['left_db']);
$right_db = 0;
} else {
if (intval($warehouse_foil['right_db']) > intval($warehouse_foil['left_db'])) {
$left_db = -intval($warehouse_foil['left_db']);
$right_db = -intval($warehouse_foil['left_db']);
} else {
$left_db = -intval($warehouse_foil['right_db']);
$right_db = -intval($warehouse_foil['right_db']);
}
}
$reset = 'true';
$message = 'A raktár megfelelő polcán a mennyiség nullázva lett';
}
// Frissítés
$stmt = $this->conn->prepare("UPDATE warehouse_foil
SET left_db = CASE WHEN left_db + ? < 0 THEN 0 ELSE left_db + ? END,
right_db = CASE WHEN right_db + ? < 0 THEN 0 ELSE right_db + ? END
WHERE wid = ?");
$stmt->bind_param("iiiii", $left_db, $left_db, $right_db, $right_db, $foil_wid);
$stmt->execute();
$stmt->close();
}
// Dobozos raktár frissítése
foreach ($box_wids as $idx => $box_wid) {
$warehouse_box = $warehouse_box_list[$idx];
$new_amount_in_warehouse = 0;
if ($corrigate == 'true') {
$new_amount_in_warehouse = 0;
$reset = 'true';
$message = 'A raktár megfelelő polcán a mennyiség nullázva lett';
} else {
$new_amount_in_warehouse = intval($warehouse_box['amount']) - $amount;
}
$stmt = $this->conn->prepare("UPDATE warehouse SET amount = ? WHERE wid = ?");
$stmt->bind_param("ii", $new_amount_in_warehouse, $box_wid);
$stmt->execute();
$stmt->close();
}
return ['reset' => $reset, 'message' => $message];
}
}
?>