first commit
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
$txt_str['productsUnits'] = [
|
||||
'short_name_frontend' => 'Zkratka pro web',
|
||||
'short_name_frontend_tooltip' => 'Více jednotek, např. pro balení (4ks, 2ks), bude mít na frontendu vždy zkratku "Ks", ale aby se dalo rozlišit v administraci, zvolíme pro administraci různé zkratky (např. B1 - balení po 1, B2 - balení po 2, atd.). ',
|
||||
'short_name_admin' => 'Zkratka pro admin',
|
||||
'long_name' => 'Dlouhý název',
|
||||
'pieces_precision' => 'Počet desetinných míst',
|
||||
'pieces_in_package' => 'Ks v balení',
|
||||
'flapUnit' => 'Jednotka',
|
||||
'recalculate_to' => 'Přepočet ceny na',
|
||||
'measure_quantity' => 'Jednotek v balení',
|
||||
|
||||
'toolbar_list' => 'Seznam jednotek',
|
||||
'toolbar_add' => 'Přidat novou jednotku',
|
||||
'titleAdd' => 'Přidat jednotku',
|
||||
];
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
use KupShop\AdminBundle\AdminList\BaseList;
|
||||
|
||||
class ProductsUnitsList extends BaseList
|
||||
{
|
||||
protected $tableName = 'products_units';
|
||||
protected ?string $tableAlias = 'pu';
|
||||
|
||||
protected $tableDef = [
|
||||
'id' => 'id',
|
||||
'fields' => [
|
||||
'ID' => ['field' => 'id'],
|
||||
'Zkratka' => ['field' => 'short_name'],
|
||||
'Zkratka v administraci' => ['field' => 'short_name_admin'],
|
||||
'Dlouhý název' => ['field' => 'long_name'],
|
||||
'Přepočet ceny na' => ['field' => 'recalculate_to'],
|
||||
],
|
||||
];
|
||||
}
|
||||
36
bundles/KupShop/UnitsBundle/Admin/productsUnits.php
Normal file
36
bundles/KupShop/UnitsBundle/Admin/productsUnits.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
class ProductsUnits extends Window
|
||||
{
|
||||
protected $template = 'window/products.units.tpl';
|
||||
protected $tableName = 'products_units';
|
||||
protected $nameField = 'short_name';
|
||||
|
||||
public function getData()
|
||||
{
|
||||
$data = parent::getData();
|
||||
|
||||
if (getVal('Submit')) {
|
||||
if (!empty($data['pieces_in_package']) && $data['pieces_precision'] > 1) {
|
||||
$data['pieces_precision'] = $data['pieces_in_package'];
|
||||
}
|
||||
|
||||
if (empty($data['short_name_admin'])) {
|
||||
$data['short_name_admin'] = $data['short_name'];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function handleDelete()
|
||||
{
|
||||
if ($this->getID() == 1) {
|
||||
$this->returnError('Základní jednotku nelze smazat!');
|
||||
}
|
||||
|
||||
parent::handleDelete();
|
||||
}
|
||||
}
|
||||
|
||||
return ProductsUnits::class;
|
||||
@@ -0,0 +1,84 @@
|
||||
{extends file="[shared]/window.tpl"}
|
||||
|
||||
{block tabs}
|
||||
{windowTab id='flapUnit'}
|
||||
{/block}
|
||||
|
||||
{block tabsContent}
|
||||
<div id="flapUnit" class="tab-pane fade active in boxFlex">
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<label>{'short_name_frontend'|translate}</label>
|
||||
<a class="help-tip" data-toggle="tooltip" title="{'short_name_frontend_tooltip'|translate}"><i
|
||||
class="bi bi-question-circle"></i></a>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control input-sm" name="data[short_name]" maxlength="100" value="{$body.data.short_name}"/>
|
||||
</div>
|
||||
<div class="col-md-2 control-label">
|
||||
<label>{'short_name_admin'|translate}</label>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<input type="text" class="form-control input-sm" name="data[short_name_admin]" maxlength="100"
|
||||
value="{$body.data.short_name_admin}"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<label>{'long_name'|translate}</label>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<input type="text" class="form-control input-sm" name="data[long_name]" maxlength="100" value="{$body.data.long_name}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label">
|
||||
<label for="recalculate_to">{'recalculate_to'|translate}</label>
|
||||
</div>
|
||||
<div class="col-md-4 form-inline">
|
||||
<input type="number" class="form-control input-sm" name="data[recalculate_to]" id="measure_unit" value="{$body.data.recalculate_to}"/>
|
||||
{if $body.data.short_name}<span class="form-control-static">{$body.data.short_name}</span>{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{if $module.PRODUCTS__UNITS_FLOAT}
|
||||
<div class="form-group">
|
||||
<div class="col-md-2 control-label two-lines">
|
||||
<label>{'pieces_precision'|translate}</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{print_select
|
||||
name='data[pieces_precision]'
|
||||
var=[
|
||||
"1" => "0 (např. 1, 2, 3, 4 ...)",
|
||||
"0.1" => "1 (např. 1.0, 1.1, 1.2, ...)",
|
||||
"0.01" => "2 (např. 1.00, 1.01, 1.02, ...)",
|
||||
"0.001" => "3 (např. 1.000, 1.001, 1.002, ...)",
|
||||
"0.0001" => "4 (např. 1.0000, 1.0001, 1.0002, ...)",
|
||||
"2" => "Balení"
|
||||
]
|
||||
selected=($body.data.pieces_precision > 1) ? "2" : (string)$body.data.pieces_precision
|
||||
}
|
||||
</div>
|
||||
|
||||
<div id='pieces_in_package' {if $body.data.pieces_precision <= 1}style="display:none"{/if}>
|
||||
<div class="col-md-2 control-label">
|
||||
<label>{'pieces_in_package'|translate}</label>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<input type="text" class="form-control input-sm" name="data[pieces_in_package]" maxlength="100"
|
||||
value="{if $body.data.pieces_precision > 1}{$body.data.pieces_precision}{/if}"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('select[name*="pieces_precision"]').change(function (e) {
|
||||
var val = $(this).val();
|
||||
$('#pieces_in_package').css('display', (val > 1) ? 'inline' : 'none');
|
||||
}).change();
|
||||
</script>
|
||||
</div>
|
||||
{/if}
|
||||
{/block}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\UnitsBundle\AdminRegister;
|
||||
|
||||
use KupShop\AdminBundle\AdminRegister\AdminRegister;
|
||||
use KupShop\AdminBundle\AdminRegister\IAdminRegisterDynamic;
|
||||
use KupShop\AdminBundle\AdminRegister\IAdminRegisterStatic;
|
||||
|
||||
class UnitsAdminRegister extends AdminRegister implements IAdminRegisterDynamic, IAdminRegisterStatic
|
||||
{
|
||||
public function getDynamicMenu(): array
|
||||
{
|
||||
return [
|
||||
static::createMenuItem('productsMenu',
|
||||
[
|
||||
'name' => 'productsUnits',
|
||||
'left' => 's=menu.php&type=productsUnits', 'right' => 's=list.php&type=productsUnits',
|
||||
'rights' => 'PRODUCT_',
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
public static function getPermissions(): array
|
||||
{
|
||||
return [
|
||||
static::createPermissions('productsUnits', [], ['PRODUCT'], false, [\Modules::PRODUCTS => \Modules::SUB_UNITS]),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\UnitsBundle\EventListener;
|
||||
|
||||
use KupShop\KupShopBundle\Event\CreateMenuEvent;
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
|
||||
class CreateMenuListener implements EventSubscriberInterface
|
||||
{
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return [
|
||||
CreateMenuEvent::COMPLETING_TREE => [
|
||||
['addItem', 200],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @var CreateMenuEvent
|
||||
*/
|
||||
public function addItem(CreateMenuEvent $event)
|
||||
{
|
||||
$event->addItem('productsMenu',
|
||||
[
|
||||
'name' => 'productsUnits',
|
||||
'left' => 's=menu.php&type=productsUnits', 'right' => 's=list.php&type=productsUnits',
|
||||
'rights' => 'PRODUCT_',
|
||||
]
|
||||
);
|
||||
|
||||
$event->addRights('productsUnits',
|
||||
[
|
||||
'submodules' => [
|
||||
\Modules::PRODUCTS => \Modules::SUB_UNITS,
|
||||
],
|
||||
'rights' => [],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
services:
|
||||
_defaults:
|
||||
autoconfigure: true
|
||||
autowire: true
|
||||
|
||||
KupShop\UnitsBundle\:
|
||||
resource: ../../{Utils,AdminRegister}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
use KupShop\ContentBundle\Entity\ProductUnified;
|
||||
use KupShop\UnitsBundle\Utils\MeasureUnitUtil;
|
||||
|
||||
function smarty_function_get_measure_price($params, $smarty)
|
||||
{
|
||||
if (empty($params['product'])) {
|
||||
throw new \KupShop\KupShopBundle\Exception\InvalidArgumentException('Parameter "product" is required');
|
||||
}
|
||||
|
||||
$round = $params['round'] ?? false;
|
||||
|
||||
$productUnified = $params['product'];
|
||||
if ($productUnified instanceof \KupShop\CatalogBundle\Entity\Wrapper\ProductWrapper || $productUnified instanceof Product) {
|
||||
$product = \KupShop\CatalogBundle\Entity\Wrapper\ProductWrapper::unwrap($productUnified);
|
||||
$product->fetchVariations();
|
||||
$productUnified = new ProductUnified($product, $product->variations);
|
||||
}
|
||||
|
||||
$result = \KupShop\KupShopBundle\Util\Compat\ServiceContainer::getService(MeasureUnitUtil::class)
|
||||
->getUnitPrice($productUnified, $round);
|
||||
|
||||
if (!empty($params['assign'])) {
|
||||
$smarty->assign($params['assign'], $result);
|
||||
} else {
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\UnitsBundle\Resources\upgrade;
|
||||
|
||||
class ProductsUnitsUpgrade extends \UpgradeNew
|
||||
{
|
||||
public function check_UnitsTable()
|
||||
{
|
||||
return $this->checkTableExists('products_units');
|
||||
}
|
||||
|
||||
/** Create product units table */
|
||||
public function upgrade_UnitsTable()
|
||||
{
|
||||
sqlQuery('CREATE TABLE products_units (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY ,
|
||||
short_name VARCHAR(10),
|
||||
long_name VARCHAR(255),
|
||||
UNIQUE (short_name)
|
||||
);
|
||||
|
||||
INSERT INTO products_units (short_name, long_name) VALUES (\'ks\', \'Počet kusů\');
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ProductsUnit()
|
||||
{
|
||||
return $this->checkColumnExists('products', 'unit');
|
||||
}
|
||||
|
||||
/** Create product unit column */
|
||||
public function upgrade_ProductsUnit()
|
||||
{
|
||||
sqlQuery('
|
||||
ALTER TABLE products ADD COLUMN unit INT DEFAULT 1 NOT NULL AFTER in_store;
|
||||
ALTER TABLE products ADD FOREIGN KEY (unit) REFERENCES products_units(\'id\');
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ProductsUnitPrecision()
|
||||
{
|
||||
return findModule(\Modules::PRODUCTS, \Modules::SUB_UNITS_FLOAT) && $this->checkColumnExists('products_units', 'pieces_precision');
|
||||
}
|
||||
|
||||
/** Create product unit precision column */
|
||||
public function upgrade_ProductsUnitPrecision()
|
||||
{
|
||||
sqlQuery('
|
||||
ALTER TABLE products_units ADD COLUMN pieces_precision TINYINT(1) DEFAULT 0 NOT NULL;
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ProductsUnitMakeInStoreDecimal()
|
||||
{
|
||||
return findModule(\Modules::PRODUCTS, \Modules::SUB_UNITS_FLOAT) && $this->checkColumnType('products', 'in_store', 'DECIMAL(15,4)');
|
||||
}
|
||||
|
||||
/** Update store to decimal values */
|
||||
public function upgrade_ProductsUnitMakeInStoreDecimal()
|
||||
{
|
||||
sqlQuery('
|
||||
ALTER TABLE products MODIFY COLUMN in_store DECIMAL(15,4) DEFAULT 0 NOT NULL;
|
||||
ALTER TABLE products_variations MODIFY COLUMN in_store DECIMAL(15,4) DEFAULT 0 NOT NULL;
|
||||
ALTER TABLE cart MODIFY COLUMN pieces DECIMAL(15,4) DEFAULT 0 NOT NULL;
|
||||
ALTER TABLE order_items MODIFY COLUMN pieces DECIMAL(15,4) DEFAULT 1 NOT NULL;
|
||||
ALTER TABLE stock_in_items MODIFY COLUMN quantity DECIMAL(15,4) not null;
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ProductsUnitsTable()
|
||||
{
|
||||
return findModule(\Modules::TRANSLATIONS) && $this->checkTableExists('products_units_translations');
|
||||
}
|
||||
|
||||
/** Create products units translations table */
|
||||
public function upgrade_ProductsUnitsTable()
|
||||
{
|
||||
sqlQuery('CREATE TABLE IF NOT EXISTS products_units_translations
|
||||
(
|
||||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
id_products_unit INT NOT NULL,
|
||||
id_language VARCHAR(2) NOT NULL,
|
||||
id_admin INT DEFAULT NULL,
|
||||
created TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated DATETIME DEFAULT NULL,
|
||||
short_name VARCHAR(10) DEFAULT NULL,
|
||||
long_name VARCHAR(255) DEFAULT NULL,
|
||||
text TEXT DEFAULT NULL,
|
||||
FOREIGN KEY (id_products_unit)
|
||||
REFERENCES products_units(id)
|
||||
ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE UNIQUE INDEX products_units_translations_id_unit_id_language_uindex
|
||||
ON products_units_translations (id_products_unit, id_language);
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_PrecisionType()
|
||||
{
|
||||
return findModule(\Modules::PRODUCTS, \Modules::SUB_UNITS_FLOAT) && $this->checkColumnType('products_units', 'pieces_precision', 'FLOAT');
|
||||
}
|
||||
|
||||
/** Change pieces_precision type */
|
||||
public function upgrade_PrecisionType()
|
||||
{
|
||||
sqlQuery('
|
||||
ALTER TABLE products_units MODIFY COLUMN pieces_precision FLOAT DEFAULT 1 NOT NULL;
|
||||
UPDATE products_units SET pieces_precision=0.01 WHERE pieces_precision=2;
|
||||
UPDATE products_units SET pieces_precision=0.1 WHERE pieces_precision=1;
|
||||
UPDATE products_units SET pieces_precision=1 WHERE pieces_precision=0;
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ShortNameAdmin()
|
||||
{
|
||||
return $this->checkColumnExists('products_units', 'short_name_admin');
|
||||
}
|
||||
|
||||
/** Add admin short name */
|
||||
public function upgrade_ShortNameAdmin()
|
||||
{
|
||||
sqlQuery('
|
||||
ALTER TABLE products_units ADD COLUMN short_name_admin VARCHAR(10) AFTER short_name;
|
||||
ALTER TABLE products_units DROP INDEX short_name;
|
||||
ALTER TABLE products_units ADD UNIQUE (short_name_admin);
|
||||
UPDATE products_units SET short_name_admin=short_name WHERE 1=1;
|
||||
');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_ProductsFKExists(): bool
|
||||
{
|
||||
return $this->checkForeignKeyExists('products', 'unit');
|
||||
}
|
||||
|
||||
/** Add unit column foreign key */
|
||||
public function upgrade_ProductsFKExists(): void
|
||||
{
|
||||
sqlQuery('UPDATE products p LEFT JOIN products_units u ON u.id = p.unit SET p.unit = 1 WHERE u.id IS NULL');
|
||||
|
||||
sqlQuery('ALTER TABLE products ADD CONSTRAINT products_products_units_id_fk FOREIGN KEY (unit) REFERENCES products_units(id) ON UPDATE CASCADE;');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_measureUnit(): bool
|
||||
{
|
||||
return $this->checkColumnExists('products_units', 'recalculate_to');
|
||||
}
|
||||
|
||||
/** ProductsUnits: add price unit */
|
||||
public function upgrade_measureUnit(): void
|
||||
{
|
||||
sqlQuery('ALTER TABLE products_units ADD COLUMN recalculate_to INT NOT NULL DEFAULT 1');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
|
||||
public function check_products()
|
||||
{
|
||||
return $this->checkColumnExists('products', 'measure_unit');
|
||||
}
|
||||
|
||||
/** Add price unit to products */
|
||||
public function upgrade_products()
|
||||
{
|
||||
// sqlQuery('ALTER TABLE products ADD COLUMN measure_unit INT NULL REFERENCES products_units(id) ON UPDATE CASCADE');
|
||||
|
||||
sqlQuery('ALTER TABLE products ADD COLUMN measure_unit INT NULL;');
|
||||
sqlQuery('ALTER TABLE products ADD CONSTRAINT products_measure_unit_fk FOREIGN KEY (measure_unit)
|
||||
REFERENCES products_units(id) ON UPDATE CASCADE;');
|
||||
|
||||
sqlQuery('ALTER table products ADD COLUMN measure_quantity DECIMAL(15,4) NULL DEFAULT NULL;');
|
||||
|
||||
sqlQuery('ALTER table products_variations ADD COLUMN measure_quantity DECIMAL(15,4) NULL DEFAULT NULL;');
|
||||
|
||||
$this->upgradeOK();
|
||||
}
|
||||
}
|
||||
10
bundles/KupShop/UnitsBundle/Tests/CartUnits_FloatSuite.json
Normal file
10
bundles/KupShop/UnitsBundle/Tests/CartUnits_FloatSuite.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"products_units": [
|
||||
{
|
||||
"id": 2,
|
||||
"short_name": "M",
|
||||
"long_name": "metry",
|
||||
"pieces_precision": 0.01
|
||||
}
|
||||
]
|
||||
}
|
||||
49
bundles/KupShop/UnitsBundle/Tests/CartUnits_FloatSuite.php
Normal file
49
bundles/KupShop/UnitsBundle/Tests/CartUnits_FloatSuite.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
use KupShop\DevelopmentBundle\Util\Tests\CartTestTrait;
|
||||
|
||||
class CartUnits_FloatSuite extends DatabaseTestCase
|
||||
{
|
||||
use CartTestTrait;
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->getJsonDataSetFromFile();
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
|
||||
Delivery::clearCache();
|
||||
}
|
||||
|
||||
public function testAddItemToCart()
|
||||
{
|
||||
$this->loginUser(1);
|
||||
|
||||
$this->updateSQL('products', ['unit' => 2], ['id' => 1]);
|
||||
|
||||
$this->createCart();
|
||||
$this->insertProduct(1, 16, 1.35);
|
||||
|
||||
$this->createCart();
|
||||
$this->assertEquals(1080, $this->cart->totalPriceWithVat->asFloat());
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
}
|
||||
|
||||
public function testCorrectSubFromStore()
|
||||
{
|
||||
$this->loginUser(1);
|
||||
$this->updateSQL('products', ['unit' => 2], ['id' => 1]);
|
||||
|
||||
$this->createCart();
|
||||
$this->insertProduct(1, 16, '1,35');
|
||||
|
||||
$this->checkOrderPriceIsSameAsCart();
|
||||
$in_store = sqlQueryBuilder()->select('in_store')->from('products_variations')->where('id = 16')->execute()->fetchColumn();
|
||||
|
||||
$this->assertEquals(-1.35, $in_store);
|
||||
}
|
||||
}
|
||||
9
bundles/KupShop/UnitsBundle/UnitsBundle.php
Normal file
9
bundles/KupShop/UnitsBundle/UnitsBundle.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\UnitsBundle;
|
||||
|
||||
use Symfony\Component\HttpKernel\Bundle\Bundle;
|
||||
|
||||
class UnitsBundle extends Bundle
|
||||
{
|
||||
}
|
||||
115
bundles/KupShop/UnitsBundle/Utils/MeasureUnitUtil.php
Normal file
115
bundles/KupShop/UnitsBundle/Utils/MeasureUnitUtil.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace KupShop\UnitsBundle\Utils;
|
||||
|
||||
use KupShop\CatalogBundle\ProductList\ProductCollection;
|
||||
use KupShop\ContentBundle\Entity\ProductUnified;
|
||||
use KupShop\ContentBundle\Entity\Wrapper\ProductUnifiedWrapper;
|
||||
use KupShop\I18nBundle\Translations\ProductsUnitsTranslation;
|
||||
use KupShop\I18nBundle\Util\PriceConverter;
|
||||
use KupShop\KupShopBundle\Context\CurrencyContext;
|
||||
use KupShop\KupShopBundle\Util\Price\Price;
|
||||
use KupShop\KupShopBundle\Util\Price\ProductPrice;
|
||||
use KupShop\KupShopBundle\Wrapper\PriceWrapper;
|
||||
use Query\Operator;
|
||||
use Query\Translation;
|
||||
use Symfony\Contracts\Service\Attribute\Required;
|
||||
|
||||
class MeasureUnitUtil
|
||||
{
|
||||
protected ?PriceConverter $priceConverter;
|
||||
protected CurrencyContext $currencyContext;
|
||||
|
||||
public function getUnitPrice(ProductUnified|ProductUnifiedWrapper $product, bool $round = false): ?array
|
||||
{
|
||||
$productCollection = new ProductCollection([$product->getId() => $product]);
|
||||
$productCollection->fetchMeasureUnits();
|
||||
|
||||
if ($product instanceof ProductUnifiedWrapper) {
|
||||
$product = $product->getObject();
|
||||
}
|
||||
|
||||
if (empty($product->measureUnits)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Select first variation by default or get data for product
|
||||
$data = $product->measureUnits[array_key_first($product->measureUnits)] ?? null;
|
||||
if ($product->getVariationId()) {
|
||||
$data = $product->measureUnits[$product->getVariationId()] ?? null;
|
||||
}
|
||||
|
||||
if (!$data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->calculatePriceUnit($product->getProductPrice(), $data);
|
||||
}
|
||||
|
||||
public function calculatePriceUnit(ProductPrice $productPrice, array $data): ?array
|
||||
{
|
||||
$measureQuantity = toDecimal($data['measure_quantity'] ?? null);
|
||||
$measureUnit = toDecimal($data['recalculate_to'] ?? null);
|
||||
|
||||
if (!$measureQuantity->isPositive()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$measureUnit->isPositive()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$wrapped = PriceWrapper::wrap($productPrice);
|
||||
$price = $wrapped->field_value_without_vat_no_rounding();
|
||||
$priceWithoutDiscount = $wrapped->field_value_without_vat_without_discount();
|
||||
|
||||
$pricePerUnit = $price->div($measureQuantity->div($measureUnit, 4), 4);
|
||||
$priceWithoutDiscountPerUnit = $priceWithoutDiscount->div($measureQuantity->div($measureUnit, 4), 4);
|
||||
|
||||
$result = [
|
||||
'price' => new Price($pricePerUnit, $this->currencyContext->getActive(), $productPrice->getVat()),
|
||||
'recalculate_to' => $data['recalculate_to'],
|
||||
'unit_name' => $data['short_name'],
|
||||
];
|
||||
|
||||
if ($priceWithoutDiscountPerUnit->comp($pricePerUnit)) {
|
||||
$result['price_without_discount'] = new Price($priceWithoutDiscountPerUnit, $this->currencyContext->getActive(), $productPrice->getVat());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getUnitPriceQueryBuilder(?array $ids = null): \Query\QueryBuilder
|
||||
{
|
||||
$qb = sqlQueryBuilder()->select('p.id id_product, pv.id id_variation,
|
||||
COALESCE(pv.measure_quantity, p.measure_quantity) measure_quantity, pu.recalculate_to, pu.id as id')
|
||||
->fromProducts()
|
||||
->joinVariationsOnProducts()
|
||||
->innerJoin('p', 'products_units', 'pu', 'pu.id = p.measure_unit')
|
||||
->andWhere(Translation::coalesceTranslatedFields(ProductsUnitsTranslation::class, ['short_name', 'long_name']));
|
||||
|
||||
if (findModule(\Modules::PRODUCTS, \Modules::SUB_UNITS_FLOAT)) {
|
||||
$qb->addSelect('pu.pieces_precision as pieces_precision');
|
||||
}
|
||||
|
||||
if ($ids) {
|
||||
$qb->andWhere(Operator::inIntArray($ids, 'p.id'));
|
||||
}
|
||||
|
||||
return $qb;
|
||||
}
|
||||
|
||||
#[Required]
|
||||
public function setPriceConverter(?PriceConverter $priceConverter): void
|
||||
{
|
||||
$this->priceConverter = $priceConverter;
|
||||
}
|
||||
|
||||
#[Required]
|
||||
public function setCurrencyContext(CurrencyContext $currencyContext): void
|
||||
{
|
||||
$this->currencyContext = $currencyContext;
|
||||
}
|
||||
}
|
||||
47
bundles/KupShop/UnitsBundle/Utils/PiecesRounder.php
Normal file
47
bundles/KupShop/UnitsBundle/Utils/PiecesRounder.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace KupShop\UnitsBundle\Utils;
|
||||
|
||||
class PiecesRounder
|
||||
{
|
||||
protected $units;
|
||||
|
||||
public function roundPieces($product, $pieces)
|
||||
{
|
||||
$units = $this->loadUnits();
|
||||
$unitID = $product->unit['id'] ?? null;
|
||||
|
||||
$pieces = str_replace(',', '.', $pieces);
|
||||
|
||||
if ($unitID && $units[$unitID]['pieces_precision']) {
|
||||
switch ($units[$unitID]['pieces_precision']) {
|
||||
case 0.0001: $round = 4;
|
||||
break;
|
||||
case 0.001: $round = 3;
|
||||
break;
|
||||
case 0.01: $round = 2;
|
||||
break;
|
||||
case 0.1: $round = 1;
|
||||
break;
|
||||
case 0:
|
||||
default: $round = 0;
|
||||
}
|
||||
|
||||
return round($pieces, $round);
|
||||
}
|
||||
|
||||
return intval($pieces);
|
||||
}
|
||||
|
||||
protected function loadUnits()
|
||||
{
|
||||
if (!$this->units) {
|
||||
$this->units = sqlFetchAll(sqlQueryBuilder()
|
||||
->select('*')
|
||||
->from('products_units')
|
||||
->execute(), 'id');
|
||||
}
|
||||
|
||||
return $this->units;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user