316 lines
13 KiB
PHP
316 lines
13 KiB
PHP
<?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;
|
|
}
|
|
}
|