Files
kupshop/admin/lists/OrdersList.php
2025-08-02 16:30:27 +02:00

597 lines
25 KiB
PHP

<?php
use KupShop\AdminBundle\AdminList\BaseList;
use KupShop\AdminBundle\AdminList\FiltersStorage;
use KupShop\AdminBundle\Util\OrdersListFilter;
use KupShop\KupShopBundle\Context\CurrencyContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
use KupShop\OrderingBundle\Attachment\InvoicePDFAttachment;
use KupShop\OrderingBundle\Util\Order\OrderInfo;
use Query\Operator as Op;
$main_class = 'OrdersList';
class OrdersList extends BaseList
{
use FiltersStorage;
protected $template = 'list/orders.tpl';
protected $orderParam = [
'sort' => 'code',
'direction' => 'DESC',
];
protected $tableName = 'orders';
protected ?string $tableAlias = 'o';
protected bool $useLazyNumberOfPages = true;
protected $showMassEdit = true;
protected $tableDef = [
'id' => 'o.id',
'fields' => [
'code' => ['translate' => true, 'field' => 'o.id', 'render' => 'renderCode', 'type' => 'orders', 'size' => 0.7],
'source' => ['translate' => true, 'field' => 'o.source', 'spec' => 'o.source', 'render' => 'renderOrderSource', 'visible' => 'N'],
'customer' => ['translate' => true, 'field' => 'o.invoice_name', 'raw_field' => 'IF(o.invoice_firm != "", o.invoice_firm, o.invoice_surname)', 'render' => 'renderName', 'size' => 1.5, 'spec' => 'o.invoice_name'],
'status' => ['translate' => true, 'field' => 'o.status', 'render' => 'renderStatus', 'size' => 1, 'spec' => 'o.status', 'fieldType' => OrdersList::TYPE_LIST],
'orderItems' => ['translate' => true, 'field' => 'items', 'render' => 'renderItems', 'class' => 'left tiny-list-items', 'size' => 2, 'visible' => 'N'],
'price' => ['translate' => true, 'field' => 'o.total_price', 'render' => 'renderPrice', 'class' => 'text-right alignRight', 'size' => 1, 'headerRender' => 'renderHeaderPrice', 'spec' => 'o.total_price', 'editable' => 'N', 'fieldType' => BaseList::TYPE_PRICE],
'priceWithoutVat' => ['translate' => true, 'field' => 'o.total_price_without_vat', 'render' => 'renderPrice', 'class' => 'text-right alignRight', 'size' => 1, 'headerRender' => 'renderHeaderPrice', 'spec' => 'o.total_price_without_vat', 'editable' => 'N', 'fieldType' => BaseList::TYPE_PRICE, 'visible' => 'N'],
'delivery_type' => ['translate' => true, 'field' => 'o.delivery_type', 'render' => 'renderDelivery', 'class' => 'getDeliveryClass', 'size' => 1.25, 'spec' => []],
'delivery_name' => ['translate' => true, 'field' => 'delivery_name', 'visible' => 'N', 'spec' => []],
'payment_name' => ['translate' => true, 'field' => 'payment_name', 'visible' => 'N', 'spec' => []],
'flags' => ['translate' => true, 'field' => 'o.flags', 'render' => 'renderFlags', 'class' => 'columnCampaigns product-campaigns', 'size' => 0.7, 'spec' => [], 'fieldType' => OrdersList::TYPE_LIST_MULTISELECT],
'date' => ['translate' => true, 'field' => 'o.date_created', 'render' => 'renderDateTime', 'spec' => 'o.date_created'],
'statusPaid' => ['translate' => true, 'field' => 'status_payed', 'render' => 'renderStatusPaid', 'size' => 0.5],
'discounts' => ['translate' => true, 'render' => 'renderDiscounts', 'class' => 'left tiny-list-items', 'size' => 1, 'visible' => 'N'],
'email' => ['translate' => true, 'field' => 'o.invoice_email', 'spec' => 'o.invoice_email', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'zip' => ['translate' => true, 'field' => 'o.delivery_zip', 'spec' => 'o.delivery_zip', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'deliveryCountry' => ['translate' => true, 'field' => 'o.delivery_country', 'spec' => 'o.delivery_country', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'currency' => ['translate' => true, 'field' => 'o.currency', 'spec' => 'o.currency', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'note' => ['translate' => true, 'field' => 'o.note_user', 'spec' => 'o.note_user', 'visible' => 'N'],
'noteUser' => ['translate' => true, 'field' => 'user_note', 'spec' => 'o.invoice_email', 'render' => 'renderUserNote', 'visible' => 'N'],
'date_updated' => ['translate' => true, 'field' => 'o.date_updated', 'render' => 'renderDateTime', 'visible' => 'N'],
'date_delivered' => ['translate' => true, 'field' => 'o.date_delivered', 'render' => 'renderDateTime', 'visible' => 'N'],
'userOrderNo' => ['translate' => true, 'field' => 'o.user_order_no', 'spec' => 'o.user_order_no', 'type' => 'orders', 'visible' => 'N'],
'phone' => ['translate' => true, 'field' => 'o.invoice_phone', 'spec' => 'o.invoice_phone', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'invoiceFirm' => ['translate' => true, 'field' => 'o.invoice_firm', 'spec' => 'o.invoice_firm', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'invoiceIco' => ['translate' => true, 'field' => 'o.invoice_ico', 'spec' => 'o.invoice_ico', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'invoiceDic' => ['translate' => true, 'field' => 'o.invoice_dic', 'spec' => 'o.invoice_dic', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'invoiceZip' => ['translate' => true, 'field' => 'o.invoice_zip', 'spec' => 'o.invoice_zip', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'invoiceCountry' => ['translate' => true, 'field' => 'o.invoice_country', 'spec' => 'o.invoice_country', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'deliveryFirm' => ['translate' => true, 'field' => 'o.delivery_firm', 'spec' => 'o.delivery_firm', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'deliveryStreet' => ['translate' => true, 'field' => 'o.delivery_street', 'spec' => 'o.delivery_street', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'deliveryCity' => ['translate' => true, 'field' => 'o.delivery_city', 'spec' => 'o.delivery_city', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'deliveryPhone' => ['translate' => true, 'field' => 'o.delivery_phone', 'spec' => 'o.delivery_phone', 'visible' => 'N', 'fieldType' => BaseList::TYPE_STRING],
'customerGroups' => ['translate' => true, 'field' => 'customer_groups', 'spec' => [], 'visible' => 'N'],
'trackingNumber' => ['translate' => true, 'field' => 'package_id', 'render' => 'renderPackage', 'visible' => 'N', 'spec' => []],
'priceLevel' => ['translate' => true, 'field' => 'id', 'render' => 'renderPriceLevel', 'visible' => 'N'],
],
'class' => 'getRowClass',
];
private $orderTotalPriceSum;
/**
* @var OrdersListFilter
*/
protected $ordersListFilter;
/** @var OrderInfo */
protected $orderInfo;
public function __construct()
{
$this->orderTotalPriceSum = toDecimal(0);
$this->ordersListFilter = ServiceContainer::getService(OrdersListFilter::class);
$this->orderInfo = ServiceContainer::getService(OrderInfo::class);
}
public function getSQLOrdering(&$var, &$orderParam)
{
parent::getSQLOrdering($var, $orderParam);
if (isset($var['orderField']) && ($var['orderField'] == 'items' || $var['orderField'] == 'user_note')) {
$var['orderField'] = '';
}
}
public function customizeTableDef($tableDef)
{
$tableDef = parent::customizeTableDef($tableDef);
$cfg = \KupShop\KupShopBundle\Config::get();
$dbcfg = Settings::getDefault();
if (!findModule('eshop_delivery')) {
unset($tableDef['fields']['delivery']);
}
if (!findModule(Modules::PRICE_LEVELS)) {
unset($tableDef['fields']['priceLevel']);
}
if (empty($cfg['Order']['Flags'])) {
unset($tableDef['fields']['flags']);
}
if (findModule(Modules::TRANSLATIONS)) {
$tableDef['fields']['Jazyk'] = ['field' => 'o.id_language', 'spec' => 'o.id_language', 'visible' => 'N'];
}
if (findModule(Modules::INVOICES)) {
$tableDef['fields']['invoiceNo'] = ['translate' => true, 'field' => 'o.invoice_no', 'render' => 'renderInvoice', 'spec' => 'o.invoice_no'];
}
if (findModule(Modules::PRODUCTS, Modules::SUB_WEIGHT)) {
$tableDef['fields']['weight'] = ['translate' => true, 'field' => 'o.total_weight', 'spec' => 'o.total_weight', 'render' => 'renderFloat', 'visible' => 'N'];
}
if (findModule(Modules::DROPSHIP)) {
$tableDef['fields']['dropship'] = ['translate' => true, 'field' => 'dropship_name', 'visible' => 'N', 'render' => 'renderDropshipment', 'spec' => function (Query\QueryBuilder $qb) {
$qb->addSelect('dps.name as dropship_name, dps.id as dropship_id')
->leftJoin('o', 'order_dropshipment', 'odps', 'odps.id_order = o.id')
->leftJoin('odps', 'dropshipment', 'dps', 'dps.id = odps.id_dropshipment');
}];
}
if (findModule(Modules::BONUS_PROGRAM)) {
$tableDef['fields']['bonusPoints'] = ['translate' => true, 'field' => 'bonus_points', 'visible' => 'N', 'spec' => function (Query\QueryBuilder $qb) {
$qb->addSelect('bp.points as bonus_points')
->leftJoin('o', 'bonus_points', 'bp', 'o.id = bp.id_order');
}];
}
$tableDef['fields']['customerGroups']['spec'] = function (Query\QueryBuilder $qb) {
$qb->addSelect('GROUP_CONCAT(ug.name) as customer_groups')
->leftJoin('o', 'users_groups_relations', 'ugr', 'ugr.id_user=o.id_user')
->leftJoin('ugr', 'users_groups', 'ug', 'ug.id=ugr.id_group')
->groupBy('o.id');
};
$tableDef['fields']['payment_name']['spec'] = function (Query\QueryBuilder $qb) {
$qb->addSelect('COALESCE(dtp.name_admin, dtp.name) as payment_name')
->leftJoin('o', 'delivery_type', 'dt', 'dt.id=o.id_delivery')
->leftJoin('dt', 'delivery_type_payment', 'dtp', 'dtp.id=dt.id_payment');
};
$tableDef['fields']['trackingNumber']['spec'] = function (Query\QueryBuilder $qb) {
$qb->addSelect('o.package_id, dtd.class')
->leftJoin('o', 'delivery_type', 'dt', 'dt.id=o.id_delivery')
->leftJoin('dt', 'delivery_type_delivery', 'dtd', 'dtd.id=dt.id_delivery');
};
$tableDef['fields']['delivery_name']['spec'] = function (Query\QueryBuilder $qb) {
$qb->addSelect('COALESCE(dtd.name_admin, dtd.name) as delivery_name')
->leftJoin('o', 'delivery_type', 'dt', 'dt.id=o.id_delivery')
->leftJoin('dt', 'delivery_type_delivery', 'dtd', 'dtd.id=dt.id_delivery');
};
$tableDef['fields']['delivery_type']['spec'] = function (Query\QueryBuilder $qb) {
$qb->addSelect('COALESCE(dtp.name_admin, dtp.name) as payment_name, COALESCE(dtd.name_admin, dtd.name) as delivery_name')
->leftJoin('o', 'delivery_type', 'dt', 'dt.id=o.id_delivery')
->leftJoin('dt', 'delivery_type_payment', 'dtp', 'dtp.id=dt.id_payment')
->leftJoin('dt', 'delivery_type_delivery', 'dtd', 'dtd.id=dt.id_delivery');
};
$tableDef['fields']['dateDue'] = ['translate' => true, 'field' => 'date_due', 'render' => 'renderDate',
'spec' => 'COALESCE(o.date_due, (COALESCE(o.date_handle, o.date_accept, o.date_created) + INTERVAL '.($dbcfg->shop_due_days ?: 14).' DAY)) as date_due',
'visible' => 'N',
];
foreach (getOrderStatuses() as $statusId => $status) {
$tableDef['fields']['status']['fieldOptions'][$statusId] = $status['name'];
}
$tableDef['fields']['flags']['spec'] = function (Query\QueryBuilder $qb) {
$qb->addSelect('o.flags');
};
if (!empty($cfg['Order']['Flags'])) {
foreach ($cfg['Order']['Flags'] as $flag => $value) {
$tableDef['fields']['flags']['fieldOptions'][$flag] = $value['name'];
}
}
if (findModule(Modules::NEW_POS)) {
$tableDef['fields']['pos'] = ['field' => 'pos_name', 'translate' => true, 'size' => 1.5,
'spec' => function (Query\QueryBuilder $qb) {
$qb->addSelect('po.name AS pos_name, po.id AS pos_id')
->leftJoin('o', 'pos', 'po', 'o.pos = po.id');
}];
}
if (findModule(Modules::SELLERS)) {
$tableDef['fields']['seller'] = ['translate' => true,
'field' => 'seller_name',
'visible' => 'N',
'render' => 'renderSeller',
'spec' => function (Query\QueryBuilder $qb) {
$qb->addSelect('sell.title as seller_name, sell.id as seller_id')
->leftJoin('o', 'order_sellers', 'osell', 'osell.id_order = o.id')
->leftJoin('osell', 'sellers', 'sell', 'sell.id = osell.id_seller');
}];
}
return $tableDef;
}
public function renderInvoice(array $values): HTML
{
return HTML::create('a')
->attr('href', path('kupshop_admin_emailattachment_adminattachment', ['id_order' => $values['id'], 'type' => InvoicePDFAttachment::getType()]))
->attr('target', '_blank')
->text($values['invoice_no']);
}
public function renderDropshipment(array $values): HTML
{
return HTML::create('a')
->attr('href', 'javascript:nw(\'Dropshipment\', '.$values['dropship_id'].')')
->text($values['dropship_name']);
}
public function renderSeller(array $values): HTML
{
return HTML::create('a')
->attr('href', 'javascript:nw(\'sellers\', '.$values['seller_id'].')')
->text($values['seller_name']);
}
public function renderOrderSource(array $values): string
{
return OrderInfo::getOrderSources()[$values['source']] ?? '';
}
public function renderStatusPaid($values, $column)
{
$value = $this->renderCell($values, $column);
if (in_array($value, [Order::STATUS_OVERPAID, Order::STATUS_UNDERPAID])) {
if ($value == Order::STATUS_OVERPAID) {
$tooltip = translate('statusOverPaid', 'orders');
} else {
$tooltip = translate('statusUnderPaid', 'orders');
}
return $this->renderIcon('warning', 'Ne', $tooltip);
} else {
return $this->renderBoolean($values, $column);
}
}
public function renderPackage($values, $column)
{
if (empty($values['package_id'])) {
return '';
}
$delivery = \Delivery::getClass($values['class']);
$link = $delivery->getTrackAndTraceLink($values['package_id']) ?? '';
return HTML::create('a')
->attr('href', $link)
->attr('target', '_blank')
->text($values['package_id']);
}
public function renderUserNote($values, $column)
{
if (!empty($values['invoice_email'])) {
if ($note = $this->selectSQL('users', ['email' => $values['invoice_email']], ['note'])->fetchColumn()) {
return $note;
}
}
return '';
}
public function renderItems($values, $column)
{
$items = sqlQueryBuilder()->select('oi.descr, oi.pieces, oi.id_product, oi.id_variation')
->from('order_items', 'oi')
->where(Op::equals(['id_order' => $values['id']]))
->execute()
->fetchAll();
$output = HTML::create('span');
$idProductIn = getVal('productId');
$idProductsIn = getVal('products', default: []);
$idProductIn && $idProductsIn[] = $idProductIn;
foreach ($items as $item) {
$searchId = $item['id_product'].($item['id_variation'] ? '-'.$item['id_variation'] : '');
if ($item['id_product'] ?? false) {
$output
->tag('div')
->text(floatval($item['pieces']).'x ')
->tag('a')
->attr('href', 'javascript:nw(\'product\', \''.$item['id_product'].'\')')
->tag(in_array($searchId, $idProductsIn) || in_array($item['id_product'], $idProductsIn) ? 'strong' : 'span')
->text($item['descr'])
->end()
->end()
->end();
} else {
$output
->tag('div')
->text(floatval($item['pieces']).'x '.$item['descr'])
->end();
}
}
return $output;
}
public function renderDiscounts($values, $column)
{
$output = HTML::create('span');
$used_order_discounts = $this->orderInfo->getUsedDiscounts($values['id']);
foreach ($used_order_discounts as $id => $name) {
$output->tag('div')->tag('a')
->attr('href', "javascript:nw('OrderDiscounts', '{$id}')")
->attr('title', translate('showDiscount', 'OrderDiscounts'))
->tag('span')->class('badge badge-primary badge-light')
->text($name)
->end()->end()->end();
}
return $output;
}
public function renderDelivery($values, $column)
{
$delivery = $values['delivery_type'];
if (!empty($values['id_delivery'])) {
$delivery = $values['payment_name'].' - '.$values['delivery_name'];
}
$styles = $this->getStyles();
$delivery_class = 'delivery';
foreach ($styles as $id => $style) {
if (!empty($style['id_delivery']) && ($style['id_delivery'] == $values['id_delivery'])) {
$delivery_class = $id;
}
}
foreach ($styles as $id => $style) {
if ($style['match'] && (stripos($values['delivery_type'], $style['match']) !== false || stripos($style['match'], $values['delivery_type'] ?? '') !== false) && $style['value']) {
$delivery_class = $id;
}
}
return $this->renderBadge($delivery, 'badge-default badge-'.$delivery_class, null);
}
public function renderFlags($values, $column)
{
$cfg = \KupShop\KupShopBundle\Config::get();
$flags = $this->getListRowValue($values, $column['field']);
if (empty($flags)) {
return '';
}
$flags = preg_split('/,/', $flags);
$ret = [];
foreach (array_intersect($flags, array_keys($cfg['Order']['Flags'])) as $flag) {
$ret[] = HTML::create('span')
->class('badge badge-pastel-default')
->tag('span')->class('tooltip-text')->text($cfg['Order']['Flags'][$flag]['name'] ?? $flag)->end()
->tag('span')->class('badge-text')->text($flag)->end();
}
return $ret;
}
public function getRowClass($values)
{
$class = '';
if ($values['status_storno'] == 1) {
$class .= ' storno';
}
$class .= " status{$values['status']}";
return $class;
}
public function getDeliveryClass($values)
{
$styles = $this->getStyles();
foreach ($styles as $id => $style) {
if (!empty($style['id_delivery']) && ($style['id_delivery'] == $values['id_delivery'])) {
return 'delivery '.$id;
}
}
foreach ($styles as $id => $style) {
if ($style['match'] && (stripos($values['delivery_type'], $style['match']) !== false || stripos($style['match'], $values['delivery_type'] ?? '') !== false)) {
return 'delivery '.$id;
}
}
return 'delivery ';
}
public function renderName($values, $column)
{
$parts = [];
$name = $this->getListRowValue($values, $column['field']);
$surname = $this->getListRowValue($values, 'invoice_surname');
$company = $this->getListRowValue($values, 'invoice_firm');
if ($company) {
$parts[] = $company;
}
if ($name || $surname) {
$parts[] = join(' ', [$surname, $name]);
}
return join(', ', $parts);
}
public function renderCode($values, $column)
{
return $this->getListRowValue($values, 'order_no');
}
public function renderStatus($values, $column)
{
global $cfg;
$status = $this->getListRowValue($values, $column['field']);
if ($values['status_storno'] == 1) {
return $this->renderBadge($cfg['Order']['Status']['storno'][$values['status_storno']], 'badge-danger', null);
}
return $this->renderBadge($cfg['Order']['Status']['global'][$status], 'badge-default status-'.$status, null);
}
public function getStyles()
{
if (isset($this->styles)) {
return $this->styles;
}
$styles = [];
$qb = sqlQueryBuilder();
if (findModule('eshop_delivery')) {
$qb->select('dt.id', 'CONCAT_WS(" - ", p.name, d.name) AS name', 'dt.format')
->from(getTableName('delivery_type'), 'dt')
->leftJoin('dt', getTableName('delivery_type_delivery'), 'd', 'dt.id_delivery=d.id')
->leftJoin('dt', getTableName('delivery_type_payment'), 'p', 'dt.id_payment=p.id')
->orderBy('vat', 'ASC');
foreach ($qb->execute() as $row) {
$styles["delivery{$row['id']}"] = ['match' => $row['name'], 'id_delivery' => $row['id'], 'value' => "{$row['format']}"];
}
}
$this->styles = $styles;
return $this->styles;
}
public function get_vars()
{
/** @var \KupShop\ElninoBundle\Query\QueryBuilder $qb */
$qb = sqlQueryBuilder();
$vars = parent::get_vars();
$vars['styles'] = $this->getStyles();
$pid = getVal('productId');
$vid = getVal('variationId');
$sold = getVal('sold');
if (!empty($sold) && !empty($pid)) {
$qb->select('YEAR(o.date_created) as year', 'SUM(oi.pieces) as count')
->from(getTableName('order_items'), 'oi')
->leftJoin('oi', getTableName('orders'), 'o', 'oi.id_order=o.id')
->where('oi.id_product='.$pid.' AND o.status_storno=0')
->groupBy('YEAR(o.date_created)')
->orderBy('year', 'DESC');
if (!empty($vid)) {
$qb->andWhere(Op::equals(['oi.id_variation' => $vid]));
}
$SQL = $qb->execute();
$vars['sold'] = [];
$vars['sold_total'] = 0;
foreach ($SQL as $row) {
$vars['sold'][] = $row;
$vars['sold_total'] += $row['count'];
}
}
return $vars;
}
public function renderPrice($values, $column)
{
$totalPrice = toDecimal($values['total_price']);
if (!empty($values['currency_rate'])) {
$totalPrice = $totalPrice->mul(toDecimal($values['currency_rate']));
}
$this->orderTotalPriceSum = $this->orderTotalPriceSum->add($totalPrice);
return parent::renderPrice($values, $column);
}
// renderFormatPrice na OrdersListu se pouziva pouze pro total_price
// total_price nechceme zaokrouhlovat = zobrazit jak je ulozena na objednavce
public function renderFormatPrice($values, $column)
{
$value = $this->renderCell($values, $column);
$params = [
'printcurrency' => false,
'ceil' => false,
'decimal' => 'dynamic',
];
$currencyContext = ServiceContainer::getService(CurrencyContext::class);
$currency = $currencyContext->getActive();
if (!empty($values['currency'])) {
$currency = $currencyContext->getAll()[$values['currency']];
$params['currency'] = $currency;
}
return [
printPrice($value, $params).' ',
HTML::create('span')->class('currency')->text($currency->getSymbol()),
];
}
public function renderPriceLevel(array $values, array $column): HTML
{
$data = json_decode($values['note_admin'] ?: '', true) ?: [];
if (!empty($data['price_level']['name'])) {
return HTML::create('a')
->attr('href', 'javascript:nw(\'pricelevel\', '.$data['price_level']['id'].')')
->attr('title', $data['price_level']['name'])
->text($data['price_level']['name']);
}
return HTML::create('span')
->text('');
}
public function getTotalPriceSum()
{
return $this->orderTotalPriceSum;
}
public function getFilterQuery(): Query\QueryBuilder
{
$qb = parent::getFilterQuery();
$qb = $this->ordersListFilter->addQueryBuilderParams($qb, $_GET);
if (findModule(Modules::POS) && $qb->getQueryPart('where') == null) {
if (getVal('pos_orders')) {
$qb->andWhere('o.pos >= 1');
} else {
$qb->andWhere('o.pos = 0 OR o.pos is null');
}
}
return $qb;
}
}