first commit

This commit is contained in:
2025-08-02 16:30:27 +02:00
commit 23646bfcee
14851 changed files with 1750626 additions and 0 deletions

View File

@@ -0,0 +1,92 @@
<?php
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
$main_class = 'Margins';
class Margins extends Window
{
public function get_vars()
{
$vars = parent::get_vars();
$margins = sqlQueryBuilder()
->select('*')
->from('margins')
->orderBy('range_from')
->execute()
->fetchAll();
$last = 0;
foreach ($margins as &$margin) {
if ($margin['range_from'] < $last) {
$margin['bad_down_range'] = true;
}
$margin['pl_range_from'] = $margin['range_from'] * (100 + $margin['margin']) / 100;
$margin['pl_range_to'] = $margin['range_to'] * (100 + $margin['margin']) / 100;
$last = $margin['range_to'];
}
$vars['body']['data']['margins'] = $margins;
return $vars;
}
public function handle()
{
$acn = getVal('acn');
if ($acn) {
$action = 'handle'.ucfirst($acn);
if (method_exists($this, $action)) {
call_user_func([$this, $action]);
}
}
$data = getVal('data');
$submit = getVal('Submit');
if ($submit) {
foreach ($data as $id => $margin) {
if (!empty($margin['delete']) || empty($margin['range_to'])) {
if ($id > 0) {
$this->deleteSQL('margins', ['id' => $margin['id']]);
}
continue;
}
$margin['margin'] = floatval(str_replace([',', ' '], ['.', ''], $margin['margin']));
if ($id < 0) {
$this->insertSQL('margins', $margin, ['id', 'delete']);
} else {
$this->updateSQL('margins', $margin, ['id' => $margin['id']], ['id', 'delete']);
}
}
$this->returnOK('Uloženo');
}
}
public function handleRecalculateProducts()
{
$compute = ServiceContainer::getService('kupshop.margins.compute.compute');
$compute->computeAll();
$this->returnOK('Přepočítáno.');
}
public function hasRights($name = null)
{
switch ($name) {
case Window::RIGHT_DUPLICATE:
case Window::RIGHT_DELETE:
return false;
default:
return parent::hasRights($name);
}
}
}

View File

@@ -0,0 +1,110 @@
{extends "[shared]window.tpl"}
{block tabs}
{windowTab id='flapMargins'}
{/block}
{block size}
width = 1220;
height = 900;
{/block}
{block tabsContent}
<div id="flapMargins" class="tab-pane fade in boxFlex">
<div class="panel-group panel-group-lists" data-values="margins">
<div class="row bottom-space">
<div class="col-md-3">
<a href="#" data-form-add class="btn btn-success btn-block"><span class="glyphicon glyphicon-plus"></span>&nbsp;{'buttonAdd'|translate}</a>
</div>
<div class="col-md-8">
<p>Při úpravě dbejte na správnou návaznost hranic OD-DO, přičemž DO a následné OD použijte stejnou hodnotu.
Například při použití hladin od 10 Kč do 50 Kč a následně od 50 Kč do 100 Kč, bude při ceně produktu 50 Kč použita první, tedy nižší hladina.</p>
</div>
<div class="col-md-1">
<a href="javascript:help('margins');"><i class="btn btn-info bi bi-question-circle"></i></a>
</div>
</div>
<div class="panel">
<div class="panel-heading">
<div class="row">
<div class="col-md-2 col-md-offset-1" style="padding-left: 0;">
<small><strong>{'range_from'|translate}</strong></small>
</div>
<div class="col-md-2 text-center">
<small><strong>{'range_to'|translate}</strong></small>
</div>
<div class="col-md-2 col-md-offset-1 text-center">
<small><strong>{'margin'|translate}</strong></small>
</div>
<div class="col-md-2 text-center">
<small><strong>{'title'|translate}</strong></small>
</div>
</div>
</div>
</div>
{foreach array_merge([[]], $body.data.margins) as $key => $row}
<div class="panel
{if $row.bad_down_range}row-red{else}row-green{/if}
" {if $key == 0}data-form-new style="display:none"{else}data-form-item{/if}>
<div class="row bottom-space">
{*<div class="col-md-1">*}
{*<span class="drag-drop-mover pull-right">*}
{*<i class="bi bi-arrows-move handle"></i>*}
{*</span>*}
{*</div>*}
<div class="col-md-2 col-md-offset-1" style="padding-left: 0;">
{if $row.bad_down_range}
<a class="help-tip" data-toggle="tooltip"title="!! Zadaný rozsah koliduje s jiným !!"><i class="glyphicon glyphicon-warning-sign"></i></a>
{/if}
<input type="text" class="form-control input-sm" name="data[{$key}][range_from]" maxlength="10" value="{$row.range_from}" />
</div>
<div class="col-md-2">
<input type="text" class="form-control input-sm" name="data[{$key}][range_to]" maxlength="10" value="{$row.range_to}" />
{if $row.pl_range_to}
<a class="help-tip" data-toggle="tooltip" title="Rozsah pro cenové hladiny: OD:{$row.pl_range_from} DO:{$row.pl_range_to} "><i class="glyphicon glyphicon-signal"></i></a>
{/if}
</div>
<div class="col-md-2 col-md-offset-1">
<div class="input-group">
<input type="text" class="form-control input-sm" name="data[{$key}][margin]" maxlength="10" value="{$row.margin}" />
<span class="input-group-addon">%</span>
</div>
</div>
<div class="col-md-3">
<input type="text" class="form-control input-sm" name="data[{$key}][title]" maxlength="100" value="{$row.title}" />
</div>
<div class="col-md-1">
<div class="btn-group">
<a class="btn-sm btn btn-danger" title="{'buttonDeleteValue'|translate}" data-form-delete>
<input class="hidden" type="checkbox" name="data[{$key}][delete]" />
<input type="hidden" name="data[{$key}][id]" value="{$row.id}" />
<span class="glyphicon glyphicon-remove"></span>
</a>
</div>
</div>
</div>
</div>
{/foreach}
</div>
</div>
{/block}
<script type="application/javascript">
{block onready append}
initForm({
selector:'[data-values=margins]'
});
{/block}
</script>
{block buttonsLeft}
<div class="col-md-3">
<a href="launch.php?s={$type}.php&amp;acn=recalculateProducts" class="btn btn-block btn-warning confirm"
title="{'recalculateProductsButtonConfirm'|translate}">{'recalculateProductsButton'|translate}</a>
</div>
{/block}

