first commit
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Actions\Frontend;
|
||||
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Context\VatContext;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
use KupShop\KupShopBundle\Util\Price\Price;
|
||||
use KupShop\OrderDiscountBundle\Actions\Frontend\AbstractHandler;
|
||||
use KupShop\OrderDiscountBundle\Actions\Frontend\HandlerWithPurchaseStateInterface;
|
||||
use KupShop\OrderDiscountBundle\Actions\Frontend\HandlerWithPurchaseStateTrait;
|
||||
use KupShop\ProductsChargesBundle\Actions\OrdersChargesAction;
|
||||
use KupShop\ProductsChargesBundle\Translations\ProductsChargesTranslation;
|
||||
use Query\Operator;
|
||||
use Query\Translation;
|
||||
|
||||
class OrdersChargesHandler extends AbstractHandler implements HandlerWithPurchaseStateInterface
|
||||
{
|
||||
use HandlerWithPurchaseStateTrait;
|
||||
|
||||
protected $template = 'order_discount/actions/orders_charge.tpl';
|
||||
|
||||
public $templateSize = 'full';
|
||||
|
||||
public function setActionData(array $actionData): AbstractHandler
|
||||
{
|
||||
$this->actionData = $actionData;
|
||||
|
||||
if ($id_charge = $actionData['id_charge'] ?? null) {
|
||||
$charge = sqlQueryBuilder()->select('ch.*')
|
||||
->from('charges', 'ch')
|
||||
->where(Operator::equals(['ch.id' => $id_charge]))
|
||||
->andWhere(Translation::coalesceTranslatedFields(ProductsChargesTranslation::class))
|
||||
->execute()->fetch();
|
||||
if ($charge) {
|
||||
$currency = Contexts::get(CurrencyContext::class)->getOrDefault($charge['currency'] ?? null);
|
||||
|
||||
if ($charge['product'] = $this->getChargeProduct($charge)) {
|
||||
// uplatnit sazbu DPH podle priplatkoveho produktu
|
||||
$vat = getVat($charge['product']->vat_id);
|
||||
} elseif (is_null($charge['vat'])) {
|
||||
// uplatnit sazbu DPH podle produktů v objednávce
|
||||
$vat = $this->purchaseState->getDeliveryVat();
|
||||
} else {
|
||||
$vat = getVat($charge['vat']);
|
||||
if ($vat != 0) {
|
||||
// v případě OSS se použije výchozí DPH dané země
|
||||
$vat = Contexts::get(VatContext::class)->isCountryOssActive() ? getVat() : $vat;
|
||||
}
|
||||
}
|
||||
|
||||
$price = $charge['price'];
|
||||
if ($charge['percentage'] !== null && $this->purchaseState) {
|
||||
$price = OrdersChargesAction::calculatePercentCharges(
|
||||
$this->purchaseState->getProductsTotalPrice(),
|
||||
$charge['percentage']
|
||||
);
|
||||
$currency = $this->purchaseState->getProductsTotalPrice()->getCurrency();
|
||||
}
|
||||
|
||||
$charge['price'] = new Price(toDecimal($price), $currency, $vat);
|
||||
$this->actionData['charge'] = $charge;
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVars(): array
|
||||
{
|
||||
$vars = parent::getVars();
|
||||
|
||||
$vars['disabled'] = false;
|
||||
$charge = &$vars['data']['charge'];
|
||||
$product = $this->getChargeProduct($charge);
|
||||
$vars['data']['product'] = $product;
|
||||
|
||||
if ($product) {
|
||||
$custom_data = json_decode($charge['data'] ?? '', true);
|
||||
$order_not_in_store = ($custom_data['order_not_in_store'] ?? false);
|
||||
if (!$order_not_in_store && ($product->inStore <= 0)) {
|
||||
$charge['figure'] = 'N';
|
||||
}
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function getChargeProduct(array $charge): ?\Product
|
||||
{
|
||||
if ($product = $charge['product'] ?? null) {
|
||||
return $product;
|
||||
}
|
||||
|
||||
if ($id_product = $charge['id_product'] ?? null) {
|
||||
if ($id_variation = $charge['id_variation'] ?? null) {
|
||||
$product = new \Variation($id_product, $id_variation);
|
||||
} else {
|
||||
$product = new \Product($id_product);
|
||||
}
|
||||
if (!$product->createFromDB()) {
|
||||
$product = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $product;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Actions;
|
||||
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Context\VatContext;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
use KupShop\KupShopBundle\Util\Price\Price;
|
||||
use KupShop\KupShopBundle\Util\Price\PriceCalculator;
|
||||
use KupShop\KupShopBundle\Util\Price\TotalPrice;
|
||||
use KupShop\OrderDiscountBundle\Actions\AbstractAction;
|
||||
use KupShop\OrderDiscountBundle\Actions\Frontend\HandlerInterface;
|
||||
use KupShop\OrderDiscountBundle\Entity\OrderDiscount;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\ChargePurchaseItem;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\ProductPurchaseItem;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\PurchaseState;
|
||||
use KupShop\OrderingBundle\Util\Order\OrderItemInfo;
|
||||
use KupShop\ProductsChargesBundle\Actions\Frontend\OrdersChargesHandler;
|
||||
use Query\Operator;
|
||||
|
||||
class OrdersChargesAction extends AbstractAction
|
||||
{
|
||||
protected static $type = 'orders_charge';
|
||||
protected static $position = 130;
|
||||
protected $adminTemplate = 'actions/orders_charges.tpl';
|
||||
protected $translationSection = 'productsCharges';
|
||||
|
||||
private $ordersChargesHandler;
|
||||
|
||||
public function __construct(OrdersChargesHandler $ordersChargesHandler)
|
||||
{
|
||||
$this->ordersChargesHandler = $ordersChargesHandler;
|
||||
}
|
||||
|
||||
public static function calculatePercentCharges(TotalPrice $totalPrice, $percentage)
|
||||
{
|
||||
return $totalPrice
|
||||
->getPriceWithoutVat()
|
||||
->div(toDecimal('100.0'))
|
||||
->mul(toDecimal($percentage));
|
||||
}
|
||||
|
||||
public function applyResult(PurchaseState &$purchaseState, OrderDiscount $orderDiscount, array $data)
|
||||
{
|
||||
$charge = sqlQueryBuilder()->select('*')->from('charges')
|
||||
->where(Operator::equals(['id' => $data['id_charge']]))
|
||||
->execute()->fetch();
|
||||
if ($charge) {
|
||||
$required = $charge['required'] ?? null;
|
||||
$defaultChecked = $charge['checked'] ?? null;
|
||||
$checked = ($data['handled']['checked'] ?? $required == 'Y' ?: $defaultChecked);
|
||||
if ($checked == 'Y') {
|
||||
$name = $orderDiscount->getDisplayName();
|
||||
$note = ['item_type' => OrderItemInfo::TYPE_CHARGE, 'id_charge' => $data['id_charge']];
|
||||
|
||||
$product = false;
|
||||
if ($id_product = $charge['id_product'] ?? null) {
|
||||
if ($id_variation = $charge['id_variation'] ?? null) {
|
||||
$product = new \Variation($id_product, $id_variation);
|
||||
} else {
|
||||
$product = new \Product($id_product);
|
||||
}
|
||||
if (!$product->createFromDB()) {
|
||||
$product = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($product) {
|
||||
// uplatnit sazbu DPH podle priplatkoveho produktu
|
||||
$vat = getVat($product->vat_id);
|
||||
} elseif (is_null($charge['vat'])) {
|
||||
// uplatnit sazbu DPH podle produktů v objednávce
|
||||
$vat = $purchaseState->getDeliveryVat();
|
||||
} else {
|
||||
$vat = getVat($charge['vat']);
|
||||
if ($vat != 0) {
|
||||
// v případě OSS se použije výchozí DPH dané země
|
||||
$vat = Contexts::get(VatContext::class)->isCountryOssActive() ? getVat() : $vat;
|
||||
}
|
||||
}
|
||||
|
||||
$discountPrice = toDecimal($charge['price']);
|
||||
$currency = Contexts::get(CurrencyContext::class)->getOrDefault($charge['currency'] ?? null);
|
||||
if ($charge['percentage'] ?? false) {
|
||||
$discountPrice = self::calculatePercentCharges($purchaseState->getTotalPrice(), $charge['percentage']);
|
||||
$currency = $purchaseState->getTotalPrice()->getCurrency();
|
||||
}
|
||||
$discountPrice = new Price($discountPrice, $currency, $vat);
|
||||
$discountPrice = PriceCalculator::convert($discountPrice, $purchaseState->getTotalPrice()->getCurrency());
|
||||
$discountPriceValue = $discountPrice->getPriceWithoutVat(); // kvuli spravnemu zaokrouhleni
|
||||
$discountPrice = new Price($discountPriceValue, $discountPrice->getCurrency(), $vat);
|
||||
if ($product) {
|
||||
$purchaseItem = new ProductPurchaseItem($id_product, $id_variation ?? null, 1,
|
||||
$discountPrice, $note, $orderDiscount->getId());
|
||||
$purchaseItem->id_charge = $data['id_charge'];
|
||||
$purchaseItem->setName($name);
|
||||
} else {
|
||||
$purchaseItem = new ChargePurchaseItem($name, $discountPrice, $data['id_charge'], $orderDiscount->getId(), $note);
|
||||
}
|
||||
$purchaseState->addCharge($purchaseItem);
|
||||
$purchaseState->addUsedDiscount($orderDiscount->getId());
|
||||
if ($message = $data['messages']['success'] ?? '') {
|
||||
$this->messages['success'] = $message;
|
||||
}
|
||||
} else {
|
||||
if ($message = $data['messages']['warning'] ?? '') {
|
||||
$this->messages['warning'] = $message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getFrontendHandler(): ?HandlerInterface
|
||||
{
|
||||
return $this->ordersChargesHandler;
|
||||
}
|
||||
|
||||
protected function getVars($vars)
|
||||
{
|
||||
$vars['charges'] = sqlFetchAll(
|
||||
sqlQueryBuilder()
|
||||
->select('id, IF(admin_title != "", admin_title, title) as title')->from('charges')
|
||||
->andWhere("type = 'order'")
|
||||
->execute(),
|
||||
['id' => 'title']
|
||||
);
|
||||
|
||||
return $vars;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
$txt_str['productsCharges'] = [
|
||||
'module' => 'Příplatky',
|
||||
'navigation' => 'Příplatky',
|
||||
'toolbar_list' => 'Seznam příplatků',
|
||||
'toolbar_add' => 'Přidat příplatek',
|
||||
'titleAdd' => 'Nový příplatek',
|
||||
'titleEdit' => 'Úprava příplatku',
|
||||
'flap1' => 'Příplatek',
|
||||
'confirmDelete' => 'Opravdu chcete smazat tento příplatek?',
|
||||
|
||||
'products_charges' => 'Příplatky ke zboží',
|
||||
'name' => 'Název',
|
||||
'display_name' => 'Název v e-shopu',
|
||||
'display_name_tooltip' => 'Název v e-shopu uvidí uživatelé. Pokud jej nevyplníte, automaticky se do e-shopu propíše text z Názvu.',
|
||||
'percentage_tooltip' => 'Vyplníte-li hodnotu v procentech, prioritizuje se před fixní cenou.',
|
||||
'type' => 'Typ příplatku',
|
||||
'type_product' => 'K produktu',
|
||||
'type_order' => 'K objednávce',
|
||||
'descr' => 'Popis',
|
||||
'price' => 'Cena',
|
||||
'vat' => 'Daň',
|
||||
'product' => 'Příplatkový produkt',
|
||||
'charge_required' => 'Povinný příplatek',
|
||||
'charge_required_help' => 'Příplatek je vždy zaškrtnutý a zákazník ho nemůže odstranit.',
|
||||
'charge_included' => 'Již zahrnut v ceně',
|
||||
'charge_included_help' => 'Aktivováním příplatku se nezvýší cena za produkt(y).',
|
||||
'charge_checked' => 'Ve výchozím stavu zaškrtnutý',
|
||||
'charge_checked_help' => 'Příplatek je ve výchozím stavu zaškrtnutý, aktivní, ale zákazník má možnost zaškrtnutí zrušit.',
|
||||
'charge_onetime' => 'Jednorázový příplatek',
|
||||
'charge_onetime_help' => 'Příplatek bude u každé položky započítán jen jednou, nehledě na to, kolik kusů dané položky má uživatel v košíku.',
|
||||
'orders_charge' => 'Příplatek k objednávce',
|
||||
'errorNotAllValid' => 'Zadejte alespoň název, cenu a DPH',
|
||||
'active' => 'Aktivní',
|
||||
|
||||
'activityEdited' => 'Upraven příplatek: %s',
|
||||
'activityAdded' => 'Přidán příplatek: %s',
|
||||
'activityDeleted' => 'Smazán příplatek: %s',
|
||||
|
||||
'orders_chargeDescription' => 'Příplatek k objednávce',
|
||||
];
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
$txt_str['productsCharges'] = [
|
||||
'module' => 'Charges',
|
||||
'navigation' => 'Charges',
|
||||
'toolbar_list' => 'Show charges',
|
||||
'toolbar_add' => 'Add charge',
|
||||
'titleAdd' => 'Add new charge',
|
||||
'titleEdit' => 'Edit charge',
|
||||
'flap1' => 'Charge',
|
||||
'confirmDelete' => 'Do you really want to delete this charge?',
|
||||
|
||||
'products_charges' => 'Product charges',
|
||||
'title' => 'Title',
|
||||
'descr' => 'Description',
|
||||
'price' => 'Price',
|
||||
'vat' => 'VAT',
|
||||
'charge_required' => 'Compulsory',
|
||||
'charge_required_help' => 'Charge is always active, customers cannot uncheck it.',
|
||||
'charge_included' => 'Included',
|
||||
'charge_included_help' => 'By activating this charge, the price of product(s) remains the same.',
|
||||
'charge_checked' => 'Checked by default',
|
||||
'charge_checked_help' => 'Charge is checked by default, but customer can uncheck it at will.',
|
||||
'charge_onetime' => 'One-time charge',
|
||||
'charge_onetime_help' => 'The charge will only be applied once for each item, regardless of how many items the user has in their cart.',
|
||||
'orders_charge' => 'Orders charge',
|
||||
'errorNotAllValid' => 'These fields are required: ',
|
||||
'active' => 'Active',
|
||||
|
||||
'activityEdited' => 'Charge edited: %s',
|
||||
'activityAdded' => 'Charge added: %s',
|
||||
'activityDeleted' => 'Charge deleted: %s',
|
||||
|
||||
'orders_chargeDescription' => 'Orders charge',
|
||||
];
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
use KupShop\AdminBundle\AdminList\BaseList;
|
||||
|
||||
class ProductsChargesList extends BaseList
|
||||
{
|
||||
protected $showMassEdit = true;
|
||||
protected $tableName = 'charges';
|
||||
protected ?string $tableAlias = 'ch';
|
||||
|
||||
protected $tableDef = [
|
||||
'id' => 'id',
|
||||
'fields' => [
|
||||
'name' => ['field' => 'ch.admin_title', 'size' => 1, 'translate' => true, 'spec' => 'ch.admin_title', 'fieldType' => BaseList::TYPE_STRING],
|
||||
'display_name' => ['field' => 'ch.title', 'size' => 2, 'translate' => true, 'spec' => 'ch.title', 'fieldType' => BaseList::TYPE_STRING],
|
||||
'type' => ['field' => 'ch.type', 'size' => 1, 'translate' => true, 'render' => 'renderType', 'fieldType' => ProductsChargesList::TYPE_LIST],
|
||||
'descr' => ['field' => 'ch.descr', 'visible' => 'N', 'size' => 3, 'translate' => true, 'spec' => 'ch.descr', 'fieldType' => BaseList::TYPE_STRING],
|
||||
'price' => ['field' => 'ch.price', 'render' => 'renderPriceVat', 'size' => 0.7, 'translate' => true, 'spec' => 'ch.price', 'fieldType' => BaseList::TYPE_PRICE],
|
||||
'vat' => ['field' => 'ch.vat', 'render' => 'renderVat', 'size' => 0.7, 'translate' => true, 'spec' => 'ch.vat', 'fieldType' => ProductsChargesList::TYPE_LIST],
|
||||
'charge_required' => ['field' => 'ch.required', 'render' => 'renderBoolean', 'size' => 0.7, 'translate' => true, 'spec' => 'ch.required', 'fieldType' => BaseList::TYPE_BOOL],
|
||||
'charge_included' => ['field' => 'ch.included', 'render' => 'renderBoolean', 'size' => 0.7, 'translate' => true, 'spec' => 'ch.included', 'fieldType' => BaseList::TYPE_BOOL, 'visible' => 'N'],
|
||||
'charge_checked' => ['field' => 'ch.checked', 'render' => 'renderBoolean', 'size' => 0.7, 'translate' => true, 'spec' => 'ch.checked', 'fieldType' => BaseList::TYPE_BOOL, 'visible' => 'N'],
|
||||
],
|
||||
];
|
||||
|
||||
protected function getVats()
|
||||
{
|
||||
return sqlQueryBuilder()
|
||||
->select('id', 'vat')
|
||||
->from('vats')
|
||||
->execute()
|
||||
->fetchAll();
|
||||
}
|
||||
|
||||
public function customizeTableDef($tableDef)
|
||||
{
|
||||
$tableDef = parent::customizeTableDef($tableDef);
|
||||
|
||||
$tableDef['fields']['type']['fieldOptions'] = [
|
||||
'product' => translate('type_product'),
|
||||
'order' => translate('type_order'),
|
||||
];
|
||||
|
||||
$vats = $this->getVats();
|
||||
|
||||
foreach ($vats as $vat) {
|
||||
$tableDef['fields']['vat']['fieldOptions'][(int) $vat['id']] = $vat['vat'].'%';
|
||||
}
|
||||
|
||||
return $tableDef;
|
||||
}
|
||||
|
||||
public function renderVat($values, $column)
|
||||
{
|
||||
$value = $this->getListRowValue($values, $column['field']);
|
||||
if ($value) {
|
||||
return getVat($value).'%';
|
||||
}
|
||||
|
||||
return translate('byProducts', 'vats');
|
||||
}
|
||||
|
||||
public function renderType($values, $column)
|
||||
{
|
||||
$type = $values['type'] ?? '';
|
||||
|
||||
return translate("type_{$type}", 'productsCharges', true);
|
||||
}
|
||||
|
||||
public function getQuery()
|
||||
{
|
||||
$qb = sqlQueryBuilder()->select('*')->from('charges', 'ch');
|
||||
|
||||
return $qb;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Admin\lists;
|
||||
|
||||
use KupShop\I18nBundle\Admin\lists\TranslateList;
|
||||
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
|
||||
use KupShop\ProductsChargesBundle\Translations\ProductsChargesTranslation;
|
||||
|
||||
class TranslateProductsChargesList extends TranslateList
|
||||
{
|
||||
protected $template = 'list/translateProductsCharges.tpl';
|
||||
|
||||
protected $listType = 'translateProductsCharges';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->translation = ServiceContainer::getService(ProductsChargesTranslation::class);
|
||||
}
|
||||
}
|
||||
|
||||
$main_class = TranslateProductsChargesList::class;
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Admin;
|
||||
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
use KupShop\ProductsChargesBundle\Translations\ProductsChargesTranslation;
|
||||
|
||||
class ProductsCharges extends \Window
|
||||
{
|
||||
protected $tableName = 'charges';
|
||||
protected $nameField = 'admin_title';
|
||||
|
||||
protected $required = [
|
||||
'admin_title' => true,
|
||||
];
|
||||
|
||||
protected $defaults = [
|
||||
'figure' => 'Y',
|
||||
];
|
||||
|
||||
public function get_vars()
|
||||
{
|
||||
$vars = parent::get_vars();
|
||||
$pageVars = getVal('body', $vars);
|
||||
|
||||
$vatValue = 0;
|
||||
if (!empty($pageVars['data']['vat'])) {
|
||||
$vatValue = getVat($pageVars['data']['vat']);
|
||||
}
|
||||
|
||||
$pageVars['data']['vatValue'] = $vatValue;
|
||||
$pageVars['data']['price'] = toDecimal($pageVars['data']['price'] ?? 0);
|
||||
$pageVars['data']['currencies'] = Contexts::get(CurrencyContext::class)->getSupported();
|
||||
$pageVars['data']['translation_figure'] = $this->getTranslationUtil()?->getTranslationsFigure(ProductsChargesTranslation::class, $this->getID());
|
||||
$this->unserializeCustomData($pageVars['data']);
|
||||
|
||||
$pageVars['vats'] = \KupShop\KupShopBundle\Context\VatContext::getAdminVats(true);
|
||||
|
||||
$vars['body'] = $pageVars;
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
$data = parent::getData();
|
||||
|
||||
if (getVal('Submit')) {
|
||||
$this->serializeCustomData($data);
|
||||
if ($data['priceWithVat'] && $data['price'] > 0) {
|
||||
$data['price'] = toDecimal($data['price'])->removeVat(getVat($data['vat']));
|
||||
}
|
||||
if (trim($data['product']) === '') {
|
||||
$data['id_product'] = '';
|
||||
$data['id_variation'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function handleUpdate()
|
||||
{
|
||||
$data = $this->getData();
|
||||
|
||||
$result = parent::handleUpdate();
|
||||
|
||||
if ($result) {
|
||||
// Save translations figure
|
||||
$this->getTranslationUtil()?->updateTranslationsFigure(ProductsChargesTranslation::class, $this->getID(), $data['translation_figure'] ?? []);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
return ProductsCharges::class;
|
||||
@@ -0,0 +1,19 @@
|
||||
{extends "actions/action.tpl"}
|
||||
|
||||
{block "action"}
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'orders_charge'|translate:'productsCharges'}</label></div>
|
||||
<div class="col-md-8">
|
||||
{print_select name="{$name}[data][id_charge]" var=$charges selected=$data.id_charge}
|
||||
</div>
|
||||
<div class="col-md-1">
|
||||
{if $data.id_charge}
|
||||
<a href="javascript:nw('productsCharges', {$data.id_charge})" title="{'titleEdit'|translate:'productsCharges'}">
|
||||
<span class="badge" title="{'titleEdit'|translate:'productsCharges'}">
|
||||
<i class="glyphicon glyphicon-cog"></i>
|
||||
</span>
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
@@ -0,0 +1,5 @@
|
||||
{extends file="[I18nBundle]/list/translate.tpl"}
|
||||
|
||||
{block translationObjectTitle}
|
||||
{$object.id} | <a title="{'titleEdit'|translate:'productsCharges'}" href="javascript:nw('productsCharges', '{$object.id}')">{$object.title}</a>
|
||||
{/block}
|
||||
@@ -0,0 +1,195 @@
|
||||
{extends file="[shared]/window.tpl"}
|
||||
|
||||
{block tabs}
|
||||
{windowTab id='flap1'}
|
||||
{/block}
|
||||
|
||||
{block tabsContent}
|
||||
<div id="flap1" class="tab-pane fade active in boxStatic">
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'name'|translate}</label></div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control input-sm" name="data[admin_title]" size="30" maxlength="100" value="{$body.data.admin_title}"/>
|
||||
</div>
|
||||
<div class="col-md-2 control-label">
|
||||
<label>{'display_name'|translate}</label>
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'display_name_tooltip'|translate}"><i class="glyphicon glyphicon-question-sign"></i></a>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control input-sm" name="data[title]" size="30" maxlength="100" value="{$body.data.title}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'descr'|translate}</label>
|
||||
{insert_llm_button type='product_charges' target="data[descr]"}
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<textarea class="form-control input-sm" name="data[descr]">{$body.data.descr}</textarea>
|
||||
{insert_wysiwyg target="data[descr]"}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'active'|translate}</label></div>
|
||||
<div class="col-md-10">
|
||||
{print_toggle name="figure" value=$body.data.figure}
|
||||
{include 'utils/translations.figure.tpl' figureData=$body.data.translation_figure parentFigure=$body.data.figure}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'type'|translate}</label></div>
|
||||
<div class="col-md-10">
|
||||
<div class="radio pull-left">
|
||||
<input type="radio" name="data[type]" class="check" value="product" {$body.data.type|checked:'product'} id="t1">
|
||||
<label for="t1"> {'type_product'|translate}</label>
|
||||
<input type="radio" name="data[type]" class="check" value="order" {$body.data.type|checked:'order'} id="t2">
|
||||
<label for="t2"> {'type_order'|translate}</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'price'|translate}</label></div>
|
||||
<div class="col-md-3">
|
||||
<div class="input-group" data-price-dropdown>
|
||||
<div class="input-group-btn">
|
||||
<select class="selecter" name="data[currency]">
|
||||
{foreach $body.data.currencies as $currencyID => $currency}
|
||||
<option{if $currencyID == $body.data.currency} selected{/if}>{$currencyID}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{* Pouzivam cenu bez DPH primo z DB a cenu s DPH vypocita JS - priceVatDropdown, takze nechci provadet format_editable_price *}
|
||||
<input data-price="" type="text" class="form-control input-sm" name="data[price]" id="price"
|
||||
value="{$body.data.price}" />
|
||||
|
||||
<div class="input-group-btn" data-dropdown>
|
||||
<a class="btn btn-primary dropdown-toggle btn-sm" data-toggle="dropdown">
|
||||
<span data-dropdown-state>
|
||||
{'withTax'|translate:'choice'}
|
||||
</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a data-value="1">{'withTax'|translate:'choice'}</a></li>
|
||||
<li><a data-value="0">{'withoutTax'|translate:'choice'}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<input type="hidden" name="data[priceWithVat]" data-price-vat="{$body.data.vatValue}" value="0"/>
|
||||
<script type="text/javascript">
|
||||
priceVatDropdown($('[data-price-dropdown]'), {if is_null($body.data.vat)}0{else}1{/if});
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-1 control-label">
|
||||
<label>{'or'|translate:'choice'}</label>
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'percentage_tooltip'|translate}"><i class="glyphicon glyphicon-question-sign"></i></a>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control input-sm" name="data[percentage]" id="percentage" maxlength="20"
|
||||
value="{$body.data.percentage}"/>
|
||||
<span class="input-group-addon">%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label"><label>{'vat'|translate}</label></div>
|
||||
<div class="col-md-3">
|
||||
<select name="data[vat]" class="selecter" id="priceVat">
|
||||
<option value="" data-vat="0" {if is_null($body.data.vat)}selected{/if}>{'byProducts'|translate:'vats'}</option>
|
||||
{foreach $body.vats as $key => $vat}
|
||||
<option value="{$vat.id}" data-vat="{$vat.vat}" {if $body.data.vat == $vat.id}selected{/if}>
|
||||
{$vat.descr}
|
||||
</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group product_autocomplete">
|
||||
<div class="col-md-2 control-label"><label>{'product'|translate}</label></div>
|
||||
<div class="col-md-6">
|
||||
<input type="text" data-autocomplete-search="product" autocomplete="off" name="data[product]"
|
||||
class="form-control input-sm autocomplete-control" placeholder="Vyhledat produkt"
|
||||
data-preload="product_variation" value="{if $body.data.id_product}{$body.data.id_product}{if $body.data.id_variation}-{$body.data.id_variation}{/if}{/if}">
|
||||
<input type="hidden" name="data[id_product]" value="{$body.data.id_product}">
|
||||
<input type="hidden" name="data[id_variation]" value="{$body.data.id_variation}">
|
||||
<script type="application/javascript">
|
||||
$('[data-autocomplete-search="product"]').adminVariationAutoComplete({
|
||||
allowSelectProduct: false,
|
||||
select: function (e, item) {
|
||||
let { product, variation } = item;
|
||||
|
||||
if (variation && typeof variation !== 'string' && variation.id) {
|
||||
variation = variation.id
|
||||
}
|
||||
|
||||
$('[name="data[id_product]"]').val(product.id);
|
||||
$('[name="data[id_variation]"]').val(variation);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</div>
|
||||
<div class="col-md-4 toggle-wrapper">
|
||||
<div class="checkbox">
|
||||
{$checked = ''}
|
||||
{if $body.data.data.order_not_in_store}
|
||||
{$checked = 'checked'}
|
||||
{/if}
|
||||
<input type="checkbox" class="check" value="1" id="order_not_in_store"
|
||||
name="data[data][order_not_in_store]" {$checked}>
|
||||
<label class="small" for="order_not_in_store">Povolit objednat zboží, které není skladem</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-group">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-10 d-flex align-center">
|
||||
{print_toggle value=$body.data.required|default:'Y' name="required"}
|
||||
<label>{'charge_required'|translate}
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'charge_required_help'|translate}"><i
|
||||
class="bi bi-question-circle"></i></a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-10 d-flex align-center">
|
||||
{print_toggle value=$body.data.checked|default:'N' name="checked"}
|
||||
<label>{'charge_checked'|translate}
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'charge_checked_help'|translate}"><i
|
||||
class="bi bi-question-circle"></i></a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-10 d-flex align-center">
|
||||
{print_toggle value=$body.data.included|default:'N' name="included"}
|
||||
<label>{'charge_included'|translate}
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'charge_included_help'|translate}"><i
|
||||
class="bi bi-question-circle"></i></a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row form-group">
|
||||
<div class="col-md-2"></div>
|
||||
<div class="col-md-10 d-flex align-center">
|
||||
{print_toggle value=$body.data.data.onetime|default:'N' nameRaw="data[data][onetime]"}
|
||||
<label>{'charge_onetime'|translate}
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'charge_onetime_help'|translate}"><i
|
||||
class="bi bi-question-circle"></i></a>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{block "custom-data"}{/block}
|
||||
{/block}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\AdminRegister;
|
||||
|
||||
use KupShop\AdminBundle\AdminRegister\AdminRegister;
|
||||
use KupShop\AdminBundle\AdminRegister\IAdminRegisterDynamic;
|
||||
use KupShop\AdminBundle\AdminRegister\IAdminRegisterStatic;
|
||||
|
||||
class ProductsChargesAdminRegister extends AdminRegister implements IAdminRegisterDynamic, IAdminRegisterStatic
|
||||
{
|
||||
public function getDynamicMenu(): array
|
||||
{
|
||||
$menu = [
|
||||
static::createMenuItem('productsMenu',
|
||||
[
|
||||
'name' => 'productsCharges',
|
||||
'title' => translate('navigation', 'productsCharges'),
|
||||
'left' => 's=menu.php&type=productsCharges',
|
||||
'right' => 's=list.php&type=productsCharges',
|
||||
]),
|
||||
];
|
||||
|
||||
if (findModule(\Modules::TRANSLATIONS)) {
|
||||
$menu[] = self::createMenuItem('translate',
|
||||
[
|
||||
'name' => 'translate.translateProductsCharges',
|
||||
'title' => translate('navigation', 'productsCharges'),
|
||||
'right' => 's=list.php&type=translateProductsCharges',
|
||||
]);
|
||||
}
|
||||
|
||||
return $menu;
|
||||
}
|
||||
|
||||
public function getDynamicPermissions(): array
|
||||
{
|
||||
return [
|
||||
static::createPermissions('productsCharges', [\Modules::PRODUCTS_CHARGES], ['CHARGES']),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\EventListener;
|
||||
|
||||
use KupShop\KupShopBundle\Util\Price\Price;
|
||||
use KupShop\OrderingBundle\Event\OrderItemEvent;
|
||||
use KupShop\OrderingBundle\Util\Order\OrderItemInfo;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class OrderItemListener implements EventSubscriberInterface
|
||||
{
|
||||
use \DatabaseCommunication;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
OrderItemEvent::ITEM_CREATED => [
|
||||
['itemCharge', 200],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function itemCharge(OrderItemEvent $event)
|
||||
{
|
||||
$product = $event->getProduct();
|
||||
$data = $event->getData();
|
||||
$items_table = $data['items_table'];
|
||||
$row = $data['row'];
|
||||
|
||||
$note = $product->parseNote($row['note'] ?? false);
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// kdyz je u zbozi příplatek, ktery nebyl jeste zapocitan v cene
|
||||
foreach ($product->fetchCharges($note['charges'] ?? []) as $charge) {
|
||||
if ($charge['included'] == 'N' && $charge['active']) {
|
||||
/** @var Price $price */
|
||||
$price = $charge['price'];
|
||||
|
||||
$PiecePrice = $price->getPriceWithoutVat();
|
||||
|
||||
if (($charge['data']['onetime'] ?? 'N') === 'Y') {
|
||||
$chargePieces = \DecimalConstants::one();
|
||||
} else {
|
||||
$chargePieces = toDecimal($row['pieces']);
|
||||
}
|
||||
|
||||
$TotalPrice = $PiecePrice->mul($chargePieces);
|
||||
|
||||
$itemData = [
|
||||
'charge' => [
|
||||
'id_product_charge' => $charge['id'],
|
||||
'id_charge' => $charge['id_charge'],
|
||||
'id_product' => $charge['id_product'],
|
||||
'id_item_parent' => $row['id'],
|
||||
],
|
||||
'item_type' => OrderItemInfo::TYPE_CHARGE,
|
||||
];
|
||||
$productTitle = !empty($product->title) ? $product->title : $product->descr;
|
||||
$chargeTitle = !empty($charge['title']) ? $charge['title'] : $charge['admin_title'];
|
||||
if (!empty($charge['product']['code'])) {
|
||||
$code = str_replace('%CODE', trim($charge['product']['code']), translate('code', 'order'));
|
||||
$chargeTitle = "{$chargeTitle} {$code}";
|
||||
}
|
||||
$productTitle = "{$chargeTitle}: {$productTitle}";
|
||||
$charge_product = $charge['product'] ?? null;
|
||||
$id_product = ($charge_product ? $charge_product->id : null);
|
||||
$id_variation = ($charge_product ? $charge_product->variationId : null);
|
||||
// zapsat polozku do DB
|
||||
$this->insertSQL(
|
||||
$items_table,
|
||||
[
|
||||
'id_order' => $row['id_order'],
|
||||
'id_product' => $id_product,
|
||||
'id_variation' => $id_variation,
|
||||
'pieces' => $chargePieces,
|
||||
'pieces_reserved' => $chargePieces,
|
||||
'piece_price' => $PiecePrice,
|
||||
'total_price' => $TotalPrice,
|
||||
'descr' => $productTitle,
|
||||
'tax' => $this->getChargeItemVat($product, $charge),
|
||||
'note' => json_encode($itemData),
|
||||
]
|
||||
);
|
||||
if ($charge_product) {
|
||||
$charge_product->sell($id_variation, $row['pieces']);
|
||||
}
|
||||
|
||||
// total price of whole order
|
||||
$orderTotalPrice = $event->getPrice();
|
||||
$orderTotalPrice = $orderTotalPrice->add($TotalPrice->addVat($this->getChargeItemVat($product, $charge)));
|
||||
|
||||
// update total price of order
|
||||
$event->setPrice($orderTotalPrice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function getChargeItemVat(\Product $product, array $charge): float
|
||||
{
|
||||
return $charge['price']->getVat()->asFloat();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\EventListener;
|
||||
|
||||
use KupShop\KupShopBundle\Util\Price\Price;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\ChargePurchaseItem;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\ProductPurchaseItem;
|
||||
use KupShop\OrderingBundle\Event\PurchaseStateCreatedEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class PurchaseStateListener implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
PurchaseStateCreatedEvent::class => [
|
||||
['addProductCharges', 200],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function addProductCharges(PurchaseStateCreatedEvent $event): void
|
||||
{
|
||||
foreach ($event->getPurchaseState()->getProducts() as $purchaseItem) {
|
||||
$this->addProductChargesToPurchaseItem(
|
||||
$purchaseItem,
|
||||
$purchaseItem->getProduct()->fetchCharges(
|
||||
$purchaseItem->getNote()['charges'] ?? []
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function addProductChargesToPurchaseItem(ProductPurchaseItem $purchaseItem, array $charges): void
|
||||
{
|
||||
foreach ($charges as $charge) {
|
||||
if (!($charge['included'] == 'N' && $charge['active'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var Price $price */
|
||||
$price = $charge['price'];
|
||||
|
||||
if (($charge['data']['onetime'] ?? 'N') === 'Y') {
|
||||
$chargePieces = \DecimalConstants::one();
|
||||
} else {
|
||||
$chargePieces = toDecimal($purchaseItem->getPieces());
|
||||
}
|
||||
|
||||
$totalPrice = new Price($price->getPriceWithoutVat()->mul($chargePieces), $price->getCurrency(), $price->getVat());
|
||||
|
||||
$purchaseItem->addAdditionalItem(
|
||||
new ChargePurchaseItem($charge['title'], $totalPrice, $charge['id'])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class ProductsChargesBundle extends Bundle
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
_defaults:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
||||
KupShop\ProductsChargesBundle\:
|
||||
resource: ../../{Actions,AdminRegister,EventListener,Translations,Util}
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Resources\upgrade;
|
||||
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
|
||||
class ProductsChargesUpgrade extends \UpgradeNew
|
||||
{
|
||||
public function check_ChargesTable()
|
||||
{
|
||||
return $this->checkTableExists('charges');
|
||||
}
|
||||
|
||||
/** Create product charges table */
|
||||
public function upgrade_ChargesTable()
|
||||
{
|
||||
sqlQuery('CREATE TABLE charges (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
title VARCHAR(100) NOT NULL,
|
||||
price DECIMAL(15,4) NOT NULL,
|
||||
vat INT(11) UNSIGNED,
|
||||
FOREIGN KEY (vat) REFERENCES vats(id) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
');
|
||||
|
||||
sqlQuery('DROP TABLE IF EXISTS products_charges;');
|
||||
|
||||
sqlQuery('CREATE TABLE products_charges (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
id_charge INT NOT NULL,
|
||||
id_product INT NOT NULL,
|
||||
included ENUM("Y", "N") DEFAULT "N" NOT NULL,
|
||||
required ENUM("Y", "N") DEFAULT "Y" NOT NULL,
|
||||
FOREIGN KEY (id_charge) REFERENCES charges(id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
FOREIGN KEY (id_product) REFERENCES products(id) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_chargesRequired()
|
||||
{
|
||||
return $this->checkColumnExists('charges', 'required');
|
||||
}
|
||||
|
||||
/** Add columns to `charges` table */
|
||||
public function upgrade_chargesRequired()
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges
|
||||
ADD COLUMN descr TEXT DEFAULT NULL,
|
||||
ADD COLUMN included ENUM("Y", "N") DEFAULT "N" NOT NULL,
|
||||
ADD COLUMN required ENUM("Y", "N") DEFAULT "Y" NOT NULL,
|
||||
ADD COLUMN checked ENUM("Y", "N") DEFAULT "N" NOT NULL,
|
||||
ADD COLUMN orders_charge ENUM("Y", "N") DEFAULT "N" NOT NULL;
|
||||
ALTER TABLE products_charges DROP COLUMN included, DROP COLUMN required;');
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_chargesTranslations()
|
||||
{
|
||||
return findModule(\Modules::TRANSLATIONS) && $this->checkTableExists('charges_translations');
|
||||
}
|
||||
|
||||
/** Create charges_translations table */
|
||||
public function upgrade_chargesTranslations()
|
||||
{
|
||||
sqlQuery('CREATE TABLE IF NOT EXISTS charges_translations
|
||||
(
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
id_charge INT NOT NULL,
|
||||
id_language VARCHAR(2) NOT NULL,
|
||||
id_admin INT DEFAULT NULL,
|
||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated DATETIME DEFAULT NULL,
|
||||
title VARCHAR(100) DEFAULT NULL,
|
||||
descr TEXT DEFAULT NULL,
|
||||
FOREIGN KEY (id_charge)
|
||||
REFERENCES charges (id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE UNIQUE INDEX charges_translations_id_charge_id_language_uindex
|
||||
ON charges_translations (id_charge, id_language);
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_RemoveCharge()
|
||||
{
|
||||
return !$this->checkColumnExists('products', 'charge_id');
|
||||
}
|
||||
|
||||
/** Remove product.charge_id, product.charge_included */
|
||||
public function upgrade_RemoveCharge()
|
||||
{
|
||||
sqlQuery('alter table products
|
||||
drop column charge_id,
|
||||
drop column charge_included');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_chargesPercentage()
|
||||
{
|
||||
return $this->checkColumnExists('charges', 'percentage');
|
||||
}
|
||||
|
||||
/** Add percentage to `charges` table */
|
||||
public function upgrade_chargesPercentage()
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges
|
||||
ADD COLUMN percentage SMALLINT NULL,
|
||||
MODIFY price decimal(15,4) NULL;
|
||||
');
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargeCurrencyColumn(): bool
|
||||
{
|
||||
return findModule(\Modules::CURRENCIES) && $this->checkColumnExists('charges', 'currency');
|
||||
}
|
||||
|
||||
public function upgrade_ChargeCurrencyColumn(): void
|
||||
{
|
||||
$defaultCurrency = Contexts::get(CurrencyContext::class)->getDefaultId();
|
||||
|
||||
sqlQuery('ALTER TABLE charges ADD COLUMN currency VARCHAR(3) DEFAULT ? NOT NULL AFTER id ', [$defaultCurrency]);
|
||||
sqlQuery('
|
||||
ALTER TABLE charges ADD CONSTRAINT fk_charges_currencies FOREIGN KEY (currency)
|
||||
REFERENCES currencies(id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargeAdminTitleColumn(): bool
|
||||
{
|
||||
return $this->checkColumnExists('charges', 'admin_title');
|
||||
}
|
||||
|
||||
public function upgrade_ChargeAdminTitleColumn(): void
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges ADD COLUMN admin_title VARCHAR(100) NOT NULL AFTER title ');
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargesDataColumn()
|
||||
{
|
||||
return $this->checkColumnExists('charges', 'data');
|
||||
}
|
||||
|
||||
/** Add 'data' column into table 'charges' */
|
||||
public function upgrade_ChargesDataColumn()
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges ADD COLUMN data MEDIUMTEXT DEFAULT NULL');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_RemoveOrdersCharge()
|
||||
{
|
||||
return !$this->checkColumnExists('charges', 'orders_charge');
|
||||
}
|
||||
|
||||
/** Remove charges.orders_charge, add charges.type column */
|
||||
public function upgrade_RemoveOrdersCharge()
|
||||
{
|
||||
sqlQuery("ALTER TABLE charges ADD COLUMN type ENUM('order', 'product') DEFAULT 'product'");
|
||||
sqlQuery("UPDATE charges SET type = 'order' WHERE orders_charge = 'Y'");
|
||||
sqlQuery('ALTER TABLE charges DROP COLUMN orders_charge');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargesProductColumn()
|
||||
{
|
||||
return $this->checkColumnExists('charges', 'id_product');
|
||||
}
|
||||
|
||||
/** Add id_product column into table 'charges' */
|
||||
public function upgrade_ChargesProductColumn()
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges ADD COLUMN id_product int DEFAULT NULL');
|
||||
sqlQuery('ALTER TABLE charges ADD CONSTRAINT charges_products_id_fk
|
||||
FOREIGN KEY (id_product) REFERENCES products (id)
|
||||
ON UPDATE CASCADE ON DELETE SET NULL');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargesProductVariationColumn()
|
||||
{
|
||||
return findModule(\Modules::PRODUCTS_VARIATIONS) && $this->checkColumnExists('charges', 'id_variation');
|
||||
}
|
||||
|
||||
/** Add id_variation column into table 'charges' */
|
||||
public function upgrade_ChargesProductVariationColumn()
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges ADD COLUMN id_variation int DEFAULT NULL');
|
||||
sqlQuery('ALTER TABLE charges ADD CONSTRAINT charges_products_variations_id_fk
|
||||
FOREIGN KEY (id_variation) REFERENCES products_variations (id)
|
||||
ON UPDATE CASCADE ON DELETE SET NULL');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargesFigureColumn(): bool
|
||||
{
|
||||
return $this->checkColumnExists('charges', 'figure');
|
||||
}
|
||||
|
||||
/** charges: add `figure` column */
|
||||
public function upgrade_ChargesFigureColumn(): void
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges ADD COLUMN figure ENUM("Y", "N") DEFAULT "Y" NOT NULL AFTER admin_title');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ChargesTranslationsFigureColumn(): bool
|
||||
{
|
||||
return findModule(\Modules::TRANSLATIONS) && $this->checkColumnExists('charges_translations', 'figure');
|
||||
}
|
||||
|
||||
/** charges_translations: add `figure` column */
|
||||
public function upgrade_ChargesTranslationsFigureColumn(): void
|
||||
{
|
||||
sqlQuery('ALTER TABLE charges_translations ADD COLUMN figure ENUM("Y", "N") DEFAULT NULL AFTER title');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
}
|
||||
175
bundles/KupShop/ProductsChargesBundle/Tests/ChargesTest.json
Normal file
175
bundles/KupShop/ProductsChargesBundle/Tests/ChargesTest.json
Normal file
@@ -0,0 +1,175 @@
|
||||
{
|
||||
"charges": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Volitelny za 100",
|
||||
"figure": "Y",
|
||||
"price": "82.6446",
|
||||
"vat": 1,
|
||||
"descr": "pokus",
|
||||
"included": "N",
|
||||
"required": "N",
|
||||
"checked": "Y",
|
||||
"type": "product"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"title": "povinny",
|
||||
"figure": "Y",
|
||||
"price": "100.0000",
|
||||
"vat": 1,
|
||||
"descr": "nejaky ten popis",
|
||||
"included": "N",
|
||||
"required": "Y",
|
||||
"checked": "N",
|
||||
"type": "product"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"title": "V ceně",
|
||||
"figure": "Y",
|
||||
"price": "60.0000",
|
||||
"vat": 1,
|
||||
"descr": null,
|
||||
"included": "Y",
|
||||
"required": "Y",
|
||||
"checked": "N",
|
||||
"type": "product"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"title": "Objednavkovy priplatek 100 Kc",
|
||||
"figure": "Y",
|
||||
"price": "82.6446",
|
||||
"vat": 1,
|
||||
"descr": "pokus",
|
||||
"included": "N",
|
||||
"required": "Y",
|
||||
"checked": "N",
|
||||
"type": "order"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"title": "Ekologicke balení",
|
||||
"figure": "Y",
|
||||
"price": "82.6446",
|
||||
"vat": 1,
|
||||
"descr": "pokus",
|
||||
"included": "N",
|
||||
"required": "N",
|
||||
"checked": "N",
|
||||
"type": "order"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"title": "Skryty priplatek",
|
||||
"figure": "N",
|
||||
"price": "82.6446",
|
||||
"vat": 1,
|
||||
"descr": "pokus",
|
||||
"included": "N",
|
||||
"required": "Y",
|
||||
"checked": "N",
|
||||
"type": "product"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"title": "Produktovy priplatek za 200",
|
||||
"figure": "N",
|
||||
"price": "165.2893",
|
||||
"vat": 1,
|
||||
"descr": "pokus",
|
||||
"included": "N",
|
||||
"required": "N",
|
||||
"checked": "Y",
|
||||
"type": "product"
|
||||
}
|
||||
],
|
||||
"products_charges": [
|
||||
{
|
||||
"id": 1,
|
||||
"id_charge": 1,
|
||||
"id_product": 1
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"id_charge": 3,
|
||||
"id_product": 3
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"id_charge": 2,
|
||||
"id_product": 2
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"id_charge": 7,
|
||||
"id_product": 8
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"id_charge": 8,
|
||||
"id_product": 3
|
||||
}
|
||||
],
|
||||
"order_discounts": [
|
||||
{
|
||||
"id": 56,
|
||||
"date_created": "2022-03-28 09:36:01",
|
||||
"name": "Dobrovolný příplatek",
|
||||
"display_name": "",
|
||||
"uses_count": 4,
|
||||
"active": "Y",
|
||||
"data": null,
|
||||
"position": 48
|
||||
},
|
||||
{
|
||||
"id": 55,
|
||||
"date_created": "2022-03-28 09:36:01",
|
||||
"name": "Pojištění dopravy zásilky",
|
||||
"display_name": "",
|
||||
"uses_count": 4,
|
||||
"active": "Y",
|
||||
"data": null,
|
||||
"position": 48
|
||||
},
|
||||
{
|
||||
"id": 54,
|
||||
"date_created": "2022-03-28 09:32:50",
|
||||
"name": "Balné",
|
||||
"display_name": "",
|
||||
"uses_count": 3,
|
||||
"active": "Y",
|
||||
"data": null,
|
||||
"position": 47
|
||||
}
|
||||
],
|
||||
"order_discounts_triggers": [
|
||||
{
|
||||
"id": 112,
|
||||
"id_order_discount": 54,
|
||||
"type": "price_range",
|
||||
"data": "{\"min\":\"\",\"max\":\"500\",\"withVat\":\"1\"}"
|
||||
}
|
||||
],
|
||||
"order_discounts_actions": [
|
||||
{
|
||||
"id": 64,
|
||||
"id_order_discount": 55,
|
||||
"type": "orders_charge",
|
||||
"data": "{\"id_charge\":\"4\"}"
|
||||
},
|
||||
{
|
||||
"id": 63,
|
||||
"id_order_discount": 54,
|
||||
"type": "orders_charge",
|
||||
"data": "{\"id_charge\":\"5\"}"
|
||||
},
|
||||
{
|
||||
"id": 65,
|
||||
"id_order_discount": 56,
|
||||
"type": "orders_charge",
|
||||
"data": "{\"id_charge\":\"6\"}"
|
||||
}
|
||||
]
|
||||
}
|
||||
173
bundles/KupShop/ProductsChargesBundle/Tests/ChargesTest.php
Normal file
173
bundles/KupShop/ProductsChargesBundle/Tests/ChargesTest.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Tests;
|
||||
|
||||
use KupShop\DevelopmentBundle\Util\Tests\CartTestTrait;
|
||||
use KupShop\OrderingBundle\Entity\Purchase\ProductPurchaseItem;
|
||||
use KupShop\OrderingBundle\Util\Order\OrderItemInfo;
|
||||
use Query\Operator;
|
||||
|
||||
class ChargesTest extends \DatabaseTestCase
|
||||
{
|
||||
use CartTestTrait;
|
||||
|
||||
/**
|
||||
* BUG: Doprava nebyla v objednavce zdarma pokud ji aktivoval produktovy priplatek.
|
||||
*
|
||||
* Pokud mam v kosiku produkt a pridam produktovy priplatek, diky kteremu ziskam narok na dopravu zdarma, tak se doprava zdarma musi
|
||||
* projevit i do objednavky.
|
||||
*/
|
||||
public function testProductChargeWithFreeDelivery(): void
|
||||
{
|
||||
$this->setActiveCharges([8]);
|
||||
sqlQueryBuilder()->update('order_discounts')->directValues(['active' => 'N'])->execute();
|
||||
|
||||
$this->prepareCart();
|
||||
$this->insertProduct(3, pieces: 2);
|
||||
$this->setDeliveryType(4);
|
||||
|
||||
$this->recalculateCart();
|
||||
|
||||
$products = $this->cart->getPurchaseState()->getProducts();
|
||||
|
||||
$this->assertCount(1, $products, 'V košíku je jeden produkt');
|
||||
|
||||
/** @var ProductPurchaseItem $product */
|
||||
$product = reset($products);
|
||||
|
||||
$this->assertCount(1, $product->getAdditionalItems(), 'Produkt ma příplatek');
|
||||
|
||||
// tohle failovalo, protoze pri vytvoreni objednavky se produktovy priplatek nezapocital a doprava nebyla v objednavce zdarma
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
/** @dataProvider data_testProductFetchCharges */
|
||||
public function testProductFetchCharges(int $productId, int $expectedCount): void
|
||||
{
|
||||
$product = new \Product();
|
||||
$product->createFromDB($productId);
|
||||
|
||||
$this->assertCount($expectedCount, $product->fetchCharges());
|
||||
}
|
||||
|
||||
public function data_testProductFetchCharges(): iterable
|
||||
{
|
||||
yield 'Priplatek u produktu' => [1, 1];
|
||||
yield 'Skryty priplatek u produktu nesmi byt nacten' => [8, 0];
|
||||
}
|
||||
|
||||
public function testHiddenProductChargeIsNotUsed(): void
|
||||
{
|
||||
$this->prepareCart();
|
||||
$this->insertProduct(8);
|
||||
|
||||
$this->recalculateCart();
|
||||
|
||||
$this->assertEquals(5090, $this->cart->totalPricePay->asFloat(), 'Cena produktu je 5090 Kc a cena priplatku u nej je 100 Kc, ale priplatek neni aktivni, takze nesmi byt pricteny');
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
public function testDefaultOnCharge()
|
||||
{
|
||||
$this->prepareCart();
|
||||
$this->insertProduct(1, 16);
|
||||
|
||||
$this->recalculateCart();
|
||||
// Cena je 800 za produkt + 100 za příplatek + povinny Objednavkovy priplatek 100 Kc
|
||||
$this->assertEquals(1000, $this->cart->totalPricePay->asFloat());
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
public function testDefaultOnTurnedOffCharge()
|
||||
{
|
||||
$this->prepareCart();
|
||||
$itemId = $this->insertProduct(1, 16);
|
||||
$this->cart->updateItem($itemId, ['note' => ['charges' => ['1' => '']]]);
|
||||
|
||||
$this->recalculateCart();
|
||||
// Cena je 800 za produkt + 0 za vyonutý příplatek + povinny Objednavkovy priplatek 100 Kc
|
||||
$this->assertEquals(900, $this->cart->totalPricePay->asFloat());
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
public function testChargeWithFreeDelivery()
|
||||
{
|
||||
// dorpava zdarma od 6150 -> celková cena objednávky je 5999 produkt + 100 povinný příplatek + 100 volitelný příplatek
|
||||
sqlQueryBuilder()->update('delivery_type')->set('price_dont_countin_from', 6150)->where(Operator::equals(['id' => 1]))->execute();
|
||||
|
||||
$this->prepareCart();
|
||||
$this->cart->setActionHandlersData([65 => ['checked' => 'Y']]); // nepovinný příplatek - 100
|
||||
|
||||
// Doprava a platba - 100Kč (zdarma od 6150Kč)
|
||||
$this->cart->setDeliveryAndPayment(3, 3);
|
||||
|
||||
// Cena produktu 5999 Kč + 100Kč příplatek
|
||||
$this->insertProduct(9);
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
public function testRequiredCharge()
|
||||
{
|
||||
$this->prepareCart();
|
||||
$this->insertProduct(2, 9);
|
||||
|
||||
$this->recalculateCart();
|
||||
// Cena je 2250 za produkt + 121 za příplatek + povinny Objednavkovy priplatek 100 Kc
|
||||
$this->assertEquals(2471, $this->cart->totalPricePay->asFloat());
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
public function testOrderCharge()
|
||||
{
|
||||
$orderItemInfo = $this->get(OrderItemInfo::class);
|
||||
|
||||
$this->prepareCart();
|
||||
$this->insertProduct(8);
|
||||
|
||||
$this->cart->charges[] = 4;
|
||||
|
||||
$this->recalculateCart();
|
||||
|
||||
// Cena je 4990 za produkt + 100 za příplatek
|
||||
$this->assertEquals(5090, $this->cart->totalPricePay->asFloat());
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
|
||||
$items = $this->order->fetchItems();
|
||||
|
||||
$this->assertCount(2, $items, '1 item + 1 order charge should be in items');
|
||||
|
||||
$orderChargeItem = null;
|
||||
foreach ($items as $item) {
|
||||
if ($orderItemInfo->getItemType($item) === OrderItemInfo::TYPE_CHARGE) {
|
||||
$orderChargeItem = $item;
|
||||
}
|
||||
}
|
||||
|
||||
$this->assertNotEmpty($orderChargeItem, 'Check that order charge item exists');
|
||||
}
|
||||
|
||||
protected function getDataSet()
|
||||
{
|
||||
return $this->getJsonDataSetFromFile();
|
||||
}
|
||||
|
||||
private function setActiveCharges(array $ids): void
|
||||
{
|
||||
sqlQueryBuilder()
|
||||
->update('charges')
|
||||
->directValues(['figure' => 'N'])
|
||||
->execute();
|
||||
|
||||
sqlQueryBuilder()
|
||||
->update('charges')
|
||||
->directValues(['figure' => 'Y'])
|
||||
->where(Operator::inIntArray($ids, 'id'))
|
||||
->execute();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"charges": [
|
||||
{
|
||||
"id": 999,
|
||||
"title": "Procentuální 1000%",
|
||||
"price": 0.0,
|
||||
"vat": 1,
|
||||
"percentage": 1000,
|
||||
"descr": "pokus",
|
||||
"included": "Y",
|
||||
"required": "Y",
|
||||
"checked": "Y",
|
||||
"type": "order"
|
||||
}
|
||||
],
|
||||
"products_charges": [
|
||||
{
|
||||
"id": 1,
|
||||
"id_charge": 999,
|
||||
"id_product": 8
|
||||
}
|
||||
],
|
||||
"order_discounts": [
|
||||
{
|
||||
"id": 10,
|
||||
"date_created": "2022-03-28 09:32:50",
|
||||
"name": "Foo Bar 1000%",
|
||||
"display_name": "",
|
||||
"uses_count": 3,
|
||||
"active": "Y",
|
||||
"data": null,
|
||||
"position": 20
|
||||
}
|
||||
],
|
||||
"order_discounts_actions": [
|
||||
{
|
||||
"id": 10,
|
||||
"id_order_discount": 10,
|
||||
"type": "orders_charge",
|
||||
"data": "{\"id_charge\":\"999\"}"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Tests;
|
||||
|
||||
use KupShop\DevelopmentBundle\Util\Tests\CartTestTrait;
|
||||
|
||||
class OrdersChargesTest extends \DatabaseTestCase
|
||||
{
|
||||
use CartTestTrait;
|
||||
|
||||
public function testOrderWithPercentCharge(): void
|
||||
{
|
||||
$this->createCart();
|
||||
$this->assertEquals(0, $this->cart->totalPricePay->asFloat());
|
||||
$this->insertProduct(8);
|
||||
$this->recalculateCart();
|
||||
$this->assertEquals(4990 * 11, $this->cart->getPurchaseState()->getTotalPrice()->getPriceWithVat()->asFloat());
|
||||
$this->assertEquals(4990 * 10, $this->cart->getPurchaseState()->getChargesTotalPrice()->getPriceWithVat()->asFloat());
|
||||
$this->assertEquals(4990, $this->cart->getPurchaseState()->getProductsTotalPrice()->getPriceWithVat()->asFloat());
|
||||
}
|
||||
|
||||
protected function getDataSet()
|
||||
{
|
||||
return $this->getJsonDataSetFromFile();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Translations;
|
||||
|
||||
use KupShop\I18nBundle\Translations\BaseTranslation;
|
||||
|
||||
class ProductsChargesTranslation extends BaseTranslation
|
||||
{
|
||||
protected $columns = [
|
||||
'title' => ['alias' => 'Název', 'maxlength' => 100],
|
||||
'descr' => ['alias' => 'Popis', 'richtext' => true],
|
||||
'figure' => ['alias' => 'Aktivní', 'select' => [null => 'Nenastavovat', 'Y' => 'Ano', 'N' => 'Ne']],
|
||||
];
|
||||
|
||||
protected $tableName = 'charges';
|
||||
|
||||
protected $tableAlias = 'ch';
|
||||
|
||||
protected $nameColumn = 'title';
|
||||
}
|
||||
102
bundles/KupShop/ProductsChargesBundle/Util/ChargesUtil.php
Normal file
102
bundles/KupShop/ProductsChargesBundle/Util/ChargesUtil.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\ProductsChargesBundle\Util;
|
||||
|
||||
use KupShop\I18nBundle\Entity\Currency;
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Context\VatContext;
|
||||
use KupShop\KupShopBundle\Util\Contexts;
|
||||
use KupShop\KupShopBundle\Util\Price\Price;
|
||||
use KupShop\KupShopBundle\Util\Price\PriceCalculator;
|
||||
|
||||
class ChargesUtil
|
||||
{
|
||||
/** @var VatContext */
|
||||
protected $vatContext;
|
||||
|
||||
/** @required */
|
||||
public function setVatContext(VatContext $vatContext)
|
||||
{
|
||||
$this->vatContext = $vatContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param null $data
|
||||
* @param \Variation $product
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function applyData(array $charges, $data = null, $product = null)
|
||||
{
|
||||
if ($data === false) {
|
||||
return $charges;
|
||||
}
|
||||
|
||||
foreach ($charges as &$charge) {
|
||||
$charge['active'] = $this->isChargeActive($charge ?: [], $data);
|
||||
}
|
||||
|
||||
return $charges;
|
||||
}
|
||||
|
||||
public function applyPrices(array $charges, ?\Product $product = null): array
|
||||
{
|
||||
$activeCurrency = Contexts::get(CurrencyContext::class)->getActive();
|
||||
|
||||
foreach ($charges as &$charge) {
|
||||
if ($product && ($charge['percentage'] ?? false)) {
|
||||
$price = $product->getPrice($product->variationId, [], toDecimal(1));
|
||||
$charge['price'] = $this->applyPercentageCharge($price, $charge['percentage'], $charge['price']->getCurrency(), $product['vat']);
|
||||
}
|
||||
|
||||
$vat = null;
|
||||
if ($charge['product']) {
|
||||
// uplatnit sazbu DPH podle priplatkoveho produktu
|
||||
$vat = $charge['product']->getProductPrice()->getVat();
|
||||
} elseif (is_null($charge['vat'])) { // null = "podle produktů"
|
||||
// uplatnit sazbu DPH podle produktu
|
||||
$vat = $product?->getProductPrice()?->getVat();
|
||||
}
|
||||
if (!empty($vat) && ($charge['price']->getVat() != $vat)) {
|
||||
$charge['price'] = new Price($charge['price']->getValue(), $charge['price']->getCurrency(), $vat);
|
||||
}
|
||||
|
||||
$charge['price'] = PriceCalculator::convert($charge['price'], $activeCurrency);
|
||||
}
|
||||
|
||||
return $charges;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $price \Decimal
|
||||
* @param $percentage int
|
||||
* @param $currency Currency
|
||||
*
|
||||
* @return Price
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function applyPercentageCharge($price, $percentage, $currency, $vat)
|
||||
{
|
||||
return new Price($price->div(toDecimal(100))->mul(toDecimal($percentage)), $currency, $vat);
|
||||
}
|
||||
|
||||
protected function isChargeActive(array $charge, ?array $data = null): bool
|
||||
{
|
||||
$id = $charge['id'];
|
||||
|
||||
$active = $charge['checked'] == 'Y';
|
||||
|
||||
if (isset($data[$id])) {
|
||||
$active = ($data[$id] == 'Y' ? true : ($data[$id] == 'N' ? false : (bool) $data[$id]));
|
||||
}
|
||||
|
||||
if ($charge['required'] == 'Y' || $charge['included'] == 'Y') {
|
||||
$active = true;
|
||||
}
|
||||
|
||||
return $active;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user