Files
interblue.pl/modules/x13allegro/classes/php5/Sync/XAllegroSyncQuantities.php
2024-10-25 14:16:28 +02:00

423 lines
19 KiB
PHP

<?php
use x13allegro\Api\DataProvider\OfferProvider;
use x13allegro\Api\Model\Command\OfferPublication\OfferPublicationCommand;
use x13allegro\Api\Model\Command\OfferPublication\PublicationAction;
use x13allegro\Api\Model\Command\QuantityChange\QuantityChangeCommand;
use x13allegro\Api\Model\Offers\Enum\SellingModeType;
use x13allegro\Api\XAllegroApi;
use x13allegro\Json\JsonMapBuilder;
final class XAllegroSyncQuantities extends XAllegroSync
{
public static function syncQuantities()
{
if (!XAllegroConfiguration::get('QUANITY_CHECK')
|| !self::checkQuantityAllegroUpdate()
|| !Configuration::get('PS_STOCK_MANAGEMENT')
) {
XAllegroLogger::getInstance()->config(['QUANTITY_ALLEGRO_UPDATE' => 'DISABLED']);
return;
}
foreach (self::getSyncQuantitiesData() as $auction) {
if (!self::changeAccount($auction['id_xallegro_account'])) {
continue;
}
// @since 7.0.0
// backward compatibility
if (!$auction['selling_mode']) {
try {
$item = (new OfferProvider(self::$api, true))->getOfferDetails($auction['id_auction']);
XAllegroAuction::updateAuctionSellingMode($item->sellingMode->format, $item->id);
$auction['selling_mode'] = $item->sellingMode->format;
}
catch (Exception $ex) {
continue;
}
}
// if offer is in AUCTION mode
if ($auction['selling_mode'] == SellingModeType::AUCTION) {
$auction['stock_quantity'] = min(1, $auction['stock_quantity']);
}
self::changeQuantity(
$auction['id_auction'],
$auction['stock_quantity'],
$auction['quantity'],
$auction['threshold'],
XAllegroTask::METHOD_SYNC
);
}
}
/**
* @param array $params
* @return void
*/
public static function hookSyncQuantities(array $params)
{
$result = Db::getInstance()->executeS('
SELECT
DISTINCT(a.`id_auction`),
a.`selling_mode`,
a.`id_xallegro_account`,
a.`quantity`
FROM `' . _DB_PREFIX_ . 'xallegro_auction` a
JOIN `' . _DB_PREFIX_ . 'xallegro_account` ac
ON (a.`id_xallegro_account` = ac.`id_xallegro_account`)
INNER JOIN (
SELECT xca.`id_account`,
CASE WHEN
xca.`value` = "' . pSQL(XAllegroConfigurationAccount::GLOBAL_OPTION) . '"
THEN (
SELECT xc.`value`
FROM `' . _DB_PREFIX_ . 'xallegro_configuration` xc
WHERE xc.`name` = "QUANITY_ALLEGRO_UPDATE"
)
ELSE xca.`value` END as `configuration_sync_quantity`
FROM `' . _DB_PREFIX_ . 'xallegro_configuration_account` xca
JOIN `' . _DB_PREFIX_ . 'xallegro_account` ac
ON (ac.`id_xallegro_account` = xca.`id_account`)
WHERE xca.`name` = "QUANITY_ALLEGRO_UPDATE"
AND ac.`active` = 1
) configurationQuantity
ON (configurationQuantity.`id_account` = a.`id_xallegro_account`)
LEFT JOIN `' . _DB_PREFIX_ . 'xallegro_custom_product` xcp_all
ON (a.`id_product` = xcp_all.`id_product`
AND xcp_all.`id_xallegro_account` = 0)
LEFT JOIN `' . _DB_PREFIX_ . 'xallegro_custom_product` xcp_single
ON (a.`id_product` = xcp_single.`id_product`
AND a.`id_xallegro_account` = xcp_single.`id_xallegro_account`)
LEFT JOIN `' . _DB_PREFIX_ . 'xallegro_task` xt
ON (a.`id_auction` = xt.`id_auction`)
LEFT JOIN `' . _DB_PREFIX_ . 'stock_available` sa
ON (a.`id_product` = sa.`id_product`
AND a.`id_product_attribute` = sa.`id_product_attribute`)
WHERE a.`id_product` = ' . (int)$params['id_product'] . '
AND a.`id_product_attribute` = ' . (int)$params['id_product_attribute'] . '
AND a.`id_auction` > 0
AND a.`closed` = 0
AND a.`archived` = 0
AND ac.`active` = 1
AND (
CASE
WHEN xcp_single.`sync_quantity_allegro` IS NOT NULL THEN xcp_single.`sync_quantity_allegro`
WHEN xcp_all.`sync_quantity_allegro` IS NOT NULL THEN xcp_all.`sync_quantity_allegro`
ELSE configurationQuantity.`configuration_sync_quantity`
END
) > 0' .
(!(bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_OOS') ? '' : '
AND (sa.`out_of_stock` = 0
OR (sa.`out_of_stock` = 2
AND (
SELECT IFNULL(`value`, 0)
FROM `' . _DB_PREFIX_ . 'configuration`
WHERE `name` = "PS_ORDER_OUT_OF_STOCK"
AND (`id_shop` = a.`id_shop` OR `id_shop` IS NULL)
AND (`id_shop_group` = a.`id_shop_group` OR `id_shop_group` IS NULL)
) = 0
)
)') . '
AND ((xt.`type` != "' . pSQL(XAllegroTask::TYPE_QUANTITY) .'" AND xt.`type` != "' . pSQL(XAllegroTask::TYPE_PUBLICATION) .'")
OR xt.`id_xallegro_task` IS NULL)
ORDER BY a.`id_xallegro_account` ASC'
);
if (!$result) {
return;
}
foreach ($result as $auction) {
if (!self::changeAccount($auction['id_xallegro_account'])) {
continue;
}
// @since 7.0.0
// backward compatibility
if (!$auction['selling_mode']) {
try {
$item = (new OfferProvider(self::$api, true))->getOfferDetails($auction['id_auction']);
XAllegroAuction::updateAuctionSellingMode($item->sellingMode->format, $item->id);
$auction['selling_mode'] = $item->sellingMode->format;
}
catch (Exception $ex) {
continue;
}
}
// if offer is in AUCTION mode
if ($auction['selling_mode'] == SellingModeType::AUCTION) {
$params['quantity'] = min(1, $params['quantity']);
}
$accountConfiguration = new XAllegroConfigurationAccount($auction['id_xallegro_account']);
self::changeQuantity(
$auction['id_auction'],
$params['quantity'],
$auction['quantity'],
(int)$accountConfiguration->get('CLOSE_AUCTION_TRESHOLD', true),
XAllegroTask::METHOD_HOOK
);
}
}
/**
* @return array
* @throws PrestaShopDatabaseException
*/
private static function getSyncQuantitiesData()
{
if ((bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX')) {
$stockCompare = 'LEAST(IF(a.`selling_mode` = "AUCTION", LEAST(1, sa.`quantity`), sa.`quantity`), ' . (int)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX') . ') ';
$valueMaxCompare = ' OR a.`quantity` > ' . (int)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX');
} else {
$stockCompare = 'IF(a.`selling_mode` = "AUCTION", LEAST(1, sa.`quantity`), sa.`quantity`) ';
$valueMaxCompare = '';
}
$stockCompare .= ((bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_ALWAYS_MAX') ? '!=' : '<') . ' a.`quantity`' . $valueMaxCompare;
$result = Db::getInstance()->executeS('
SELECT
DISTINCT(a.`id_auction`),
a.`selling_mode`,
a.`quantity`,
a.`id_xallegro_account`,
IF(a.`selling_mode` = "AUCTION", LEAST(1, sa.`quantity`), sa.`quantity`) as `stock_quantity`,
IFNULL(configurationThreshold.`threshold`, 0) as `threshold`
FROM `' . _DB_PREFIX_ . 'xallegro_auction` a
JOIN `' . _DB_PREFIX_ . 'xallegro_account` ac
ON (a.`id_xallegro_account` = ac.`id_xallegro_account`)
INNER JOIN (
SELECT xca.`id_account`,
CASE WHEN
xca.`value` = "' . pSQL(XAllegroConfigurationAccount::GLOBAL_OPTION) . '"
THEN (
SELECT xc.`value`
FROM `' . _DB_PREFIX_ . 'xallegro_configuration` xc
WHERE xc.`name` = "QUANITY_ALLEGRO_UPDATE"
)
ELSE xca.`value` END as `configuration_sync_quantity`
FROM `' . _DB_PREFIX_ . 'xallegro_configuration_account` xca
JOIN `' . _DB_PREFIX_ . 'xallegro_account` ac
ON (ac.`id_xallegro_account` = xca.`id_account`)
WHERE xca.`name` = "QUANITY_ALLEGRO_UPDATE"
AND ac.`active` = 1
) configurationQuantity
ON (configurationQuantity.`id_account` = a.`id_xallegro_account`)
LEFT JOIN (
SELECT xca.`id_account`,
CASE WHEN
xca.`value` = "" OR xca.`value` = 0
THEN (
SELECT COALESCE(SUM(xc.`value`), 0)
FROM `' . _DB_PREFIX_ . 'xallegro_configuration` xc
WHERE xc.`name` = "CLOSE_AUCTION_TRESHOLD"
)
ELSE COALESCE(SUM(xca.`value`), 0) END as `threshold`
FROM `' . _DB_PREFIX_ . 'xallegro_configuration_account` xca
JOIN `' . _DB_PREFIX_ . 'xallegro_account` ac
ON (ac.`id_xallegro_account` = xca.`id_account`)
WHERE xca.`name` = "CLOSE_AUCTION_TRESHOLD"
AND ac.`active` = 1
GROUP BY xca.`id_account`
) configurationThreshold
ON (configurationThreshold.`id_account` = a.`id_xallegro_account`)
LEFT JOIN `' . _DB_PREFIX_ . 'xallegro_custom_product` xcp_all
ON (a.`id_product` = xcp_all.`id_product`
AND xcp_all.`id_xallegro_account` = 0)
LEFT JOIN `' . _DB_PREFIX_ . 'xallegro_custom_product` xcp_single
ON (a.`id_product` = xcp_single.`id_product`
AND a.`id_xallegro_account` = xcp_single.`id_xallegro_account`)
LEFT JOIN `' . _DB_PREFIX_ . 'xallegro_task` xt
ON (a.`id_auction` = xt.`id_auction`)
JOIN `' . _DB_PREFIX_ . 'shop` s
ON (s.`id_shop` = a.`id_shop`)
JOIN `' . _DB_PREFIX_ . 'shop_group` sg
ON (sg.`id_shop_group` = s.`id_shop_group`)
LEFT JOIN `' . _DB_PREFIX_ . 'stock_available` sa
ON a.`id_product` = sa.`id_product`
AND a.`id_product_attribute` = sa.`id_product_attribute`
AND ((sg.`share_stock` = 1 AND sa.`id_shop` = 0 AND sa.`id_shop_group` = s.`id_shop_group`)
OR (sg.`share_stock` = 0 AND sa.`id_shop` = s.`id_shop` AND sa.`id_shop_group` = 0))
WHERE a.`closed` = 0
AND a.`archived` = 0
AND a.`id_auction` > 0
AND a.`id_xallegro_account` > 0
AND ac.`active` = 1
AND (
CASE
WHEN xcp_single.`sync_quantity_allegro` IS NOT NULL THEN xcp_single.`sync_quantity_allegro`
WHEN xcp_all.`sync_quantity_allegro` IS NOT NULL THEN xcp_all.`sync_quantity_allegro`
ELSE configurationQuantity.`configuration_sync_quantity`
END
) > 0
AND (' . $stockCompare . '
OR (IF(a.`selling_mode` = "AUCTION", LEAST(1, sa.`quantity`), sa.`quantity`) < configurationThreshold.`threshold`))' .
(!(bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_OOS') ? '' : '
AND (sa.`out_of_stock` = 0
OR (sa.`out_of_stock` = 2
AND (
SELECT IFNULL(`value`, 0)
FROM `' . _DB_PREFIX_ . 'configuration`
WHERE `name` = "PS_ORDER_OUT_OF_STOCK"
AND (`id_shop` = a.`id_shop` OR `id_shop` IS NULL)
AND (`id_shop_group` = a.`id_shop_group` OR `id_shop_group` IS NULL)
) = 0
)
)') . '
AND ((xt.`type` != "' . pSQL(XAllegroTask::TYPE_QUANTITY) .'" AND xt.`type` != "' . pSQL(XAllegroTask::TYPE_PUBLICATION) .'")
OR xt.`id_xallegro_task` IS NULL)
GROUP BY a.`id_auction`
ORDER BY a.`id_xallegro_account` ASC
LIMIT ' . (int)XAllegroConfiguration::get('QUANITY_ALLEGRO_UPDATE_CHUNK')
);
return $result ?: [];
}
/**
* @param int|float $id_auction
* @param int $stock_quantity
* @param int $auction_quantity
* @param int $threshold
* @param string $method
*/
private static function changeQuantity($id_auction, $stock_quantity, $auction_quantity, $threshold, $method)
{
$forcedClosing = false;
if ($threshold) {
// if qty is lower than threshold, we need to force auction to close
if ($stock_quantity < $threshold && $stock_quantity > 0) {
$stock_quantity = 0;
$forcedClosing = true;
}
}
// jesli ilosc w magazynie jest dodatnia robimy aktualizację
if ($stock_quantity > 0)
{
// jesli ilosc na aukcji jest mniejsza niż w sklepie i ustawione jest trzymanie maksymalnych stanow magazynowych
// lub ilosc na aukcji jest większa niż w sklepie
if (($auction_quantity < $stock_quantity && (bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_ALWAYS_MAX'))
|| ((bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX') && $auction_quantity > (int)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX'))
|| $auction_quantity > $stock_quantity)
{
if ((bool)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX')) {
$stock_quantity = min($stock_quantity, (int)XAllegroConfiguration::get('QUANITY_ALLEGRO_VALUE_MAX'));
}
$stock_quantity = min(
$stock_quantity,
XAllegroApi::QUANTITY_MAX
);
if ($auction_quantity == XAllegroApi::QUANTITY_MAX && $stock_quantity == XAllegroApi::QUANTITY_MAX) {
return;
}
/** @var QuantityChangeCommand $object */
$object = (new JsonMapBuilder('Command/QuantityChangeCommand'))->map(new QuantityChangeCommand());
$object->offerCriteria()->offers($id_auction);
$object->modification->value = (int)$stock_quantity;
$commandId = self::$api->generateUUID();
try {
self::$api
->sale()
->commands()
->quantityChange()
->setCommand($object)
->executeCommand($commandId);
XAllegroLogger::getInstance()
->env($method)
->account(self::$account->id)
->offer($id_auction)
->api('put', 'quantity-change-command', "commandId: $commandId; old: $auction_quantity; new: $stock_quantity");
$task = new XAllegroTask();
$task->id_xallegro_account = self::$account->id;
$task->id_command = $commandId;
$task->id_auction = (float)$id_auction;
$task->type = XAllegroTask::TYPE_QUANTITY;
$task->method = $method;
$task->value = (int)$stock_quantity;
$task->add();
}
catch (Exception $ex) {
if ($ex->getCode() == 404) {
XAllegroAuction::closeAuctions([$id_auction], 'offer-not-found');
}
}
}
}
// jesli ilosc w magazynie jest zerowa - konczymy aukcje
else {
/** @var OfferPublicationCommand $object */
$object = (new JsonMapBuilder('Command/OfferPublicationCommand'))->map(new OfferPublicationCommand());
$object->publication->action = PublicationAction::END;
$object->offerCriteria()->offers($id_auction);
$commandId = self::$api->generateUUID();
try {
self::$api
->sale()
->commands()
->offerPublication()
->setCommand($object)
->executeCommand($commandId);
XAllegroLogger::getInstance()
->env($method)
->account(self::$account->id)
->offer($id_auction)
->api('put', 'publication-command', "commandId: $commandId; currentAuctionQty: $auction_quantity; currentStockQty: $stock_quantity; forcedClosing: $forcedClosing; END");
$task = new XAllegroTask();
$task->id_xallegro_account = self::$account->id;
$task->id_command = $commandId;
$task->id_auction = (float)$id_auction;
$task->type = XAllegroTask::TYPE_PUBLICATION;
$task->method = $method;
$task->value = PublicationAction::END;
$task->add();
}
catch (Exception $ex) {
if ($ex->getCode() == 404) {
XAllegroAuction::closeAuctions([$id_auction], 'offer-not-found');
}
}
}
}
/**
* @return bool
*/
private static function checkQuantityAllegroUpdate()
{
$accountOption = (int)Db::getInstance()->getValue('
SELECT COUNT(*)
FROM `' . _DB_PREFIX_ . 'xallegro_configuration_account`
WHERE `name` = "QUANITY_ALLEGRO_UPDATE"
AND `value` != "' . pSQL(XAllegroConfigurationAccount::GLOBAL_OPTION) . '"
AND `value` > 0'
);
$productOption = (int)Db::getInstance()->getValue('
SELECT COUNT(*)
FROM `' . _DB_PREFIX_ . 'xallegro_custom_product`
WHERE `sync_quantity_allegro` > 0'
);
return (int)XAllegroConfiguration::get('QUANITY_ALLEGRO_UPDATE') || $accountOption || $productOption;
}
}