View File

@@ -0,0 +1,83 @@
<?php
namespace KupShop\MarginsBundle\Compute;
use Doctrine\ORM\EntityManagerInterface;
class Compute
{
/**
* @var EntityManagerInterface
*/
private $entityManager;
/**
* Compute constructor.
*/
public function __construct(EntityManagerInterface $entityManager)
{
$this->entityManager = $entityManager;
}
public function computeAll()
{
$this->computeProducts();
$this->computeVariations();
}
protected function computeProducts()
{
sqlQueryBuilder()
->update('products', 'p')
->set('p.price', $this->getMarginPattern('p'))
->where('p.price_buy IS NOT NULL AND !FIND_IN_SET(\'MM\', p.campaign)')
->execute();
}
protected function computeVariations()
{
sqlQuery("
UPDATE products_variations pv
JOIN margins m ON m.range_from < pv.price_buy AND m.range_to >= pv.price_buy
JOIN products p ON p.id = pv.id_product
SET pv.price = pv.price_buy * (100 + m.margin) / 100
WHERE pv.price_buy IS NOT NULL AND !FIND_IN_SET('MM', p.campaign)
");
}
/**
* @param $id_product int id of product
*
* @return bool
*/
public function computeProductPrice($id_product)
{
return sqlQueryBuilder()
->update('products', 'p')
->set('p.price', $this->getMarginPattern('p'))
->where('p.price_buy IS NOT NULL AND p.id = :id AND !FIND_IN_SET(\'MM\', p.campaign)')
->setParameter('id', $id_product)
->execute();
}
/**
* @param $id_variation int id of variation
*
* @return bool
*/
public function computeVariationPrice($id_variation = null)
{
return sqlQuery("
UPDATE products_variations pv
JOIN margins m ON m.range_from < pv.price_buy AND m.range_to >= pv.price_buy
JOIN products p ON p.id = pv.id_product
SET pv.price = pv.price_buy * (100 + m.margin) / 100
WHERE pv.price_buy IS NOT NULL AND pv.id = :id AND !FIND_IN_SET('MM', p.campaign)
", ['id' => $id_variation]);
}
private function getMarginPattern($alias)
{
return "{$alias}.price_buy * (100 + COALESCE((SELECT margin FROM margins m WHERE m.range_from < {$alias}.price_buy AND m.range_to >= {$alias}.price_buy), 0)) / 100";
}
}

View File

@@ -0,0 +1,94 @@
<?php
namespace KupShop\MarginsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Margins.
*
* @ORM\Table(name="margins")})
*
* @ORM\Entity
*/
class Margin
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
*
* @ORM\Id
*
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var int
*
* @ORM\Column(name="range_from", type="integer", nullable=true)
*/
private $range_from;
public function getRangeFrom(): int
{
return $this->range_from;
}
public function setRangeFrom(int $range_from)
{
$this->range_from = $range_from;
}
public function getRangeTo(): int
{
return $this->range_to;
}
public function setRangeTo(int $range_to)
{
$this->range_to = $range_to;
}
public function getMargin(): int
{
return $this->margin;
}
public function setMargin(int $margin)
{
$this->margin = $margin;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title)
{
$this->title = $title;
}
/**
* @var int
*
* @ORM\Column(name="range_to", type="integer", nullable=true)
*/
private $range_to;
/**
* @var int
*
* @ORM\Column(name="margin", type="integer", nullable=true)
*/
private $margin;
/**
* @var string
*
* @ORM\Column(name="title", type="string", length=250, nullable=true)
*/
private $title;
}

