first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,315 @@
<?php
namespace KupShop\OrderingBundle;
use KupShop\AdminBundle\Exception\ExportException;
use KupShop\KupShopBundle\Util\Excel\ExcelGenerator;
use KupShop\OrderingBundle\OrderList\MultiFetch;
use KupShop\OrderingBundle\OrderList\OrderList;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use Query\Operator;
use Query\QueryBuilder;
class OrdersExcelExport
{
/** @var int[] */
protected $orderIDs = [];
/** @var array */
protected $fields;
/** @var array */
protected $vats;
/** @var \Order|null */
protected $order;
protected $ORDERS_ITEMS_LIMIT = 1000000;
/** @var MultiFetch */
protected $multiFetch;
/** @var ExcelGenerator */
protected $excelGenerator;
/** @var OrderInfo */
protected $orderInfo;
/**
* @param int[] $orderIDs
*/
public function setOrderIDs(array $orderIDs)
{
$this->orderIDs = $orderIDs;
}
/** @required */
public function setMultiFetch(MultiFetch $multiFetch)
{
$this->multiFetch = $multiFetch;
}
/** @required */
public function setExcelGenerator(ExcelGenerator $excelGenerator)
{
$this->excelGenerator = $excelGenerator;
}
/** @required */
public function setOrderInfo(OrderInfo $orderInfo)
{
$this->orderInfo = $orderInfo;
}
protected function getFields()
{
if (!isset($this->fields)) {
$this->fields = $this->prepareFields();
}
return $this->fields;
}
protected function prepareFields()
{
$fields = [
'order_no' => ['field' => 'o.order_no', 'name' => 'Kód'],
'status' => ['field' => 'o.status', 'name' => 'Stav objednávky'],
'status_payed' => ['field' => 'o.status_payed', 'name' => 'Zaplaceno'],
'status_storno' => ['field' => 'o.status_storno', 'name' => 'Stornováno'],
'date_created' => ['field' => 'o.date_created', 'name' => 'Datum objednávky', 'type' => 'datetime', 'format' => 'd.m.yyyy hh:mm:ss', 'width' => 16],
'date_accept' => ['field' => 'o.date_accept', 'name' => 'Datum přijetí', 'type' => 'datetime', 'format' => 'd.m.yyyy hh:mm:ss', 'width' => 16],
'date_handle' => ['field' => 'o.date_handle', 'name' => 'Datum vyřízení', 'type' => 'datetime', 'format' => 'd.m.yyyy hh:mm:ss', 'width' => 16],
'date_due' => ['field' => 'o.date_due', 'name' => 'Datum splatnosti', 'type' => 'datetime', 'format' => 'd.m.yyyy hh:mm:ss', 'width' => 16],
'source' => ['field' => 'o.source', 'name' => 'Zdroj objednávky'],
'items' => [
'spec' => function (QueryBuilder $qb) {
$qb->leftJoin('o', 'order_items', 'oi', 'oi.id_order = o.id');
return 'COUNT(oi.id) AS items';
},
'name' => 'Počet položek',
'type' => DataType::TYPE_NUMERIC,
],
'total_price' => ['field' => 'o.total_price', 'name' => 'Cena s DPH', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'],
];
if (findModule(\Modules::CURRENCIES)) {
$fields['currency'] = ['field' => 'o.currency', 'name' => 'Měna'];
$fields['id_language'] = ['field' => 'o.id_language', 'name' => 'Jazyk'];
$fields['currency_rate'] = ['field' => 'o.currency_rate', 'name' => 'Kurz', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.0000'];
$dbcfg = \Settings::getDefault();
$fields['total_price_in_default_currency'] = ['field' => 'o.total_price*o.currency_rate AS total_price_in_default_currency', 'name' => 'Cena ('.$dbcfg['currency'].') s DPH', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'];
}
foreach ($this->getVats() as $vatValue => $vatRow) {
$fields["BASEVAT{$vatValue}"] = ['name' => 'Základ DPH '.$vatValue.'%', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'];
$fields["VAT{$vatValue}"] = ['name' => 'DPH '.$vatValue.'%', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.00'];
}
$fields = array_merge($fields, [
'invoice_name' => ['field' => 'o.invoice_name', 'name' => 'Jméno'],
'invoice_surname' => ['field' => 'o.invoice_surname', 'name' => 'Příjmení'],
'invoice_firm' => ['field' => 'o.invoice_firm', 'name' => 'Firma'],
'invoice_email' => ['field' => 'o.invoice_email', 'name' => 'Email'],
'invoice_phone' => ['field' => 'o.invoice_phone', 'name' => 'Telefon'],
'invoice_street' => ['field' => 'o.invoice_street', 'name' => 'Ulice'],
'invoice_city' => ['field' => 'o.invoice_city', 'name' => 'Město'],
'invoice_zip' => ['field' => 'o.invoice_zip', 'name' => 'PSČ'],
'invoice_country' => ['field' => 'o.invoice_country', 'name' => 'Země'],
'invoice_state' => ['field' => 'o.invoice_state', 'name' => 'Stát/region'],
'invoice_custom_address' => ['field' => 'o.invoice_custom_address', 'name' => 'Upřesnění adresy'],
'invoice_ico' => ['field' => 'o.invoice_ico', 'name' => 'IČO'],
'invoice_dic' => ['field' => 'o.invoice_dic', 'name' => 'DIČ'],
'delivery_name' => ['field' => 'o.delivery_name', 'name' => 'Doruč. jméno'],
'delivery_surname' => ['field' => 'o.delivery_surname', 'name' => 'Doruč. příjmení'],
'delivery_firm' => ['field' => 'o.delivery_firm', 'name' => 'Doruč. firma'],
'delivery_street' => ['field' => 'o.delivery_street', 'name' => 'Doruč. ulice'],
'delivery_city' => ['field' => 'o.delivery_city', 'name' => 'Doruč. město'],
'delivery_zip' => ['field' => 'o.delivery_zip', 'name' => 'Doruč. PSČ'],
'delivery_country' => ['field' => 'o.delivery_country', 'name' => 'Doruč. země'],
'delivery_state' => ['field' => 'o.delivery_state', 'name' => 'Doruč. stát/region'],
'delivery_custom_address' => ['field' => 'o.delivery_custom_address', 'name' => 'Doruč. upřesnění adresy'],
'note_user' => ['field' => 'o.note_user', 'name' => 'Pozn. pro obchodníka'],
'flags' => ['field' => 'o.flags', 'name' => 'Příznaky'],
'delivery' => [
'spec' => function (QueryBuilder $qb) {
$qb->leftJoin('o', 'delivery_type', 'dt', 'dt.id = o.id_delivery')
->leftJoin('dt', 'delivery_type_delivery', 'dtd', 'dtd.id = dt.id_delivery');
return 'dtd.name AS delivery';
},
'name' => 'Doprava',
],
'payment' => [
'spec' => function (QueryBuilder $qb) {
$qb->leftJoin('o', 'delivery_type', 'dt', 'dt.id = o.id_delivery')
->leftJoin('dt', 'delivery_type_payment', 'dtp', 'dtp.id = dt.id_payment');
return 'dtp.name AS payment';
},
'name' => 'Platba',
],
'discounts' => ['name' => 'Použité slevy'],
'package_id' => ['field' => 'o.package_id', 'name' => 'Číslo balíku'],
'note_invoice' => ['field' => 'o.note_invoice', 'name' => 'Poznámka na faktuře'],
'consents' => ['field' => 'JSON_KEYS(note_admin, "$.consents") as consents', 'name' => 'Consents'],
]);
if (findModule(\Modules::PRODUCTS, \Modules::SUB_WEIGHT)) {
$fields['weight'] = ['name' => 'Váha objednávky', 'type' => DataType::TYPE_NUMERIC, 'format' => '0.000'];
}
if (findModule(\Modules::PRODUCTS, \Modules::SUB_PRICE_BUY)) {
$fields['items_price_buy'] = [
'name' => 'Nákupní cena',
'spec' => function (QueryBuilder $qb) {
$qb->leftJoin('oi', 'products', 'p', 'p.id = oi.id_product');
$qb->leftJoin('oi', 'products_variations', 'pv', 'pv.id = oi.id_variation');
return 'SUM(COALESCE(oi.price_buy * o.currency_rate, pv.price_buy, p.price_buy)*oi.pieces) AS items_price_buy';
},
'type' => DataType::TYPE_NUMERIC,
];
}
if (findModule(\Modules::INVOICES)) {
$fields['invoice_no'] = [
'name' => 'Číslo faktury',
'field' => 'o.invoice_no',
];
}
$fields['user_order_no'] = ['field' => 'o.user_order_no', 'name' => 'Zákazníkovo číslo objednávky'];
return $fields;
}
protected function getVats(): array
{
if (!isset($this->vats)) {
$vatsSQL = sqlQuery('SELECT id, descr, vat, is_default
FROM vats
ORDER BY vat DESC ');
$vats = [];
foreach ($vatsSQL as $row) {
$vats[(string) $row['vat']] = $row;
}
$this->vats = $vats;
}
return $this->vats;
}
protected function prepareQuery(): QueryBuilder
{
/** @var $qb QueryBuilder */
$qb = sqlQueryBuilder()->select('o.id')
->from('orders', 'o')
->andWhere(\Query\Operator::inIntArray($this->orderIDs, 'o.id'))
->groupBy('o.id')
->orderBy('o.id');
foreach ($this->getFields() as $key => $arr) {
if (isset($arr['field'])) {
$qb->addSelect($arr['field']);
}
if (isset($arr['spec'])) {
$qb->addSelect($arr['spec']);
}
}
return $qb;
}
protected function prepareRow($row, \Order $order): array
{
$row['status'] = getOrderStatus($row['status'])['name'] ?? '';
$row['total_price'] = number_format($row['total_price'], 2, '.', '');
foreach ($this->getVats() as $vatValue => $value) {
if (!empty($order->vats[$vatValue])) {
$vat = $order->vats[$vatValue];
if (findModule('currencies')) {
$total_price_without_vat = $vat['total_price_without_vat']->mul(toDecimal($row['currency_rate']));
$total_price_with_vat = $vat['total_price_with_vat']->mul(toDecimal($row['currency_rate']));
$row["BASEVAT{$vatValue}"] = $total_price_without_vat->printFloatValue(2);
$row["VAT{$vatValue}"] = $total_price_with_vat->sub($total_price_without_vat)->printFloatValue(2);
} else {
$row["BASEVAT{$vatValue}"] = $vat['total_price_without_vat']->printFloatValue(2);
$row["VAT{$vatValue}"] = $vat['total_price_with_vat']->sub($vat['total_price_without_vat'])->printFloatValue(2);
}
} else {
$row["BASEVAT{$vatValue}"] = number_format(0, 2);
$row["VAT{$vatValue}"] = number_format(0, 2);
}
}
$row['discounts'] = join(',', $this->orderInfo->getUsedDiscounts($order->id));
if (findModule(\Modules::PRODUCTS, \Modules::SUB_WEIGHT)) {
$row['weight'] = $order->getTotalWeight();
}
return $row;
}
protected function checkItemsCount()
{
$data = $this->prepareQuery()->execute();
$items_count = $data->rowCount();
if ($items_count >= $this->ORDERS_ITEMS_LIMIT) {
throw new ExportException('Export se nepodařil, protože byl překročen limit '.$this->ORDERS_ITEMS_LIMIT.' položek');
}
if ($items_count == 0) {
throw new ExportException('Export se nepodařil, protože zadanému filtru neodpovídá žádná položka');
}
set_time_limit(600);
}
protected function getData()
{
$data = $this->prepareQuery()->execute()->fetchAll();
$chunks = array_chunk($data, 1000, false);
foreach ($chunks as $chunk) {
$filter = array_map(function ($x) {
return $x['id'];
}, $chunk);
$orderList = new OrderList($this->multiFetch);
$orders = $orderList->andSpec(
function (QueryBuilder $qb) use ($filter) {
$qb->andWhere(Operator::inIntArray($filter, 'o.id'));
}
)->getOrders();
$this->multiFetch->fetchItems($orders);
foreach ($chunk as $row) {
if ($orders[$row['id']] != null) {
$output = $this->prepareRow($row, $orders[$row['id']]);
$ordered = [];
foreach ($this->getFields() as $key => $value) {
$ordered[$key] = $output[$key];
}
yield $ordered;
}
}
}
}
public function export()
{
ini_set('memory_limit', '2048M');
$this->checkItemsCount();
$filename = 'objednavky_'.date('Y-m-d_H-i').'.xlsx';
$this->excelGenerator->generateExcel($this->getFields(), $this->getData(), $filename);
return;
}
}