Files
kupshop/bundles/KupShop/CheckAppBundle/Util/OrderCheckoutWorker.php
2025-08-02 16:30:27 +02:00

282 lines
9.8 KiB
PHP

<?php
namespace KupShop\CheckAppBundle\Util;
use KupShop\BalikonosBundle\Balikobot;
use KupShop\CheckAppBundle\Exception\OrderCheckException;
use KupShop\KupShopBundle\Config;
use Query\Operator;
class OrderCheckoutWorker
{
/** @var Balikobot */
protected $balikobot;
/**
* @required
*/
public function setBalikobot(?Balikobot $balikobot): void
{
$this->balikobot = $balikobot;
}
/**
* Proved povinný kontroly nad objednávkou před výstupní kontrolou.
*/
public function checkOrder(string $order_no, ?\Order &$order)
{
if (empty($order_no)) {
return 'Načtete prosím objednávku.';
}
try {
$order = \Order::createFromDbOrderNo($order_no);
} catch (\InvalidArgumentException $e) {
return 'Neexistující objednávka.';
}
if ($error = $this->generalOrderCheck($order)) {
return $error;
}
if ($this->balikobot && ($error = $this->balikobotOrderCheck($order))) {
return $error;
}
return null;
}
public function generalOrderCheck($order)
{
if (!$order->isActive()) {
return 'Stornovaná objednávka.';
}
$deliveryType = $order->getDeliveryType();
if (!$deliveryType->id) {
return 'Neexistující způsob doručení.';
}
if ($deliveryType->isInPerson() && $order->getData('checkout_control')) {
return 'Výstupní kontrola proběhla! Připraveno na Osobní předání!';
}
$items = $order->fetchItems();
$products = array_filter($items, function ($i) { return !empty($i['id_product']); });
if (!$products) {
return 'Objednávka nemá produkty.';
}
return null;
}
public function balikobotOrderCheck($order)
{
if ($this->balikobot->isDeliverySupported($order->getDeliveryType()->id_delivery)) {
$balikobotRow = sqlQueryBuilder()
->select('id, close')->from('balikonos')
->where(Operator::equals(['id_order' => $order->id]))
->andWhere('close = 1')
->execute()->fetch();
if ($balikobotRow) {
$url = Config::get()['Addr']['full']."admin/launch.php?s=orders.php&acn=edit&acn=PrintTicket&ID={$order->id}";
return "Štítek byl už jednou vytisknut. <a href=\"#\" onclick=\"window.scanner.print('{$url}'); return false;\">Znovu vytisknout</a>";
}
}
return null;
}
public function getOrderCheckData(int $id_order)
{
$order = new \Order();
$order->createFromDB($id_order);
// it means order does not exist
if ($order->order_no === null) {
return false;
}
$order->fetchItems();
$order->productList->fetchMainImages(3);
$data = [];
foreach ($order->fetchItems() as $item) {
// TODO vyhazovat neproduktovy polozky?
if ($item['id_product'] === null || $item['pieces'] <= 0) {
continue;
}
$additionalData = $this->getAdditionalData($item['id_product'], $item['id_variation']);
$variationCode = null;
if (!empty($item['id_variation']) && findModule(\Modules::PRODUCTS_VARIATIONS, 'variationCode')) {
$variationCode = sqlQueryBuilder()->select('code')->from('products_variations')
->where(Operator::equals(['id' => $item['id_variation']]))
->execute()->fetchColumn();
}
$newData = [
'id' => $item['id'],
'title' => $item['descr'],
'quantity' => (int) $item['pieces'],
'code' => !empty($variationCode) ? $variationCode : ($item['product']->code ?? ''),
'ean' => formatEAN($item['ean']),
'id_product' => $item['id_product'],
'id_variation' => $item['id_variation'],
'note' => $item['product']->note_ ?? '',
'serial_number_require' => $additionalData['serial_number_require'] ?? '',
'image' => $item['product']->image['src'] ?? '',
'positions' => $additionalData['positions'] ?? '',
'supplier_eans' => explode(';', $additionalData['supplier_eans'] ?? ''),
'supplier_codes' => explode(';', $additionalData['supplier_codes'] ?? ''),
];
$data[] = $newData;
}
// Srovnat aby ty bez EANů byly na konci
usort($data, function ($a, $b) {
return empty($b['ean']) <=> empty($a['ean']);
});
$index = 0;
foreach ($data as &$item) {
$item['index'] = $index++;
}
return array_values($data);
}
protected function getAdditionalData($id_product, $id_variation)
{
$data = [];
if (findModule(\Modules::PRODUCTS_SERIAL_NUMBERS)) {
$serial_number_require = sqlQueryBuilder()->select('serial_number_require')->from('products')
->where(Operator::equals(['id' => $id_product]))
->execute()->fetchColumn();
$data['serial_number_require'] = $serial_number_require;
}
return $data;
}
/**
* @return array
*/
public function checkoutOrder($order_no)
{
/** @var \Order $order */
if ($errors = $this->checkOrder($order_no, $order)) {
return [
'result' => false,
'message' => $errors,
];
}
$deliveryType = $order->getDeliveryType();
if ($deliveryType->isInPerson()) {
return $this->checkoutInPersonOrder($order);
}
if ($this->balikobot && $this->balikobot->isDeliverySupported($deliveryType->id_delivery)) {
return $this->checkoutBalikobotOrder($order);
}
}
public function checkoutInPersonOrder($order)
{
$order->setData('checkout_control', true);
$order->logHistory('Proběhla výstupní kontrola. Připraveno na osobní odběr.');
return [
'result' => true,
'message' => 'Připraveno na osobní odběr.',
];
}
public function checkoutBalikobotOrder($order)
{
// Send data to Balikobot
$balikobot = $this->sendToBalikobot($order);
if ($balikobot_error = $balikobot->getError()) {
return [
'result' => false,
'message' => "Objednávku <a href=\"javascript:nw('order', {$order->id})\">{$order->id}</a> se nepodařilo odeslat o Balíkobota: {$balikobot_error}",
];
}
$order->setData('checkout_control', true);
$order->logHistory('Proběhla výstupní kontrola. Objednávka nahrána do Balíkobota.');
return [
'result' => true,
'message' => 'Tiskneme etiketu.',
'printOrderLabel' => $order->id,
];
}
public function checkoutOrderSerialNumbers($items)
{
$items = array_filter($items ?? [], function ($item) {
return $item->serial_number_require === 'Y';
});
sqlGetConnection()->transactional(
function () use ($items) {
foreach ($items as $item) {
if (count($item->serialNumbers) == $item->checked) {
if (count($item->serialNumbers) > count(array_unique($item->serialNumbers))) {
throw new OrderCheckException('Produkt s ID '.$item->id_product.' má duplicitní SN.');
}
foreach ($item->serialNumbers as $serialNumber) {
$selectedSN = sqlQueryBuilder()->select('psn.id', 'psn.id_order_item')
->from('products_serial_numbers', 'psn')
->where(
Operator::equalsNullable(
[
'psn.serial_number' => $serialNumber,
'psn.id_product' => $item->id_product,
'psn.id_variation' => $item->id_variation,
]
)
)->execute()->fetch();
if (!$selectedSN) {
throw new OrderCheckException('Produkt s ID '.$item->id_product.' a SN "'.$serialNumber.'" není dostupný.');
} elseif (!empty($selectedSN['id_order_item']) && $selectedSN['id_order_item'] != $item->id) {
throw new OrderCheckException('Produkt s ID '.$item->id_product.' a SN "'.$serialNumber.'" je už v jiné objednávce.');
}
sqlQueryBuilder()->update('products_serial_numbers', 'psn')
->directValues(['id_order_item' => $item->id])
->where(Operator::equals([
'id' => $selectedSN['id'],
]))->execute();
}
} else {
throw new OrderCheckException('Produkt s id '.$item->id_product.' má méně SN než je nakliknuto.');
}
}
});
}
protected function sendToBalikobot($order, $reclamation = null)
{
$data = $order->getData('balikobot');
$IDs[$order->id] = [
'packages' => $data['packages'] ?? 1,
'note' => $data['note'] ?? null,
];
$this->balikobot->setIDs($IDs);
$this->balikobot->sendDeliveries();
return $this->balikobot;
}
}