first commit
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\Actions;
|
||||
|
||||
use KupShop\AdminBundle\Admin\Actions\ActionResult;
|
||||
use KupShop\PreordersBundle\Entity\UserPreorder;
|
||||
|
||||
class CreateOrderAction extends UserPreorderAction
|
||||
{
|
||||
private ?bool $enabled = null;
|
||||
|
||||
public function execute(&$data, array $config, string $type): ActionResult
|
||||
{
|
||||
return new ActionResult(true);
|
||||
}
|
||||
|
||||
public function getLaunchHandler(): string
|
||||
{
|
||||
return "nw('preordersCreateOrder', '', 'ID={$this->getId()}&acn=edit',);";
|
||||
}
|
||||
|
||||
public function hasDialog(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function checkEnabled(): bool
|
||||
{
|
||||
$script = str_replace('.php', '', (string) getVal('s', default: ''));
|
||||
if (!in_array($script, $this->getTypes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ids = explode('-', $this->getId() ?? '');
|
||||
if (count($ids) < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->enabled === null) {
|
||||
[$userId, $dateId] = $ids;
|
||||
|
||||
$preorder = new UserPreorder((int) $userId, (int) $dateId);
|
||||
$date = $preorder->getPreorderDate();
|
||||
|
||||
$this->enabled = \DateTimeImmutable::createFromFormat('Y-m-d', $date['date_end'])
|
||||
<= (new \DateTimeImmutable())->sub(\DateInterval::createFromDateString('1 day'));
|
||||
}
|
||||
|
||||
return $this->enabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\Actions;
|
||||
|
||||
use KupShop\AdminBundle\Admin\Actions\ActionResult;
|
||||
use KupShop\AdminBundle\Admin\Actions\IAction;
|
||||
use KupShop\PreordersBundle\Service\OrderCreator;
|
||||
|
||||
class CreateOrderListAction extends UserPreorderAction implements IAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly OrderCreator $orderCreator,
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(&$data, array $config, string $type): ActionResult
|
||||
{
|
||||
$userPreorder = $this->getUserPreorder();
|
||||
$date = $userPreorder->getPreorderDate();
|
||||
|
||||
$enabled = \DateTimeImmutable::createFromFormat('Y-m-d', $date['date_end'])
|
||||
<= (new \DateTimeImmutable())->sub(\DateInterval::createFromDateString('1 day'));
|
||||
|
||||
if (!$enabled) {
|
||||
return new ActionResult(false, 'Objednávku nelze vytvořit z předobjednávky uživatele, která je stále otevřená.');
|
||||
}
|
||||
|
||||
$itemsToAdd = [];
|
||||
foreach ($userPreorder->getItems() as $item) {
|
||||
$piecesRemaining = $item['pieces'] - $item['pieces_sent'];
|
||||
if ($piecesRemaining <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$itemsToAdd[$item['id']] = $piecesRemaining;
|
||||
}
|
||||
|
||||
$order = $this->orderCreator->createOrder($userPreorder, $itemsToAdd);
|
||||
|
||||
return new ActionResult(true, "Objednávka {$order->order_no} úspěšně vytvořena.");
|
||||
}
|
||||
|
||||
public function showInMassEdit(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function checkEnabled(): bool
|
||||
{
|
||||
return getVal('s') === 'listEdit.php' || getVal('acn') === 'getActionSnippet';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\Actions;
|
||||
|
||||
use KupShop\AdminBundle\Admin\Actions\ActionResult;
|
||||
use KupShop\PreordersBundle\Service\DynamicContexts;
|
||||
use KupShop\PreordersBundle\Service\PreorderItemsUpdater;
|
||||
|
||||
class RecalculatePreorderPiecesAction extends UserPreorderAction
|
||||
{
|
||||
public function __construct(
|
||||
private readonly PreorderItemsUpdater $itemsUpdater,
|
||||
private readonly DynamicContexts $contexts,
|
||||
) {
|
||||
}
|
||||
|
||||
public function execute(&$data, array $config, string $type): ActionResult
|
||||
{
|
||||
try {
|
||||
$userPreorder = $this->getUserPreorder();
|
||||
|
||||
$this->contexts->activateUserPreorder($userPreorder);
|
||||
$this->itemsUpdater->recalculatePiecePrices($userPreorder);
|
||||
} catch (\Throwable $e) {
|
||||
return new ActionResult(false, $e->getMessage());
|
||||
}
|
||||
|
||||
return new ActionResult(true);
|
||||
}
|
||||
|
||||
protected function checkEnabled(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\Actions;
|
||||
|
||||
use KupShop\AdminBundle\Admin\Actions\AbstractAction;
|
||||
use KupShop\AdminBundle\Admin\Actions\IAction;
|
||||
use KupShop\PreordersBundle\Entity\UserPreorder;
|
||||
|
||||
abstract class UserPreorderAction extends AbstractAction implements IAction
|
||||
{
|
||||
private ?UserPreorder $userPreorder = null;
|
||||
|
||||
public function getTypes(): array
|
||||
{
|
||||
return ['preordersUsers'];
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
$split = explode('\\', static::class);
|
||||
|
||||
$className = lcfirst($split[count($split) - 1]);
|
||||
|
||||
return translate($className, 'preordersUsers', false, true);
|
||||
}
|
||||
|
||||
protected function getUserPreorder(): UserPreorder
|
||||
{
|
||||
return $this->userPreorder ?? new UserPreorder(...array_map(intval(...), explode('-', $this->getId())));
|
||||
}
|
||||
|
||||
public function isVisible(): bool
|
||||
{
|
||||
return $this->checkEnabled();
|
||||
}
|
||||
|
||||
public function isEnabled(): bool
|
||||
{
|
||||
return $this->checkEnabled();
|
||||
}
|
||||
|
||||
abstract protected function checkEnabled(): bool;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\Tabs;
|
||||
|
||||
use KupShop\AdminBundle\Admin\WindowTab;
|
||||
|
||||
class PreordersSettingsTab extends WindowTab
|
||||
{
|
||||
protected $title = 'flapPreorders';
|
||||
|
||||
protected $template = 'tabs/settingsTab.tpl';
|
||||
|
||||
public static function getTypes(): array
|
||||
{
|
||||
return [
|
||||
'settings' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public function getLabel(): string
|
||||
{
|
||||
return 'Předobjednávky';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
$txt_str['preorders'] = [
|
||||
'titleAdd' => 'Definice nové předobjednávky',
|
||||
'titleEdit' => 'Předobjednávka',
|
||||
|
||||
'toolbar_add' => 'Vytvořit novou předobjednávku',
|
||||
'toolbar_list' => 'Předobjednávky',
|
||||
|
||||
'flapMain' => 'Nastavení',
|
||||
'flapProducts' => 'Produkty',
|
||||
'flapDiscountLevels' => 'Slevové hladiny',
|
||||
'flapDates' => 'Termíny',
|
||||
|
||||
'name' => 'Název',
|
||||
'usersGroup' => 'Skupiny uživatelů',
|
||||
'pricelist' => 'Ceník',
|
||||
'pricelistEmptyChoice' => 'Žádný ceník',
|
||||
'emptyChoice' => 'Nevybráno',
|
||||
'priceLevel' => 'Cenová hladina',
|
||||
'addPreorderDate' => 'Přidat termín předobjednávky',
|
||||
'priceFrom' => 'Cena od',
|
||||
'priceTo' => 'Cena do',
|
||||
'addDynamicPrice' => 'Přidat hladinu',
|
||||
'base' => 'Základní',
|
||||
'preorder' => 'Předobjednávka',
|
||||
'preorders' => 'Předobjednávky',
|
||||
'minPrice' => 'Minimální hodnota předobjednávky',
|
||||
'multipleDatesSinglePage' => 'Více termínů na jedné stránce',
|
||||
'multipleDatesSinglePageTooltip' => 'Zákazníkům se budou všechny termíny patřící k jedné předobjednávce zobrazovat na jedné stránce.',
|
||||
'showHidden' => 'Umožnit předobjednávat skryté produkty',
|
||||
];
|
||||
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
$txt_str['preordersCreateOrder'] = [
|
||||
'titleEdit' => 'Vytvoření objednávky',
|
||||
'buttonAddValue' => 'Přidat všechny produkty do objednávky',
|
||||
];
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
$txt_str['preordersDates'] = [
|
||||
'titleAdd' => 'Nový termín předobjednávky',
|
||||
'titleEdit' => 'Úprava termínu',
|
||||
'toolbar_list' => 'Termíny předobjednávek',
|
||||
'toolbar_add' => 'Přidat termín předobjednávky',
|
||||
'MenuHelp' => 'Nápověda',
|
||||
|
||||
'flapMain' => 'Nastavení',
|
||||
'flapPreordersCreated' => 'Vytvořené předobjednávky',
|
||||
'dateEnd' => 'Datum ukončení pro zákazníky',
|
||||
'dateName' => 'Název termínu',
|
||||
'dateStart' => 'Datum otevření termínu',
|
||||
'dateShipment' => 'Datum expedice',
|
||||
'preorder' => 'Předobjednávka',
|
||||
'preorderCreateBtn' => 'Vytvořit novou',
|
||||
'description' => 'Popis termínu',
|
||||
|
||||
'labelProducts' => 'Produkty',
|
||||
'addProduct' => 'Přidat produkt',
|
||||
|
||||
'customerName' => 'Zákazník',
|
||||
'priceTotal' => 'Celková cena',
|
||||
'priceRemaining' => 'Cena zbylého zboží',
|
||||
'userAddress' => 'Doručovací adresa',
|
||||
|
||||
'dateStartTooltip' => 'Zákazníci předobjednávku uvidí a budou moci objednávat od tohoto dne.',
|
||||
'dateEndTooltip' => 'Zákazníci mohou objednávat do půlnoci tohoto dne.',
|
||||
'dateShipmentTooltip' => 'Slouží pouze pro informování zákazníků, kdy mohou předobjednané produkty očekávat.',
|
||||
|
||||
'flapProducts' => 'Produkty',
|
||||
|
||||
'date_end' => 'Datum ukončení předobjednávání',
|
||||
'date_start' => 'Datum zahájení předobjednávání',
|
||||
'date_shipment' => 'Datum expedice',
|
||||
];
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
$txt_str['preordersItems'] = [
|
||||
'toolbar_list' => 'Seznam produktů',
|
||||
|
||||
'order' => 'Objednávka č.',
|
||||
'name' => 'Jméno a příjmení',
|
||||
'price' => 'Cena objednávky',
|
||||
'totalPieces' => 'Celkem předobjednáno',
|
||||
'sentPieces' => 'Kusů odesláno',
|
||||
'totalPrice' => 'Celková cena',
|
||||
'photo' => 'Fotka produktu',
|
||||
|
||||
'title' => 'Název',
|
||||
'code' => 'Kód',
|
||||
'vat' => 'Daň',
|
||||
'discount' => 'Sleva z ceny',
|
||||
'producer' => 'Výrobce',
|
||||
'inStoreMin' => 'Min. skladem',
|
||||
'piecesInStore' => 'Kusů na skladě',
|
||||
'piecesSold' => 'Prodáno',
|
||||
'deliveryTime' => 'Dostupnost',
|
||||
'campaign' => 'Kampaň',
|
||||
'statusNews' => 'Novinky',
|
||||
'statusDiscount' => 'Akce / Slevy',
|
||||
'statusSoldout' => 'Výprodeje',
|
||||
'statusLeadPage' => 'Na úvodní straně',
|
||||
'statusBestSeller' => 'Nejprodávanější',
|
||||
'dateAdded' => 'Datum přidání',
|
||||
'figure' => 'Zobrazení zboží',
|
||||
'annotation' => 'Anotace',
|
||||
'descriptionLead' => 'Popis zboží',
|
||||
'descriptionProperties' => 'Rozšiřující popis',
|
||||
'allParameteres' => 'Všechny parametry',
|
||||
'activeParameteres' => 'Použité v sekcích a u výrobce',
|
||||
'producerParameteres' => 'Použité u výrobce',
|
||||
'parameteresInSections' => 'Použité v sekci',
|
||||
'noParameters' => 'Žádné parametry',
|
||||
'sectionRoot' => 'Sekce',
|
||||
|
||||
'filterProduct' => 'Podle produktu',
|
||||
'products' => 'Předobjednané předměty',
|
||||
'productList' => 'Seznam produktů',
|
||||
'addProduct' => 'Přidat produkt',
|
||||
'help' => 'Nápověda',
|
||||
'filter' => 'Filtrování',
|
||||
'filterSection' => 'Podle sekcí',
|
||||
'filterProducer' => 'Podle výrobců',
|
||||
'filterCampaign' => 'Podle kampaně',
|
||||
'filterHidden' => 'Nezobrazované produkty',
|
||||
'filterOld' => 'Ukončený prodej',
|
||||
'filterMisplaced' => 'Nezařazené produkty',
|
||||
'filterNoImg' => 'Produkty bez obrázků',
|
||||
'filterImg' => 'Produkty s obrázky',
|
||||
'filterIncompleteRelated' => 'Neúplný stav souvisejícího zboží',
|
||||
'filterInStore' => 'Produkty skladem',
|
||||
'massEdit' => 'Hromadná úprava',
|
||||
'massEditProduct' => 'Hromadná úprava produktů',
|
||||
'editationPrice' => 'Úprava cen',
|
||||
'editationStock' => 'Úprava skladu',
|
||||
'editationText' => 'Úprava textů',
|
||||
'visibleProductsWithHiddenProducer' => 'Viditelné produkty se skrytým výrobcem',
|
||||
'search' => 'Vyhledávání',
|
||||
'searchId' => 'Podle čísla',
|
||||
'searchCode' => 'Podle kódu',
|
||||
'searchName' => 'Podle názvu',
|
||||
'searchEan' => 'Podle EANu',
|
||||
'inclOld' => 'Včetně ukončeného prodeje',
|
||||
'searchCodeOrId' => 'Podle kódu / čísla',
|
||||
'supplierCodes' => 'Kódy dodavatelů',
|
||||
'generateCode' => 'Vygenerovat kód',
|
||||
'generateEan' => 'Vygenerovat EAN',
|
||||
'priceWithoutVat' => 'MOC bez DPH',
|
||||
'priceForDiscount' => 'Cena pro slevu',
|
||||
'normalPrice' => 'MOC s DPH',
|
||||
'variation' => 'Varianta',
|
||||
'shortDescription' => 'Popis',
|
||||
'longDescription' => 'Dlouhý popis',
|
||||
'stockInDate' => 'Datum naskladnění',
|
||||
'showOnlyRemaining' => 'Zobrazit pouze neuspokojené',
|
||||
'pieces_sent' => 'ks odesláno',
|
||||
'pieces' => 'ks předobjednáno',
|
||||
'currency' => 'Měna',
|
||||
'preorder' => 'Předobjednávka',
|
||||
'category' => 'Kategorie',
|
||||
];
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
$txt_str['preordersUsers'] = [
|
||||
'toolbar_list' => 'Seznam uživatelů',
|
||||
'toolbar_add' => 'Přidat termín předobjednávky',
|
||||
|
||||
'titleEdit' => 'Shrnutí předobjednávky uživatele',
|
||||
'flapMain' => 'Shrnutí předobjednávky uživatele',
|
||||
'flapMessages' => 'Komunikace',
|
||||
'flapOrders' => 'Vytvořené objednávky',
|
||||
|
||||
'titleUser' => 'Předobjednávka uživatele',
|
||||
'titleOrderedProducts' => 'Objednané zboží',
|
||||
'user' => 'Uživatel',
|
||||
'dateTitle' => 'Termín',
|
||||
'item' => 'Název',
|
||||
'piecePrice' => 'Jednotková cena',
|
||||
'piecesSent' => 'Ks (odesláno / celkem)',
|
||||
'priceRemaining' => 'Cena (zbývá / celkem)',
|
||||
'piecesToAdd' => 'ks přidat do objednávky',
|
||||
'saveItemPieces' => 'Uložit počty ks produktů',
|
||||
'createOrderAction' => 'Vytvořit objednávku z předobjednávky',
|
||||
'recalculatePreorderPiecesAction' => 'Přepočítat jednotkové ceny',
|
||||
'recalculateAreYouSure' => 'Opravdu chcete předpočíat jednotkové ceny podle aktuálního nastavení předobjednávky?',
|
||||
|
||||
'messageDate' => 'Datum',
|
||||
'messageText' => 'Text zprávy',
|
||||
'messageSentBy' => 'Odeslal',
|
||||
'newMessage' => 'Nová zpráva',
|
||||
|
||||
'notification' => 'E-mail odeslán',
|
||||
'previousMessages' => 'Historie komunikace',
|
||||
|
||||
'notificationNotNotified' => 'Ne',
|
||||
'notificationEmailNotified' => 'Ano',
|
||||
'dateShipmentAbbr' => 'exp.:',
|
||||
'createOrderListAction' => 'Vytvořit objednávku',
|
||||
|
||||
'variationNotSelected' => 'Položka <a href="#preorder-item-%d">"%s"</a> nemá vybranou variantu, ale produkt má více variant. Při vytváření objednávky bude vybrána první varianta, případně ji změňte v objednávce.',
|
||||
'variationNotSelectedTooltip' => 'Položka nemá vybranou variantu.',
|
||||
];
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use KupShop\AdminBundle\AdminList\BaseList;
|
||||
use Query\Operator as Op;
|
||||
use Query\QueryBuilder;
|
||||
|
||||
class PreordersDatesList extends BaseList
|
||||
{
|
||||
protected ?string $tableAlias = 'pd';
|
||||
|
||||
protected $tableDef = [
|
||||
'id' => 'id',
|
||||
'fields' => [
|
||||
'Číslo' => ['field' => 'id', 'spec' => 'pd.id'],
|
||||
'Název předobjednávky' => ['field' => 'name', 'spec' => 'po.name'],
|
||||
'Popis' => ['field' => 'description', 'spec' => 'pd.description', 'render' => 'renderHTML'],
|
||||
'Datum otevření' => ['field' => 'date_start', 'spec' => 'pd.date_start', 'render' => 'renderDate'],
|
||||
'Datum skrytí' => ['field' => 'date_end', 'spec' => 'pd.date_end', 'render' => 'renderDate'],
|
||||
'Datum expedice' => ['field' => 'date_shipment', 'spec' => 'pd.date_shipment'],
|
||||
'Cena zbylého zboží' => ['field' => 'price_remaining', 'spec' => 'totals.price_remaining', 'render' => 'renderPrice'],
|
||||
],
|
||||
];
|
||||
|
||||
public function getQuery()
|
||||
{
|
||||
$qb = sqlQueryBuilder()
|
||||
->from('preorders_dates', 'pd')
|
||||
->leftJoin('pd', 'preorders', 'po', 'pd.id_preorder = po.id');
|
||||
|
||||
$totals = sqlQueryBuilder()
|
||||
->select(
|
||||
'pi.id_preorder_date AS id',
|
||||
'SUM(pi.piece_price * currencies.rate * (pi.pieces - pi.pieces_sent)) AS price_remaining',
|
||||
)
|
||||
->from('preorders_items', 'pi')
|
||||
->leftJoin('pi', 'currencies', 'currencies', 'pi.currency = currencies.id')
|
||||
->groupBy('pi.id_preorder_date');
|
||||
|
||||
$qb->leftJoinSubQuery('pd', $totals, 'totals', 'totals.id = pd.id');
|
||||
|
||||
return $this->getFilterQueryParams($qb);
|
||||
}
|
||||
|
||||
public function getFilterQueryParams(QueryBuilder $qb): QueryBuilder
|
||||
{
|
||||
if ($ids = getVal('id_preorder_date')) {
|
||||
$qb->andWhere(Op::inIntArray($ids, 'pd.id_preorder_date'));
|
||||
}
|
||||
|
||||
if ($ids = getVal('id_preorder')) {
|
||||
$qb->andWhere(Op::inIntArray($ids, 'pd.id_preorder'));
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
||||
return PreordersDatesList::class;
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use KupShop\AdminBundle\AdminList\BaseList;
|
||||
use Query\Operator;
|
||||
use Query\QueryBuilder;
|
||||
|
||||
class PreordersItemsList extends BaseList
|
||||
{
|
||||
protected $tableName = 'preorders_items';
|
||||
protected ?string $tableAlias = 'pi';
|
||||
|
||||
protected $tableDef = [
|
||||
'id' => 'id',
|
||||
'fields' => [
|
||||
'Název' => ['field' => 'title', 'size' => 3, 'type' => 'products', 'spec' => 'p.title, p.id AS id'],
|
||||
'Varianta' => ['field' => 'variation_title', 'spec' => 'COALESCE(pv.title, "Bez varianty") AS variation_title'],
|
||||
'Kód' => ['field' => 'code', 'spec' => 'COALESCE(pv.code, p.code) AS code'],
|
||||
'EAN' => ['field' => 'ean', 'spec' => 'COALESCE(pv.ean, p.ean) AS ean'],
|
||||
'Číslo produktu' => ['field' => 'p.id'],
|
||||
|
||||
'Celkem (ks)' => ['field' => 'pieces', 'spec' => 'SUM(pi.pieces) AS pieces'],
|
||||
'Zbývá odeslat (ks)' => ['field' => 'pieces_remaining', 'spec' => 'SUM(pi.pieces - pi.pieces_sent) AS pieces_remaining'],
|
||||
'Odesláno (ks)' => ['field' => 'pieces_sent', 'spec' => 'SUM(pi.pieces_sent) AS pieces_sent'],
|
||||
|
||||
'Průměrná cena za ks' => ['field' => 'average_price', 'spec' => 'AVG(pi.piece_price * currencies.rate) AS average_price', 'render' => 'renderPrice'],
|
||||
'Celková cena' => ['field' => 'total_price', 'spec' => 'SUM(pi.piece_price * pi.pieces * currencies.rate) AS total_price', 'render' => 'renderPrice'],
|
||||
|
||||
'Produktová cena (bez DPH)' => ['field' => 'product_price', 'spec' => 'COALESCE(pv.price, p.price) AS product_price', 'render' => 'renderPrice'],
|
||||
'Rozdíl předobjednávkové a produktové ceny' => ['field' => 'price_diff', 'spec' => '(AVG(pi.piece_price * currencies.rate) - COALESCE(pv.price, p.price)) AS price_diff', 'render' => 'renderPrice'],
|
||||
'Na skladě' => ['field' => 'in_store', 'spec' => 'COALESCE(pv.in_store, p.in_store) AS in_store'],
|
||||
],
|
||||
];
|
||||
|
||||
public function getQuery(): QueryBuilder
|
||||
{
|
||||
$qb = sqlQueryBuilder()
|
||||
->from($this->tableName, $this->tableAlias)
|
||||
->leftJoin('pi', 'products', 'p', 'pi.id_product = p.id')
|
||||
->leftJoin('pi', 'products_variations', 'pv', 'pi.id_variation = pv.id')
|
||||
->leftJoin('pi', 'currencies', 'currencies', 'pi.currency = currencies.id')
|
||||
->leftJoin('pi', 'preorders_dates', 'pd', 'pi.id_preorder_date = pd.id')
|
||||
->addGroupBy('pi.id_product')
|
||||
->addGroupBy('pi.id_variation');
|
||||
|
||||
$qb->andWhere($this->getFilterSpec());
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
private function getFilterSpec(): \Closure
|
||||
{
|
||||
return function (QueryBuilder $qb) {
|
||||
$equals = [];
|
||||
|
||||
if ($preorder = getVal('id_preorder')) {
|
||||
$equals[] = Operator::inIntArray($preorder, 'pd.id_preorder');
|
||||
}
|
||||
|
||||
if ($date = getVal('id_preorder_date')) {
|
||||
$equals[] = Operator::inIntArray($date, 'pi.id_preorder_date');
|
||||
}
|
||||
|
||||
if ($user = getVal('id_user')) {
|
||||
$equals[] = Operator::inIntArray($user, 'pi.id_user');
|
||||
}
|
||||
|
||||
if (getVal('only_remaining', default: 'N') === 'Y') {
|
||||
$qb->andWhere('(pi.pieces - pi.pieces_sent) <> 0');
|
||||
}
|
||||
|
||||
$qb->andWhere(Operator::andX($equals));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return PreordersItemsList::class;
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use KupShop\AdminBundle\AdminList\BaseList;
|
||||
|
||||
class PreordersList extends BaseList
|
||||
{
|
||||
protected $tableDef = [
|
||||
'id' => 'id',
|
||||
'fields' => [
|
||||
'Název' => ['field' => 'name', 'spec' => 'p.name'],
|
||||
'Číslo' => ['field' => 'id', 'spec' => 'p.id'],
|
||||
'Konec posledního termínu' => ['field' => 'pd.last_end', 'render' => 'renderDate', 'spec' => 'pd.last_end'],
|
||||
'Počet termínů' => ['field' => 'count', 'spec' => 'COALESCE(pd.date_count, 0) AS count'],
|
||||
],
|
||||
];
|
||||
|
||||
public function getQuery()
|
||||
{
|
||||
$counts = sqlQueryBuilder()
|
||||
->select('pd.id_preorder',
|
||||
'COUNT(pd.id) AS date_count',
|
||||
'MAX(pd.date_end) AS last_end')
|
||||
->from('preorders_dates', 'pd')
|
||||
->groupBy('pd.id_preorder');
|
||||
|
||||
return sqlQueryBuilder()
|
||||
->from('preorders', 'p')
|
||||
->leftJoinSubQuery('p', $counts, 'pd', 'p.id = pd.id_preorder');
|
||||
}
|
||||
}
|
||||
|
||||
return PreordersList::class;
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use Query;
|
||||
|
||||
global $cfg;
|
||||
|
||||
require_once $cfg['Path']['shared_version'].'admin/lists/OrdersList.php';
|
||||
|
||||
class PreordersOrdersCreatedList extends \OrdersList
|
||||
{
|
||||
public function customizeTableDef($tableDef): array
|
||||
{
|
||||
$tableDef = parent::customizeTableDef($tableDef);
|
||||
|
||||
foreach ($tableDef['fields'] as &$field) {
|
||||
if ($field['translation_section'] ?? false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field['translation_section'] = 'orders';
|
||||
}
|
||||
|
||||
return $tableDef;
|
||||
}
|
||||
|
||||
public function getFilterQuery(): Query\QueryBuilder
|
||||
{
|
||||
$qb = parent::getFilterQuery();
|
||||
$qb->andWhere("JSON_VALUE(o.note_admin, '$.preorders.id_preorder_date') IS NOT NULL");
|
||||
|
||||
if ($id = getVal('id_preorder_date')) {
|
||||
$qb->andWhere("JSON_VALUE(o.note_admin, '$.preorders.id_preorder_date') = :id_preorder_date")
|
||||
->addParameters(['id_preorder_date' => $id], ['id_preorder_date' => ParameterType::INTEGER]);
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
||||
return PreordersOrdersCreatedList::class;
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use Doctrine\DBAL\ParameterType;
|
||||
use KupShop\AdminBundle\AdminList\BaseList;
|
||||
use KupShop\KupShopBundle\Util\HtmlBuilder\HTML;
|
||||
use Query\Operator as Op;
|
||||
use Query\QueryBuilder;
|
||||
|
||||
class PreordersUsersList extends BaseList
|
||||
{
|
||||
protected $showMassEdit = true;
|
||||
|
||||
protected $tableDef = [
|
||||
'fields' => [
|
||||
'Uživatel' => ['field' => 'user', 'spec' => "CONCAT_WS(' ', IF(u.firm = '', '', CONCAT(u.firm, ',')), u.name, u.surname) AS user"],
|
||||
'Číslo předobjednávky' => ['field' => 'po.id_preorder', 'spec' => 'po.id_preorder'],
|
||||
'Číslo termínu' => ['field' => 'id_preorder_date', 'spec' => 'po.id_preorder_date'],
|
||||
|
||||
'Název předobjednávky' => ['field' => 'preorder', 'spec' => 'po.name AS preorder'],
|
||||
|
||||
'Termín' => ['field' => 'preorder_date', 'spec' => "CONCAT(DATE_FORMAT(date_start, '%d.%m.%Y'), ' - ', DATE_FORMAT(date_end, '%d.%m.%Y')) AS preorder_date"],
|
||||
'Začátek termínu' => ['field' => 'date_start', 'spec' => 'po.date_start', 'render' => 'renderDate'],
|
||||
'Konec termínu' => ['field' => 'date_end', 'spec' => 'po.date_end', 'render' => 'renderDate'],
|
||||
'Datum expedice' => ['field' => 'po.date_shipment', 'spec' => 'po.date_shipment'],
|
||||
|
||||
'Celková cena' => ['field' => 'price_total', 'spec' => 'SUM(po.piece_price * po.pieces) AS price_total', 'render' => 'renderPrice', 'fieldType' => BaseList::TYPE_PRICE, 'editable' => 'N'],
|
||||
'Cena zbylého zboží' => ['field' => 'price_remaining', 'spec' => 'SUM(po.piece_price * (po.pieces - po.pieces_sent)) AS price_remaining', 'render' => 'renderPrice', 'fieldType' => BaseList::TYPE_PRICE, 'editable' => 'N'],
|
||||
'Zprávy od zákazníka' => ['field' => 'history', 'spec' => 'pud.history', 'render' => 'renderUserMessages'],
|
||||
],
|
||||
'class' => 'getRowClass',
|
||||
];
|
||||
|
||||
public function getRowClass($values): string
|
||||
{
|
||||
$class = '';
|
||||
if ($values['price_remaining'] > 0) {
|
||||
$class .= ' danger';
|
||||
} elseif ($values['pieces'] <= 0) {
|
||||
$class .= ' info';
|
||||
} else {
|
||||
$class .= ' success';
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
public function renderPreorderDate($values, $column): string
|
||||
{
|
||||
$value = $this->renderCell($values, $column);
|
||||
|
||||
return "{$value} ({$this->renderDate($values, ['field' => 'date_start'])} – {$this->renderDate($values, ['field' => 'date_end'])})";
|
||||
}
|
||||
|
||||
public function renderUserMessages($values, $column)
|
||||
{
|
||||
$messages = json_decode($values['history'] ?: '[]', true);
|
||||
|
||||
$count = count(array_filter($messages, fn (array $m) => empty($m['admin'])));
|
||||
if ($count > 0) {
|
||||
return HTML::create('strong')
|
||||
->text($count);
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
public function getQuery(): QueryBuilder
|
||||
{
|
||||
$preordersQb = sqlQueryBuilder()
|
||||
->select('pi.*', 'po.name', 'pd.date_end', 'pd.date_start', 'pd.date_shipment', 'po.id AS id_preorder')
|
||||
->from('preorders_items', 'pi')
|
||||
->leftJoin('pi', 'preorders_dates', 'pd', 'pi.id_preorder_date = pd.id')
|
||||
->leftJoin('pd', 'preorders', 'po', 'pd.id_preorder = po.id');
|
||||
|
||||
$qb = sqlQueryBuilder()
|
||||
->select("CONCAT(u.id, '-', COALESCE(po.id_preorder_date, '')) AS id", 'po.currency')
|
||||
->from('users', 'u')
|
||||
->leftJoinSubQuery('u', $preordersQb, 'po', 'po.id_user = u.id')
|
||||
->leftJoin('po', 'preorders_users_data', 'pud', 'po.id_user = pud.id_user AND po.id_preorder_date = pud.id_preorder_date')
|
||||
->andWhere("u.figure = 'Y'")
|
||||
->addGroupBy('u.id')
|
||||
->addGroupBy('po.id_preorder_date');
|
||||
|
||||
return $this->applyCustomQueryFilters($qb);
|
||||
}
|
||||
|
||||
public function applyCustomQueryFilters(QueryBuilder $qb): QueryBuilder
|
||||
{
|
||||
$andEq = [];
|
||||
|
||||
if (getVal('id_preorder_date')) {
|
||||
$andEq['po.id_preorder_date'] = array_map(intval(...), getVal('id_preorder_date'));
|
||||
}
|
||||
|
||||
if (getVal('id_preorder')) {
|
||||
$andEq['po.id_preorder'] = array_map(intval(...), getVal('id_preorder'));
|
||||
}
|
||||
|
||||
if (getVal('id_user')) {
|
||||
$andEq['u.id'] = array_map(intval(...), getVal('id_user'));
|
||||
}
|
||||
|
||||
if (!empty($andEq)) {
|
||||
foreach ($andEq as $key => $ids) {
|
||||
$qb->andWhere(Op::inIntArray($ids, $key));
|
||||
}
|
||||
}
|
||||
|
||||
if (!getVal('allUsers')) {
|
||||
$qb->andWhere('po.pieces > 0');
|
||||
}
|
||||
|
||||
if ($groups = getVal('id_users_group')) {
|
||||
$permittedIds = sqlQueryBuilder()->select('id_user')
|
||||
->from('users_groups_relations')
|
||||
->andWhere(Op::inIntArray(
|
||||
array_map(intval(...), $groups),
|
||||
'id_group',
|
||||
));
|
||||
|
||||
$qb->andWhere('u.id IN ('.$permittedIds->getSQL().')')
|
||||
->addParameters($permittedIds->getParameters(), $permittedIds->getParameterTypes());
|
||||
}
|
||||
|
||||
if ($user = getVal('user')) {
|
||||
if (ctype_digit($user)) {
|
||||
$qb->andWhere('u.ico = :user_ico')
|
||||
->addParameters(['user_ico' => $user], [ParameterType::INTEGER]);
|
||||
} else {
|
||||
$userLikeFilter = '%'.htmlspecialchars($user).'%';
|
||||
$qb->andWhere(Op::like([
|
||||
'u.firm' => $userLikeFilter,
|
||||
'u.name' => $userLikeFilter,
|
||||
'u.surname' => $userLikeFilter,
|
||||
], 'OR'));
|
||||
}
|
||||
}
|
||||
|
||||
if (getVal('onlyClosed')) {
|
||||
$qb->andWhere('po.date_end <= NOW()');
|
||||
}
|
||||
|
||||
if (getVal('onlyUnsent')) {
|
||||
$ids = sqlQueryBuilder()->select('DISTINCT pi.id_preorder_date')
|
||||
->from('preorders_items', 'pi')
|
||||
->where('pi.pieces - pi.pieces_sent > 0')
|
||||
->execute()
|
||||
->fetchFirstColumn();
|
||||
|
||||
$qb->andWhere(Op::inIntArray($ids, 'po.id'));
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
||||
return PreordersUsersList::class;
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use KupShop\I18nBundle\Admin\lists\TranslateList;
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use KupShop\PreordersBundle\Translations\PreordersDatesTranslation;
|
||||
|
||||
class TranslatePreordersDatesList extends TranslateList
|
||||
{
|
||||
protected $listType = 'translatePreordersDates';
|
||||
protected $template = 'translateList/preordersDates.tpl';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->translation = ServiceContainer::getService(PreordersDatesTranslation::class);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function createQueryBuilder(): QueryBuilder
|
||||
{
|
||||
$qb = parent::createQueryBuilder();
|
||||
$qb->leftJoin('pd', 'preorders', 'po', 'pd.id_preorder = po.id')
|
||||
->addSelect('po.name AS preorder');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
|
||||
return TranslatePreordersDatesList::class;
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin\lists;
|
||||
|
||||
use KupShop\I18nBundle\Admin\lists\TranslateList;
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use KupShop\PreordersBundle\Translations\PreordersTranslation;
|
||||
|
||||
class TranslatePreordersList extends TranslateList
|
||||
{
|
||||
protected $listType = 'translatePreorders';
|
||||
protected $template = 'translateList/preorders.tpl';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->translation = ServiceContainer::getService(PreordersTranslation::class);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
||||
|
||||
return TranslatePreordersList::class;
|
||||
86
bundles/KupShop/PreordersBundle/Admin/preorders.php
Normal file
86
bundles/KupShop/PreordersBundle/Admin/preorders.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin;
|
||||
|
||||
class preorders extends \Window
|
||||
{
|
||||
protected $tableName = 'preorders';
|
||||
|
||||
public function get_vars(): array
|
||||
{
|
||||
$vars = parent::get_vars();
|
||||
$body = &$vars['body'];
|
||||
$data = &$body['data'];
|
||||
|
||||
if (!empty($data['settings'])) {
|
||||
$this->sanitiseSettings($data['settings']);
|
||||
}
|
||||
|
||||
if (!empty($data['min_price'])) {
|
||||
$data['min_price'] = toDecimal($data['min_price']);
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
$data = parent::getData();
|
||||
|
||||
if (!empty($data['settings'])) {
|
||||
$this->sanitiseSettings($data['settings']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function sanitiseSettings(&$settings): void
|
||||
{
|
||||
if (is_string($settings)) {
|
||||
$settings = json_decode($settings, true);
|
||||
}
|
||||
|
||||
if (!empty($settings['dynamic_prices'])) {
|
||||
$this->sanitiseDynamicPrices($settings['dynamic_prices']);
|
||||
}
|
||||
|
||||
if (!empty($settings['users_groups'])) {
|
||||
$settings['users_groups'] = array_map('intval', $settings['users_groups']);
|
||||
}
|
||||
|
||||
if (getVal('Submit')) {
|
||||
$settings = json_encode($settings);
|
||||
}
|
||||
}
|
||||
|
||||
protected function sanitiseDynamicPrices(&$dynamicPrices): void
|
||||
{
|
||||
$dynamicPrices = array_filter($dynamicPrices, function ($val) {
|
||||
return (empty($val['price_from']) || ctype_digit($val['price_from']))
|
||||
&& (empty($val['price_to']) || ctype_digit($val['price_to']))
|
||||
&& (ctype_digit($val['id_price_level'] ?? 'NaN') || ctype_digit($val['id_pricelist'] ?? 'NaN'));
|
||||
});
|
||||
|
||||
usort($dynamicPrices, function ($a, $b) {
|
||||
if (empty($a['price_from'])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (empty($b['price_from'])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (empty($a['price_to'])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (empty($b['price_to'])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return $a['price_from'] < $b['price_from'] ? -1 : 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return preorders::class;
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin;
|
||||
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use KupShop\PreordersBundle\Entity\UserPreorder;
|
||||
use KupShop\PreordersBundle\Service\DynamicContexts;
|
||||
use KupShop\PreordersBundle\Service\OrderCreator;
|
||||
|
||||
class preordersCreateOrder extends \Window
|
||||
{
|
||||
protected $tableName = 'preorders_items';
|
||||
|
||||
private readonly DynamicContexts $contexts;
|
||||
private ?UserPreorder $userPreorder = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->contexts = ServiceContainer::getService(DynamicContexts::class);
|
||||
}
|
||||
|
||||
private function getUserPreorder(): UserPreorder
|
||||
{
|
||||
if ($this->userPreorder === null) {
|
||||
[$userId, $dateId] = explode('-', $this->getID());
|
||||
|
||||
$this->userPreorder = new UserPreorder((int) $userId, (int) $dateId);
|
||||
}
|
||||
|
||||
return $this->userPreorder;
|
||||
}
|
||||
|
||||
protected function getObject()
|
||||
{
|
||||
return $this->getUserPreorder()->getTemplateVars();
|
||||
}
|
||||
|
||||
public function get_vars()
|
||||
{
|
||||
$vars = parent::get_vars();
|
||||
$this->contexts->activateUserPreorder($this->getUserPreorder());
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function hasRights($name = null): bool
|
||||
{
|
||||
switch ($name) {
|
||||
case \Window::RIGHT_DUPLICATE:
|
||||
case \Window::RIGHT_DELETE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function handleUpdate(): true
|
||||
{
|
||||
$vars = $this->get_vars();
|
||||
$data = $vars['body']['data'];
|
||||
$items = isset($data['items']) ? array_filter($data['items']) : [];
|
||||
|
||||
if (!empty($items)) {
|
||||
/** @var OrderCreator $orderCreator */
|
||||
$orderCreator = ServiceContainer::getService(OrderCreator::class);
|
||||
|
||||
$userPreorder = new UserPreorder((int) $data['id_user'], (int) $data['id_preorder_date']);
|
||||
$order = $orderCreator->createOrder($userPreorder, $items);
|
||||
$this->returnOK("Objednávka {$order->order_no} úspěšně vytvořena.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return preordersCreateOrder::class;
|
||||
50
bundles/KupShop/PreordersBundle/Admin/preordersDates.php
Normal file
50
bundles/KupShop/PreordersBundle/Admin/preordersDates.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin;
|
||||
|
||||
class preordersDates extends \Window
|
||||
{
|
||||
protected $tableName = 'preorders_dates';
|
||||
protected $nameField;
|
||||
|
||||
public function get_vars()
|
||||
{
|
||||
$vars = parent::get_vars();
|
||||
$body = &$vars['body'];
|
||||
$data = &$body['data'];
|
||||
$acn = $this->getAction();
|
||||
|
||||
if ($acn === 'add' && getVal('id_preorder')) {
|
||||
$data['id_preorder'] = intval(getVal('id_preorder'));
|
||||
}
|
||||
|
||||
if (!empty($data['date_start'])) {
|
||||
$data['date_start'] = \DateTime::createFromFormat('Y-m-d', $data['date_start']);
|
||||
}
|
||||
|
||||
if (!empty($data['date_end'])) {
|
||||
$data['date_end'] = \DateTime::createFromFormat('Y-m-d', $data['date_end']);
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
$data = parent::getData();
|
||||
|
||||
if (getVal('Submit')) {
|
||||
if (!empty($data['date_start'])) {
|
||||
$data['date_start'] = $this->prepareDate($data['date_start']);
|
||||
}
|
||||
|
||||
if (!empty($data['date_end'])) {
|
||||
$data['date_end'] = $this->prepareDate($data['date_end']);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
||||
return preordersDates::class;
|
||||
198
bundles/KupShop/PreordersBundle/Admin/preordersUsers.php
Normal file
198
bundles/KupShop/PreordersBundle/Admin/preordersUsers.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\PreordersBundle\Admin;
|
||||
|
||||
use KupShop\AdminBundle\Admin\UserMessagesAdminInterface;
|
||||
use KupShop\KupShopBundle\Email\UserMessagesInterface;
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use KupShop\PreordersBundle\Email\UserPreorderEmail;
|
||||
use KupShop\PreordersBundle\Email\UserPreorderMessageEmail;
|
||||
use KupShop\PreordersBundle\Entity\NotifyState;
|
||||
use KupShop\PreordersBundle\Entity\UserPreorder;
|
||||
use KupShop\PreordersBundle\Entity\UserPreorderMessage;
|
||||
use KupShop\PreordersBundle\Service\DynamicContexts;
|
||||
use Query\Operator as Op;
|
||||
|
||||
class preordersUsers extends \Window implements UserMessagesAdminInterface
|
||||
{
|
||||
protected $tableName = 'preorders_items';
|
||||
private ?UserPreorder $userPreorder = null;
|
||||
private readonly DynamicContexts $contextsService;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->contextsService = ServiceContainer::getService(DynamicContexts::class);
|
||||
}
|
||||
|
||||
private function getUserPreorder(): UserPreorder
|
||||
{
|
||||
if ($this->userPreorder === null) {
|
||||
[$userId, $preorderDateId] = explode('-', $this->getID());
|
||||
$this->userPreorder = new UserPreorder((int) $userId, (int) $preorderDateId);
|
||||
}
|
||||
|
||||
return $this->userPreorder;
|
||||
}
|
||||
|
||||
protected function getObject(): array
|
||||
{
|
||||
$up = $this->getUserPreorder()->getTemplateVars();
|
||||
|
||||
usort($up['items'], fn ($i, $j) => $i['title'] <=> $j['title']);
|
||||
|
||||
return $up;
|
||||
}
|
||||
|
||||
public function get_vars(): array
|
||||
{
|
||||
$updateKeys = array_intersect(array_keys($_POST), ['SaveItemPieces', 'AddNewMessage']);
|
||||
|
||||
if (!empty($updateKeys)) {
|
||||
$this->forceUpdate();
|
||||
}
|
||||
|
||||
$vars = parent::get_vars();
|
||||
$body = &$vars['body'];
|
||||
$data = &$body['data'];
|
||||
|
||||
$userPreorder = $this->getUserPreorder();
|
||||
$this->contextsService->activateUserPreorder($userPreorder);
|
||||
|
||||
$body['isClosed'] = \DateTimeImmutable::createFromFormat('Y-m-d', $data['date_end'])
|
||||
<= (new \DateTimeImmutable())->sub(\DateInterval::createFromDateString('1 day'));
|
||||
|
||||
$body['messages'] = $userPreorder->getMessages();
|
||||
$body['custom_data'] = $userPreorder->getCustomData();
|
||||
$body['errors'] = $this->getItemErrors($data['items']);
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
private function getItemErrors(array $items): array
|
||||
{
|
||||
$errors = [];
|
||||
|
||||
foreach ($items as $item) {
|
||||
if (($item['has_variations'] ?? false) && empty($item['id_variation'])) {
|
||||
$errors[] = sprintf(
|
||||
translate('variationNotSelected', 'preordersUsers'),
|
||||
(int) $item['id'],
|
||||
$item['product_title'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
public function hasRights($name = null): bool
|
||||
{
|
||||
switch ($name) {
|
||||
case \Window::RIGHT_DUPLICATE:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function handleUpdate(): void
|
||||
{
|
||||
$userPreorder = $this->getUserPreorder();
|
||||
|
||||
$data = $this->getData();
|
||||
if (!empty($data['user_address'])) {
|
||||
$customData = $userPreorder->getCustomData();
|
||||
$customData->set('user_address', $data['user_address']);
|
||||
$customData->save();
|
||||
}
|
||||
|
||||
if (getVal('SaveItemPieces', null, false) && $items = getVal('items')) {
|
||||
foreach ($items as $id => $item) {
|
||||
$userPreorder->setItem(
|
||||
$id,
|
||||
null,
|
||||
null,
|
||||
$item['pieces'],
|
||||
$item['pieces_sent'],
|
||||
);
|
||||
}
|
||||
|
||||
$this->returnOK('Kusy produktů uloženy.');
|
||||
}
|
||||
|
||||
if (getVal('AddNewMessage')) {
|
||||
$this->handleSendMessage();
|
||||
}
|
||||
|
||||
$this->returnOK();
|
||||
}
|
||||
|
||||
private function handleSendMessage(): void
|
||||
{
|
||||
$userMessages = $this->getUserPreorder()->getMessages();
|
||||
$text = getVal('new_message');
|
||||
if (!$text) {
|
||||
$this->returnError('Zpráva nebyla odeslána - žádný text.');
|
||||
}
|
||||
|
||||
$admin = getAdminUser();
|
||||
$newMessage = new UserPreorderMessage(
|
||||
text: $text,
|
||||
admin: $admin['login'] ?? 'NEZNÁMÝ ADMIN',
|
||||
);
|
||||
|
||||
$userMessages->add($newMessage);
|
||||
|
||||
if ($exception = $userMessages->save()) {
|
||||
$this->returnError('Nepodařilo se uložit zprávu. '.$exception->getMessage());
|
||||
}
|
||||
|
||||
if (!getVal('message_do_not_notify')) {
|
||||
if ($statusMessage = getVal('status_message')) {
|
||||
$emailService = ServiceContainer::getService(UserPreorderMessageEmail::class);
|
||||
$emailService->setUserMessage($statusMessage);
|
||||
} else {
|
||||
$emailService = ServiceContainer::getService(UserPreorderEmail::class);
|
||||
}
|
||||
|
||||
$email = $emailService->setUserPreorder($this->getUserPreorder())->setMessage($newMessage);
|
||||
|
||||
$emailRes = $emailService->sendEmail($email->getEmail());
|
||||
if (!$emailRes) {
|
||||
$this->returnError('Nepodařilo se poslat e-mail uživateli.');
|
||||
}
|
||||
|
||||
$newMessage->notified = NotifyState::EmailNotified;
|
||||
$userMessages->save();
|
||||
}
|
||||
|
||||
$this->returnOK('Zpráva úspěšně odeslána.');
|
||||
}
|
||||
|
||||
public function handleDelete(): void
|
||||
{
|
||||
$userPreorder = $this->getUserPreorder();
|
||||
$items = $userPreorder->getItems(true);
|
||||
$ids = array_column($items, 'id');
|
||||
|
||||
sqlQueryBuilder()->delete('preorders_items')
|
||||
->andWhere(Op::inIntArray($ids, 'id'))
|
||||
->execute();
|
||||
|
||||
sqlQueryBuilder()->delete('preorders_users_data')
|
||||
->andWhere(Op::equals([
|
||||
'id_preorder_date' => $userPreorder->preorderDateId,
|
||||
'id_user' => $userPreorder->userId,
|
||||
]))
|
||||
->execute();
|
||||
|
||||
redirect('launch.php?s=preordersUsers.php&acn=erased');
|
||||
}
|
||||
|
||||
public function getUserEmails(): UserMessagesInterface
|
||||
{
|
||||
return ServiceContainer::getService(UserPreorderMessageEmail::class)->setUserPreorder($this->userPreorder);
|
||||
}
|
||||
}
|
||||
|
||||
return preordersUsers::class;
|
||||
@@ -0,0 +1,4 @@
|
||||
<p style="width: 100%; text-align: center; margin-bottom: 2rem;">
|
||||
Tato akce převede <strong>celou</strong> předobjednávku do objednávky. Tato akce nelze vrátit zpět.
|
||||
<br>Opravdu chcete pokračovat?
|
||||
</p>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div class="row mb-3">
|
||||
<p class="col-lg-6 text-center">{'recalculateAreYouSure'|translate:'preordersUsers'}</p>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{extends file="[shared]/menu.tpl"}
|
||||
@@ -0,0 +1,62 @@
|
||||
{extends file="[shared]/menu.tpl"}
|
||||
|
||||
{block name="menu-items"}
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="nav-header"><i class="glyphicon glyphicon-tags"></i><span>{translate_type type=$type}</span></li>
|
||||
<li><a href="javascript:nf('', 'launch.php?s=list.php&type={$type}');"><i class="glyphicon glyphicon-list"></i>
|
||||
<span>{'toolbar_list'|translate}</span></a></li>
|
||||
<li>
|
||||
<ul class="nav-sub nav-pills">
|
||||
<form class="form-inline" target="mainFrame" method="get">
|
||||
<input type="hidden" name="type" value="preordersItems"/>
|
||||
<input type="hidden" name="s" value="list.php"/>
|
||||
|
||||
<div style="flex-direction: column;" class="d-flex form-group">
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_user[]"
|
||||
multiple
|
||||
data-autocomplete="users"
|
||||
data-placeholder="Vyberte uživatele"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_preorder[]"
|
||||
multiple
|
||||
data-autocomplete="preorders"
|
||||
data-autocomplete-params="entity_type=preorders"
|
||||
data-placeholder="Vyberte předobjednávky"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_preorder_date[]"
|
||||
multiple
|
||||
data-autocomplete="preorders"
|
||||
data-autocomplete-params="entity_type=preorders_dates"
|
||||
data-placeholder="Vyberte termíny"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" class="input" name="only_remaining" id="only_remaining" value="Y">
|
||||
<label for="only_remaining">Pouze neodeslané</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary" title="Vyhledat uživatele">
|
||||
<i class="glyphicon glyphicon-search"></i>
|
||||
<span>Vyhledat</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{/block}
|
||||
@@ -0,0 +1,85 @@
|
||||
{extends file="[shared]/menu.tpl"}
|
||||
|
||||
{block name="menu-items"}
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="nav-header"><i class="glyphicon glyphicon-tags"></i><span>{translate_type type=$type}</li>
|
||||
<li><a href="javascript:nf('', 'launch.php?s=list.php&type={$type}');"><i class="glyphicon glyphicon-list"></i>
|
||||
<span>{'toolbar_list'|translate}</span></a></li>
|
||||
<li>
|
||||
<ul class="nav-sub nav-pills">
|
||||
<form class="form-inline" target="mainFrame" method="get">
|
||||
<input type="hidden" name="type" value="preordersUsers"/>
|
||||
<input type="hidden" name="s" value="list.php"/>
|
||||
<div style="flex-direction: column;" class="d-flex form-group">
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_user[]"
|
||||
multiple
|
||||
data-autocomplete="users"
|
||||
data-placeholder="Vyberte uživatele"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_preorder[]"
|
||||
multiple
|
||||
data-autocomplete="preorders"
|
||||
data-autocomplete-params="entity_type=preorders"
|
||||
data-placeholder="Vyberte předobjednávky"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_preorder_date[]"
|
||||
multiple
|
||||
data-autocomplete="preorders"
|
||||
data-autocomplete-params="entity_type=preorders_dates"
|
||||
data-placeholder="Vyberte termíny"
|
||||
></select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" class="input" name="onlyClosed" id="onlyClosed">
|
||||
<label for="onlyClosed">Pouze z uzavřených termínů</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" class="input" name="onlyUnsent" id="onlyUnsent">
|
||||
<label for="onlyUnsent">Pouze s neodeslanými produkty</label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex-direction: column; margin-top: 1em;" class="d-flex form-group">
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" class="input" name="allUsers" id="allUsers">
|
||||
<label for="allUsers">Zobrazit všechny uživatele</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<select class="selecter"
|
||||
name="id_users_group[]"
|
||||
multiple
|
||||
data-autocomplete="users_groups"
|
||||
data-placeholder="Vyberte skupiny uživatelů"
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-primary" title="Vyhledat uživatele">
|
||||
<i class="glyphicon glyphicon-search"></i>
|
||||
<span>Vyhledat</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{/block}
|
||||
@@ -0,0 +1,31 @@
|
||||
<div id="flapPreorders" class="tab-pane fade in boxFlex">
|
||||
<div class="row bottom-space">
|
||||
<div class="col-md-12">
|
||||
<h1 class="h4 main-panel-title">{'preorders'|translate:'preorders'}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if isSuperuser()}
|
||||
<div class="form-group">
|
||||
<div class="col-md-4 control-label">
|
||||
<label>{'multipleDatesSinglePage'|translate:'preorders'}</label>
|
||||
<span class="glyphicon glyphicon-flash m-l-1" style="color: #aab2bd;" title="Vidí pouze superadmin"></span>
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'multipleDatesSinglePageTooltip'|translate:'preorders'}"><i class="bi bi-question-circle"></i></a>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
{print_toggle name="preorders][multiple_dates" value=$dbcfg.preorders.multiple_dates|default:'N'}
|
||||
</div>
|
||||
</div>
|
||||
{else}
|
||||
<input type="hidden" value="{$dbcfg.preorders.multiple_dates|default:'N'}" name="data[preorders][multiple_dates]">
|
||||
{/if}
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-4 control-label">
|
||||
<label>{'showHidden'|translate:'preorders'}</label>
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
{print_toggle name="preorders][show_hidden" value=$dbcfg.preorders.show_hidden|default:'N'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,5 @@
|
||||
{extends "[I18nBundle]/list/translate.tpl"}
|
||||
|
||||
{block translationObjectTitle}
|
||||
<strong>({$object.id})</strong> {$object.name}
|
||||
{/block}
|
||||
@@ -0,0 +1,5 @@
|
||||
{extends "[I18nBundle]/list/translate.tpl"}
|
||||
|
||||
{block translationObjectTitle}
|
||||
<strong>({$object.id})</strong> {$object.preorder} {$object.date_start|date_format:'%d.%m.%Y'} - {$object.date_end|date_format:'%d.%m.%Y'}
|
||||
{/block}
|
||||
@@ -0,0 +1,250 @@
|
||||
{extends file="[shared]/window.tpl"}
|
||||
|
||||
{block tabs}
|
||||
{windowTab id='flapMain'}
|
||||
|
||||
{if $body.data.id}
|
||||
{windowTab id='flapProducts'}
|
||||
{windowTab id='flapDiscountLevels'}
|
||||
{windowTab id='flapDates'}
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block tabsContent}
|
||||
<div id="flapMain" class="tab-pane fade active in boxStatic box">
|
||||
<div class="row">
|
||||
<div class="col-xs-1">
|
||||
<div class="wpj-form-group">
|
||||
<label for="id_preorder">Číslo</label>
|
||||
<input id="id_preorder" class="form-control text-center" disabled value="{$body.data.id}" style="max-width: 3em;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-5">
|
||||
<div class="wpj-form-group">
|
||||
<label>
|
||||
{'name'|translate}
|
||||
<a class="help-tip" data-html="true" data-placement="right"
|
||||
data-toggle="tooltip" title="" data-original-title="Zobrazí se uživatelům v prostředí předobjednávek">
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</label>
|
||||
<input type="text" name="data[name]" id="name" class="form-control" value="{$body.data.name}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group" id="date-fields">
|
||||
<label>{'usersGroup'|translate}</label>
|
||||
<select
|
||||
name="data[settings][users_groups][]"
|
||||
multiple="multiple"
|
||||
class="selecter"
|
||||
data-autocomplete="users_groups"
|
||||
data-preload="usersGroups"
|
||||
>
|
||||
{foreach $body.data.settings.users_groups as $group}
|
||||
<option value="{$group}" selected>{$group}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{block "custom-data"}{/block}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label>{'base'|translate} {lcfirst('pricelist'|translate)}</label>
|
||||
<select
|
||||
name="data[id_pricelist]"
|
||||
class="selecter"
|
||||
data-autocomplete="priceLists"
|
||||
data-preload="priceLists"
|
||||
>
|
||||
<option value="">{'pricelistEmptyChoice'|translate}</option>
|
||||
{if $body.data.id_pricelist}
|
||||
<option value="{$body.data.id_pricelist}" selected>{$body.data.id_pricelist}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label>{'base'|translate} {lcfirst('priceLevel'|translate)}</label>
|
||||
<select
|
||||
name="data[id_price_level]"
|
||||
class="selecter"
|
||||
data-autocomplete="priceLevels"
|
||||
data-preload="priceLevels"
|
||||
>
|
||||
<option value="">{'priceLevelStandard'|translate:'users'}<option>
|
||||
{if $body.data.id_price_level}
|
||||
<option value="{$body.data.id_price_level}" selected>{$body.data.id_price_level}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label for="input--min_price">{'minPrice'|translate}</label>
|
||||
<div class="input-group">
|
||||
<input id="input--min_price" type="text" class="form-control" name="data[min_price]"
|
||||
value="{if $body.data.min_price}{$body.data.min_price->asFloat()|string_format:"%.2f"}{/if}">
|
||||
<span class="input-group-addon">{$dbcfg.currency}</span>
|
||||
<span class="input-group-addon">{'withoutTax'|translate:'choice'}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flapProducts" class="tab-pane fade boxFlex">
|
||||
{$productsSortable = true}
|
||||
{include 'block.productsFilter.tpl' filter=$body.data.settings.products_filter
|
||||
filterInputName='data[settings][products_filter]' filterName='products_filter'}
|
||||
</div>
|
||||
|
||||
<div id="flapDiscountLevels" class="tab-pane fade boxStatic box">
|
||||
<div class="row bottom-space">
|
||||
<div class="col-xs-3">
|
||||
<button type="button" class="btn btn-block btn-success" data-form-add>
|
||||
<i class="bi bi-plus-lg m-r-1"></i>{'addDynamicPrice'|translate}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wpj-panel wpj-panel-default">
|
||||
<div class="wpj-panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<strong class="small">{'priceFrom'|translate}</strong>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<strong class="small">{'priceTo'|translate}</strong>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<strong class="small">{'priceLevel'|translate}</strong>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<strong class="small">{'pricelist'|translate}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wpj-list-group">
|
||||
<div class="wpj-list-group-item" style="display: none;" data-form-new>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="data[settings][dynamic_prices][@][price_from]"
|
||||
placeholder="{'priceFrom'|translate}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="data[settings][dynamic_prices][@][price_to]"
|
||||
placeholder="{'priceTo'|translate}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<select
|
||||
class="selecter"
|
||||
name="data[settings][dynamic_prices][@][id_price_level]"
|
||||
data-autocomplete="priceLevels"
|
||||
>
|
||||
<option selected value="">{'priceLevelStandard'|translate:'users'}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<select
|
||||
class="selecter"
|
||||
name="data[settings][dynamic_prices][@][id_pricelist]"
|
||||
data-autocomplete="priceLists"
|
||||
>
|
||||
<option value="">{'pricelistEmptyChoice'|translate}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
<button type="button" class="btn btn-sm btn-danger" data-form-delete>
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{foreach $body.data.settings.dynamic_prices as $dynamicPrice}
|
||||
<div class="wpj-list-group-item" data-form-item>
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="data[settings][dynamic_prices][{$dynamicPrice@index}][price_from]"
|
||||
value="{$dynamicPrice.price_from}"
|
||||
placeholder="{'priceFrom'|translate}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="data[settings][dynamic_prices][{$dynamicPrice@index}][price_to]"
|
||||
value="{$dynamicPrice.price_to}"
|
||||
placeholder="{'priceTo'|translate}">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<select
|
||||
class="selecter"
|
||||
name="data[settings][dynamic_prices][{$dynamicPrice@index}][id_price_level]"
|
||||
data-autocomplete="priceLevels"
|
||||
data-autocomplete-params="allow_empty=1"
|
||||
data-preload="priceLevels"
|
||||
>
|
||||
{if $dynamicPrice.id_price_level}
|
||||
<option selected value="{$dynamicPrice.id_price_level}">{$dynamicPrice.id_price_level}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<select
|
||||
class="selecter"
|
||||
name="data[settings][dynamic_prices][{$dynamicPrice@index}][id_pricelist]"
|
||||
data-autocomplete="priceLists"
|
||||
data-preload="priceLists"
|
||||
>
|
||||
<option value="">{'pricelistEmptyChoice'|translate}</option>
|
||||
{if $dynamicPrice.id_pricelist}
|
||||
<option selected value="{$dynamicPrice.id_pricelist}">{$dynamicPrice.id_pricelist}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
<button type="button" class="btn btn-sm btn-danger" data-form-delete>
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flapDates" class="tab-pane fade active in boxStatic box">
|
||||
<div class="row bottom-space">
|
||||
<div class="col-xs-3">
|
||||
<a class="btn btn-block btn-success"
|
||||
href="javascript:nw('preordersDates', null, 'id_preorder={$body.data.id}');"><span class="bi bi-plus-lg m-r-1"></span>{'addPreorderDate'|translate}</a>
|
||||
</div>
|
||||
</div>
|
||||
<iframe class="on-demand boxFlex" height="600"
|
||||
data-src="launch.php?s=list.php&type=preordersDates&id_preorder[]={$body.data.id}"></iframe>
|
||||
</div>
|
||||
{/block}
|
||||
{block onready append}
|
||||
initForm({
|
||||
selector: '#flapDiscountLevels',
|
||||
jsonFriendly: true,
|
||||
beforeAdd(callback) {
|
||||
var $form = callback();
|
||||
window.preloadAutocompletes($form);
|
||||
|
||||
return false;
|
||||
},
|
||||
});
|
||||
{/block}
|
||||
@@ -0,0 +1,75 @@
|
||||
{extends file="[shared]/window.tpl"}
|
||||
|
||||
{block tabsContent}
|
||||
<div class="row">
|
||||
<div class="col-xs-4 pull-right">
|
||||
<div class="wpj-form-group">
|
||||
<a href="#" data-add-all class="btn btn-success btn-block"><span
|
||||
class="bi bi-plus-lg m-r-1"></span>{'buttonAddValue'|translate}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wpj-panel wpj-panel-default">
|
||||
<div class="wpj-panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<small class="text-muted">{'item'|translate:'preordersUsers'}</small>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<small class="text-muted">{'piecePrice'|translate:'preordersUsers'}</small>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<small class="text-muted">{'piecesSent'|translate:'preordersUsers'}</small>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<small class="text-muted">{'piecesToAdd'|translate:'preordersUsers'}</small>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<small class="text-muted"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wpj-list-group">
|
||||
{foreach $body.data.items as $item}
|
||||
{if $item.pieces_sent >= $item.pieces}{continue}{/if}
|
||||
<div class="wpj-list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<strong><a href="javascript:nw('products','{$item.id_product}');" class="text-dark">{$item.title}</a></strong>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
{$item.piece_price|format_price}
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
{$item.pieces_sent} / {$item.pieces}
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="input-group">
|
||||
<input class="form-control" name="data[items][{$item.id}]"
|
||||
aria-label="{'piecesToAdd'|translate}">
|
||||
<div class="input-group-btn">
|
||||
<button type="button" data-add-all-count="{$item.pieces - $item.pieces_sent}" class="btn btn-success">Vše
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-1">
|
||||
<small class="text-muted"></small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$('button[data-add-all-count]').on('click', function () {
|
||||
var $btn = $(this);
|
||||
var count = $btn.data('add-all-count');
|
||||
$btn.parent('.input-group-btn').siblings('input').val(count);
|
||||
});
|
||||
|
||||
$('[data-add-all]').on('click', function (e) {
|
||||
$('button[data-add-all-count]').click();
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,150 @@
|
||||
{extends file="[shared]/window.tpl"}
|
||||
|
||||
{block tabs}
|
||||
{windowTab id='flapMain'}
|
||||
|
||||
{if $body.data.id}
|
||||
{windowTab id='flapPreordersCreated'}
|
||||
{windowTab id='flapProducts'}
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block tabsContent}
|
||||
<div id="flapMain" class="tab-pane fade active in boxStatic box">
|
||||
<div class="row wpj-form-group-flex">
|
||||
<div class="col-xs-1">
|
||||
<div class="wpj-form-group">
|
||||
<label for="id_preorder_date">Číslo</label>
|
||||
<input id="id_preorder_date" disabled value="{$body.data.id}" class="form-control text-center" style="max-width: 3em;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-5"></div>
|
||||
|
||||
<div class="col-xs-4">
|
||||
<div class="wpj-form-group">
|
||||
<label>
|
||||
<a href="javascript:void showPreorder();">{'preorder'|translate}</a>
|
||||
</label>
|
||||
|
||||
<script>
|
||||
function showPreorder() {
|
||||
var preorderId = $('select[name="data[id_preorder]"] option:selected').attr('value');
|
||||
nw('preorders', preorderId);
|
||||
}
|
||||
</script>
|
||||
|
||||
<select
|
||||
name="data[id_preorder]"
|
||||
class="selecter"
|
||||
data-preload="preorders"
|
||||
data-autocomplete="preorders"
|
||||
data-autocomplete-params="entity_type=preorders"
|
||||
>
|
||||
{if $body.data.id_preorder}
|
||||
<option selected value="{$body.data.id_preorder}">{$body.data.id_preorder}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="wpj-form-group">
|
||||
<a href="javascript:nw('preorders');" class="btn btn-block btn-success"><span class="bi bi-plus-lg m-r-1"></span>{'preorderCreateBtn'|translate}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label>
|
||||
{'dateStart'|translate}
|
||||
<a class="help-tip"
|
||||
data-toggle="tooltip"
|
||||
title="{'dateStartTooltip'|translate}"
|
||||
>
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="data[date_start]" id="date_start" class="form-control input-sm"
|
||||
value="{$body.data.date_start|format_date:'d.m.Y'}">
|
||||
{insert_calendar selector='#date_start' format='date'}
|
||||
<label for="date_start" class="input-group-addon">
|
||||
<span class="bi bi-calendar-week"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label>
|
||||
{'dateEnd'|translate}
|
||||
<a class="help-tip"
|
||||
data-toggle="tooltip"
|
||||
title="{'dateEndTooltip'|translate}"
|
||||
>
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="text" name="data[date_end]" id="date_end" class="form-control input-sm"
|
||||
value="{$body.data.date_end|format_date:'d.m.Y'}">
|
||||
{insert_calendar selector='#date_end' format='date'}
|
||||
<label for="date_end" class="input-group-addon">
|
||||
<span class="bi bi-calendar-week"></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label>
|
||||
{'dateShipment'|translate}
|
||||
<a class="help-tip"
|
||||
data-toggle="tooltip"
|
||||
title="{'dateShipmentTooltip'|translate}"
|
||||
>
|
||||
<i class="bi bi-question-circle"></i>
|
||||
</a>
|
||||
</label>
|
||||
<input type="text" name="data[date_shipment]" id="date_shipment" class="form-control input-sm"
|
||||
value="{$body.data.date_shipment}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6">
|
||||
<div class="wpj-form-group">
|
||||
<label for="description">{'description'|translate}</label>
|
||||
<textarea
|
||||
id="description"
|
||||
name="data[description]"
|
||||
rows="3"
|
||||
class="form-control input-sm"
|
||||
>{$body.data.description}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="flapPreordersCreated" class="tab-pane fade active in boxStatic box">
|
||||
<iframe data-src="launch.php?s=list.php&type=preordersUsers&id_preorder_date[]={$body.data.id}" height="520" class="on-demand"></iframe>
|
||||
</div>
|
||||
<div id="flapProducts" class="tab-pane fade active in boxStatic box">
|
||||
<iframe data-src="launch.php?s=list.php&type=preordersItems&id_preorder_date[]={$body.data.id}" height="520" class="on-demand"></iframe>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
$('[data-shipment-clear]').on('click', function () {
|
||||
var selector = $(this).data('shipment-clear');
|
||||
$(selector).val('');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
@@ -0,0 +1,276 @@
|
||||
{extends file="[shared]/window.tpl"}
|
||||
|
||||
{block tabs}
|
||||
{windowTab id='flapMain'}
|
||||
{windowTab id='flapMessages'}
|
||||
{if $body.isClosed}
|
||||
{windowTab id='flapOrders'}
|
||||
{/if}
|
||||
{/block}
|
||||
|
||||
{block js append}
|
||||
<script src="./static/js/EmailMessages.js"></script>
|
||||
{/block}
|
||||
|
||||
{block tabsContent}
|
||||
<div id="flapMain" class="tab-pane fade active in boxStatic box">
|
||||
<div class="m-b-1">
|
||||
<h4>{'titleUser'|translate}</h4>
|
||||
</div>
|
||||
<div class="well well-lg">
|
||||
<div class="row">
|
||||
<div class="col-xs-3">
|
||||
<p class="m-b-0">
|
||||
{'user'|translate}<br>
|
||||
<a href="javascript:nw('users', {$body.data.id_user});" class="text-large text-bold text-dark">
|
||||
{$body.data.user_firm}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<p class="m-b-0">
|
||||
{'preorder'|translate:'preordersDates'}<br>
|
||||
<a href="javascript:nw('preorders', {$body.data.id_preorder});" class="text-large text-bold text-dark">
|
||||
{$body.data.name}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-3">
|
||||
<p class="m-b-0">
|
||||
{'dateTitle'|translate}<br>
|
||||
<a href="javascript:nw('preordersDates', {$body.data.id_preorder_date});" class="text-large text-bold text-dark" title="{$body.data.date_description}">
|
||||
{$body.data.date_start|format_date:'d.m.Y'} – {$body.data.date_end|format_date:'d.m.Y'}
|
||||
{if $body.data.date_shipment}
|
||||
<br>
|
||||
<small class="text-muted" style="font-weight: normal;">({'dateShipmentAbbr'|translate} {$body.data.date_shipment})</small>
|
||||
{/if}
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<p class="m-b-0">
|
||||
{'priceTotal'|translate:'preordersDates'}<br>
|
||||
<strong class="text-large">{$body.data.price_total|format_price}</strong>
|
||||
</p>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<p class="m-b-0">
|
||||
{'priceRemaining'|translate:'preordersDates'}<br>
|
||||
<strong class="text-large">{$body.data.price_remaining|format_price}</strong>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{ifmodule USER_ADDRESSES}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<label>{'userAddress'|translate:'preordersDates'}</label>
|
||||
</div>
|
||||
<div class="col-xs-12">
|
||||
<select class="selecter" name="data[user_address]" data-autocomplete="UserAddresses" data-placeholder="--"
|
||||
data-preload="UserAddresses"
|
||||
data-autocomplete-params="id_user={$body.data.id_user}">
|
||||
{if $body.custom_data.user_address}
|
||||
<option value="{$body.custom_data.user_address}" selected>{$body.custom_data.user_address}</option>
|
||||
{/if}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
{/ifmodule}
|
||||
|
||||
</div>
|
||||
|
||||
{if $body.errors|count}
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
{foreach $body.errors as $error}
|
||||
<div class="alert alert-danger">
|
||||
<span>{$error nofilter}</span>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between m-b-1">
|
||||
<h4>{'titleOrderedProducts'|translate}</h4>
|
||||
<button name="SaveItemPieces" class="btn btn-primary" type="submit" value="SaveItemPieces">{'saveItemPieces'|translate}</button>
|
||||
</div>
|
||||
<div class="wpj-panel wpj-panel-default">
|
||||
<div class="wpj-panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<small>{'item'|translate}</small>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<small>{'piecePrice'|translate}</small>
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<small>{'piecesSent'|translate}</small>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
<small>{'priceRemaining'|translate}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wpj-list-group">
|
||||
{foreach $body.data.items as $item}
|
||||
{$formatParams = "currency=`$item.currency`"}
|
||||
|
||||
<div id="preorder-item-{$item.id}" class="wpj-list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-xs-5">
|
||||
<a href="javascript:nw('products','{$item.id_product}');">{$item.product_title} {$item.variation_title}</a>
|
||||
{if $item.has_variations and $item.id_variation === null}
|
||||
<a class="text-danger m-l-1" data-toggle="tooltip" title=""
|
||||
data-original-title="{'variationNotSelectedTooltip'|translate}">
|
||||
<i class="bi bi-exclamation-circle"></i>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
{$item.piece_price|format_price:$formatParams}
|
||||
</div>
|
||||
<div class="col-xs-2">
|
||||
<div class="d-flex align-items-center">
|
||||
<input class="form-control" name="items[{$item.id}][pieces_sent]" value="{$item.pieces_sent}">
|
||||
/
|
||||
<input class="form-control" name="items[{$item.id}][pieces]" value="{$item.pieces}">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-3 text-right">
|
||||
{$item.price_remaining|format_price:$formatParams} / {$item.price_total|format_price:$formatParams}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h4>Metadata</h4>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-4">
|
||||
<div class="d-flex justify-content-between align-items-center m-b-1">
|
||||
<label>Jazyk:</label>
|
||||
<code>{$body.custom_data.language}</code>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center m-b-1">
|
||||
<label>Doména:</label>
|
||||
<code><a href="https://{$body.custom_data.domain}/" target="_blank">{$body.custom_data.domain}</a></code>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center m-b-1">
|
||||
<label>Měna:</label>
|
||||
<code>{$body.custom_data.currency}</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-4">
|
||||
<div class="d-flex justify-content-between align-items-center m-b-1">
|
||||
<label>Naposledy uloženo:</label>
|
||||
<code>{$body.custom_data.last_saved_at|date_format:'%d.%m.%Y %H:%I %Z'}</code>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center m-b-1">
|
||||
<label>IP Adresa:</label>
|
||||
<code>{$body.custom_data.ip_address}</code>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center m-b-1" >
|
||||
<label>Prohlížeč:</label>
|
||||
<code title="{$body.custom_data.user_agent}">{$body.custom_data.user_agent|truncate:30:'...'}</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flapMessages" class="tab-pane fade in boxStatic box">
|
||||
<div class="m-b-1">
|
||||
<h4>{'previousMessages'|translate}</h4>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 m-b-2">
|
||||
<div class="row m-b-2">
|
||||
<div class="wpj-panel wpj-panel-default">
|
||||
<div class="wpj-panel-heading">
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
<small class="text-muted">{'notification'|translate}</small>
|
||||
</div>
|
||||
<div class="col-xs-2 text-center">
|
||||
<small class="text-muted">{'messageDate'|translate}</small>
|
||||
</div>
|
||||
<div class="col-xs-6 text-center">
|
||||
<small class="text-muted">{'messageText'|translate}</small>
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
<small class="text-muted">{'messageSentBy'|translate}</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wpj-list-group">
|
||||
{foreach $body.messages as $message}
|
||||
<div class="wpj-list-group-item">
|
||||
<div class="row">
|
||||
<div class="col-xs-2">
|
||||
{$message.notified->getMessage()}
|
||||
</div>
|
||||
<div class="col-xs-2 text-center">
|
||||
{$message.date|date_format:'d.m.Y H:i'}
|
||||
</div>
|
||||
<div class="col-xs-6 text-center">
|
||||
{$message.text nofilter}
|
||||
</div>
|
||||
<div class="col-xs-2 text-right">
|
||||
{if $message.admin}
|
||||
{$message.admin}
|
||||
{else}
|
||||
{$body.data.user_firm}
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-row justify-content-end">
|
||||
<div class="col-xs-6">
|
||||
<h5>{'newMessage'|translate}</h5>
|
||||
|
||||
<div class="m-b-1">
|
||||
<textarea id="message" name="new_message" wrap="soft"></textarea>
|
||||
{insert_wysiwyg target="message" type="BasicTable"
|
||||
config="toolbarStartupExpanded : false,startupFocus : false,removePlugins : 'elementspath', height:'150px', resize_minHeight:'100px', resize_enabled:false, ignoreEmptyParagraph:true, startupOutlineBlocks:false"}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input type="hidden" name="status_message" value="" id="status_comment">
|
||||
{include "block.UserMessages.tpl"}
|
||||
{renderMessageButtons}
|
||||
</div>
|
||||
<div class="d-flex flex-row justify-content-between">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" class="check" value="Y" name="message_do_not_notify" id="donotnotify">
|
||||
<label for="donotnotify"><strong>{'negation'|translate:'orders'}</strong>{'sendEmail'|translate:'orders'}</label>
|
||||
</div>
|
||||
<button class="btn btn-primary" type="submit" name="AddNewMessage" value="SaveItemPieces">Odeslat zprávu</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="flapOrders" class="tab-pane fade in boxStatic box">
|
||||
<iframe
|
||||
class="on-demand boxFlex" height="600"
|
||||
src="launch.php?s=list.php&type=preordersOrdersCreated&userId={$body.data.id_user}&id_preorder_date={$body.data.id_preorder_date}"></iframe>
|
||||
</div>
|
||||
{/block}
|
||||
Reference in New Issue
Block a user