View File

@@ -0,0 +1,31 @@
<?php
namespace KupShop\MarginsBundle\EventListener;
use KupShop\KupShopBundle\Event\CreateMenuEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class MarginMenuListener implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return [
CreateMenuEvent::COMPLETING_TREE => [
['addItem', 200],
],
];
}
/**
* @var CreateMenuEvent
*/
public function addItem(CreateMenuEvent $event)
{
$event->addItem('productsMenu',
[
'name' => 'margins',
'script' => "nw('margins')",
]
);
}
}

View File

@@ -0,0 +1,9 @@
<?php
namespace KupShop\MarginsBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class MarginsBundle extends Bundle
{
}

View File

@@ -0,0 +1,10 @@
services:
kupshop.margins.compute.compute:
class: KupShop\MarginsBundle\Compute\Compute
autowire: true
KupShop\MarginsBundle\EventListener\MarginMenuListener:
class: KupShop\MarginsBundle\EventListener\MarginMenuListener
autowire: true
tags:
- { name: kernel.event_subscriber }

View File

@@ -0,0 +1,35 @@
<?php
class UpgradeMargins extends UpgradeNew
{
public function check_MarginsModule()
{
return findModule(\Modules::MARGINS) && $this->checkTableExists('margins');
}
/** Create table for margins module*/
public function upgrade_MarginsModule()
{
sqlQuery(' CREATE TABLE IF NOT EXISTS margins (
`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`range_from` INT(11) NOT NULL DEFAULT 0,
`range_to` INT(11) NOT NULL DEFAULT 0,
`margin` FLOAT NOT NULL DEFAULT 0,
`title` VARCHAR(250) NOT NULL DEFAULT ""
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
');
$this->upgradeOK();
}
public function check_InnoDBMargins()
{
return findModule(\Modules::MARGINS) && $this->checkIsInnoDB('margins');
}
/** Fix innodb instead myisam*/
public function upgrade_InnoDBMargins()
{
sqlQuery('ALTER TABLE margins ENGINE = InnoDB;');
}
}

View File

@@ -0,0 +1,43 @@
{
"products" : [
{
"id": 123,
"title": "Test",
"code": "QO591",
"ean": 321564,
"short_descr": "Lorem ipsum dolor sit amet",
"long_descr": "",
"parameters": "",
"price": 1000,
"price_buy": 1000,
"vat": 1,
"discount": 0,
"producer": 15,
"guarantee": 24,
"in_store": 0,
"pieces_sold": 0,
"delivery_time": 0,
"campaign": "N,L",
"updated": "2015-02-16 11:18:43",
"date_added": "2015-02-16 09:41:00",
"figure": "Y",
"show_raw_price": "N",
"position": null,
"meta_title": null,
"meta_description": null,
"meta_keywords": null,
"show_in_feed": "N",
"max_cpc": 0,
"in_store_min": null
}
],
"margins":[
{
"id": 4,
"range_from": 500,
"range_to": 1500,
"margin": 20,
"title": ""
}
]
}

View File

@@ -0,0 +1,26 @@
<?php
namespace KupShop\CatalogBundle\Tests;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\MarginsBundle\Compute;
class MarginsTest extends \DatabaseTestCase
{
public function testMarginsCompute()
{
/** @var Compute\Compute $service */
$service = ServiceContainer::getService('kupshop.margins.compute.compute');
$service->computeAll();
$product = new \Product();
$product->createFromDB(123);
$this->assertEquals('1200', $product->price_array['value_without_vat']->asFloat());
}
public function getDataSet()
{
return $this->getJsonDataSetFromFile();
}
}