diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index 25c6b7bf..e1d86a0b 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -43,7 +43,119 @@ "lmtime": 0, "modified": false }, - "app": {}, + "app": { + "config": { + "addons": {}, + "config_dev.yml": { + "type": "-", + "size": 1541, + "lmtime": 0, + "modified": false + }, + "config_legacy_dev.yml": { + "type": "-", + "size": 47, + "lmtime": 0, + "modified": false + }, + "config_legacy_prod.yml": { + "type": "-", + "size": 163, + "lmtime": 0, + "modified": false + }, + "config_legacy_test.yml": { + "type": "-", + "size": 47, + "lmtime": 0, + "modified": false + }, + "config_legacy.yml": { + "type": "-", + "size": 590, + "lmtime": 0, + "modified": false + }, + "config.php": { + "type": "-", + "size": 4886, + "lmtime": 0, + "modified": false + }, + "config_prod.yml": { + "type": "-", + "size": 715, + "lmtime": 0, + "modified": false + }, + "config_test.yml": { + "type": "-", + "size": 1001, + "lmtime": 0, + "modified": false + }, + "config.yml": { + "type": "-", + "size": 4094, + "lmtime": 0, + "modified": false + }, + "doctrine.yml": { + "type": "-", + "size": 880, + "lmtime": 0, + "modified": false + }, + "parameters.php": { + "type": "-", + "size": 1019, + "lmtime": 1773273531115, + "modified": false + }, + "parameters.yml": { + "type": "-", + "size": 11, + "lmtime": 0, + "modified": false + }, + "parameters.yml.dist": { + "type": "-", + "size": 983, + "lmtime": 0, + "modified": false + }, + "routing_dev.yml": { + "type": "-", + "size": 1132, + "lmtime": 0, + "modified": false + }, + "routing.yml": { + "type": "-", + "size": 315, + "lmtime": 0, + "modified": false + }, + "security.yml": { + "type": "-", + "size": 631, + "lmtime": 0, + "modified": false + }, + "services.yml": { + "type": "-", + "size": 258, + "lmtime": 0, + "modified": false + }, + "set_parameters.php": { + "type": "-", + "size": 3096, + "lmtime": 0, + "modified": false + } + } + }, "autoload.php": { "type": "-", "size": 1316, @@ -116,13 +228,13 @@ }, "google-merchant_id-1.xml": { "type": "-", - "size": 62638554, + "size": 63312722, "lmtime": 0, "modified": true }, "google-merchant_id-2.xml": { "type": "-", - "size": 2733981, + "size": 2750870, "lmtime": 0, "modified": true }, @@ -318,8 +430,8 @@ }, "omnibuseufree.php": { "type": "-", - "size": 29375, - "lmtime": 1772663858543, + "size": 29553, + "lmtime": 1773275484740, "modified": false }, "Readme.md": { @@ -597,8 +709,8 @@ }, "presta_studio_omnibus_price.tpl": { "type": "-", - "size": 1401, - "lmtime": 1772663725687, + "size": 1444, + "lmtime": 1773275495347, "modified": false } }, @@ -749,7 +861,63 @@ "lmtime": 0, "modified": false }, - "themes": {}, + "themes": { + "leo_lulandia": { + "assets": { + "css": { + "components": {}, + "dr_materac.css": { + "type": "-", + "size": 84199, + "lmtime": 1773276500555, + "modified": false + }, + "dr_materac.css.map": { + "type": "-", + "size": 32543, + "lmtime": 1773276500556, + "modified": false + }, + "dr_materac.scss": { + "type": "-", + "size": 101907, + "lmtime": 1773276500559, + "modified": false + }, + "index.php": { + "type": "-", + "size": 1277, + "lmtime": 0, + "modified": false + }, + "rtl.css": { + "type": "-", + "size": 61948, + "lmtime": 0, + "modified": false + }, + "theme.css": { + "type": "-", + "size": 433723, + "lmtime": 0, + "modified": false + }, + "theme.css.map": { + "type": "-", + "size": 1360187, + "lmtime": 0, + "modified": false + }, + "theme.scss": { + "type": "-", + "size": 640895, + "lmtime": 0, + "modified": false + } + } + } + } + }, "tools": {}, "translations": {}, "upload": {}, @@ -761,6 +929,12 @@ "size": 448, "lmtime": 0, "modified": false + }, + "AGENTS.md": { + "type": "-", + "size": 2807, + "lmtime": 1773273811171, + "modified": false } } }, diff --git a/changelog/2026-03-16.md b/changelog/2026-03-16.md new file mode 100644 index 00000000..1c629e8f --- /dev/null +++ b/changelog/2026-03-16.md @@ -0,0 +1,12 @@ +# 2026-03-16 + +## Co zrobiono +- Naprawiono wyświetlanie ceny w fallbacku modułu `omnibuseufree` i dopasowano zaokrąglanie do sposobu prezentacji cen na froncie. +- Dodano tryb debug uruchamiany parametrem `omnibuseufree_debug=1`, aby podejrzeć wartości wejściowe i wyliczone (`price`, `price_amount`, `regular_price`, fallback, minimalna). +- Uporządkowano logikę braku historii: gdy brak historii do wyświetlenia, moduł pokazuje cenę regularną (bez promocji). +- Dodano warunek dla promocji: jeśli w historii z okresu nie ma ceny różnej od bieżącej ceny promocyjnej, moduł traktuje to jako brak historii „sprzed obniżki” i wymusza fallback na cenę regularną. +- Zweryfikowano na przypadkach testowych poprawne wyjście (w tym przypadki z wcześniejszym błędem 4 067,52 / 4 068,00 oraz z historią zawierającą tylko aktualną cenę promocyjną). + +## Zmienione pliki +- `modules/omnibuseufree/omnibuseufree.php` +- `modules/omnibuseufree/views/templates/hook/presta_studio_omnibus_price.tpl` diff --git a/modules/omnibuseufree/omnibuseufree.php b/modules/omnibuseufree/omnibuseufree.php index b6673096..b78db343 100644 --- a/modules/omnibuseufree/omnibuseufree.php +++ b/modules/omnibuseufree/omnibuseufree.php @@ -148,14 +148,95 @@ class OmnibusEuFree extends Module return (!empty($sqlResult)) ? $sqlResult[0] : array(); } + protected function hasDifferentHistoricalPrice($id_product, $id_product_attribute, $currency, $currentPrice) + { + $info_version = Configuration::get('OMNIBUSEUFREE_INFORMATION_VERSION', null, null, null, 2); + $numberOfDays = (int) Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30); + + $date = new DateTime(); + $date->modify('-' . $numberOfDays . ' days'); + $cutOffDate = $date->format('Y-m-d'); + + $sql = new DbQuery(); + $sql->select('id_omnibuseufree'); + $sql->from('omnibus_eu_free'); + $sql->where('id_product = ' . (int) $id_product); + $sql->where('id_product_attribute = ' . (int) $id_product_attribute); + $sql->where('id_currency = ' . (int) $currency); + $sql->where('date_add >= "' . pSQL($cutOffDate . ' 00:00:00') . '"'); + $sql->where('ABS(price - ' . (float) $currentPrice . ') > 0.000001'); + + if ($info_version == 2) { + $sql->where('is_last = 0'); + } + + $sql->limit(1); + + return (bool) Db::getInstance()->getValue($sql); + } + + protected function formatDisplayPrice($price, $currency, $precisionOverride = null) + { + if ($precisionOverride !== null) { + $priceDisplayPrecision = (int) $precisionOverride; + } else { + $priceDisplayPrecision = (int) Configuration::get('PS_PRICE_DISPLAY_PRECISION', null, null, null, _PS_PRICE_DISPLAY_PRECISION_); + } + $roundedPrice = Tools::ps_round((float) $price, $priceDisplayPrecision); + + return PrestashopCompatibility::formatPrice(_PS_VERSION_, $roundedPrice, $currency); + } + public function hookDisplayOmnibusEuFree($params) { $currency = $this->context->currency; - $lastMinimalPrice = $this->getLastMinimalPrice($params['product']['id_product'], $params['product']['id_product_attribute'], $currency->id); + $debugEnabled = (bool) Tools::getValue('omnibuseufree_debug'); + $idProduct = isset($params['product']['id_product']) ? (int) $params['product']['id_product'] : 0; + $idProductAttribute = isset($params['product']['id_product_attribute']) ? (int) $params['product']['id_product_attribute'] : 0; + $lastMinimalPrice = $this->getLastMinimalPrice($idProduct, $idProductAttribute, $currency->id); $regularPrice = isset($params['product']['regular_price']) ? $params['product']['regular_price'] : null; + $displayPrecisionOverride = null; + $forcedFallbackNoPreDiscountHistory = false; + + if (isset($params['product']['price_amount']) && is_numeric($params['product']['price_amount'])) { + $priceAmount = (float) $params['product']['price_amount']; + if (abs($priceAmount - round($priceAmount)) < 0.000001) { + $displayPrecisionOverride = 0; + } + } + + $fallbackPrice = null; + if (is_string($regularPrice) && $regularPrice !== '') { + // Prefer the already prepared regular (non-discounted) price from product presenter. + $fallbackPrice = $regularPrice; + } elseif ($idProduct > 0) { + // Compute regular (without reduction) price if presenter did not provide it. + $useTax = Product::getTaxCalculationMethod((int) $this->context->customer->id) != PS_TAX_EXC; + $regularRaw = Product::getPriceStatic($idProduct, $useTax, $idProductAttribute, 6, null, false, false); + $fallbackPrice = $this->formatDisplayPrice((float) $regularRaw, $currency, $displayPrecisionOverride); + } elseif (isset($params['product']['price_amount']) && is_numeric($params['product']['price_amount'])) { + // Last resort if product id is missing in hook params. + $fallbackPrice = $this->formatDisplayPrice((float) $params['product']['price_amount'], $currency, $displayPrecisionOverride); + } elseif (isset($params['product']['price']) && is_numeric($params['product']['price'])) { + $fallbackPrice = $this->formatDisplayPrice((float) $params['product']['price'], $currency, $displayPrecisionOverride); + } elseif (isset($params['product']['price']) && is_string($params['product']['price']) && $params['product']['price'] !== '') { + $fallbackPrice = $params['product']['price']; + } if (!empty($lastMinimalPrice)) { - $minimalPrice = PrestashopCompatibility::formatPrice(_PS_VERSION_, $lastMinimalPrice['price'], $currency); + if ( + !empty($params['product']['has_discount']) && + isset($params['product']['price_amount']) && + is_numeric($params['product']['price_amount']) && + !$this->hasDifferentHistoricalPrice($idProduct, $idProductAttribute, $currency->id, (float) $params['product']['price_amount']) + ) { + $lastMinimalPrice = array(); + $forcedFallbackNoPreDiscountHistory = true; + } + } + + if (!empty($lastMinimalPrice)) { + $minimalPrice = $this->formatDisplayPrice($lastMinimalPrice['price'], $currency, $displayPrecisionOverride); } else { $minimalPrice = null; @@ -166,8 +247,26 @@ class OmnibusEuFree extends Module 'OmnibuseufreeProductPriceMin' => $minimalPrice, 'OmnibuseufreeProductPriceCurrent' => $params['product']['price'], 'OmnibuseufreeProductPriceRegular' => $regularPrice, + 'OmnibuseufreeProductPriceFallback' => $fallbackPrice, 'OmnibuseufreeProductDiscount' => (bool) $params['product']['has_discount'], 'OmnibuseufreeNumberOfDays' => (int) Configuration::get('OMNIBUSEUFREE_DAYS', null, null, null, 30), + 'OmnibuseufreeDebugEnabled' => $debugEnabled, + 'OmnibuseufreeDebugData' => [ + 'marker' => 'omnibuseufree-debug-2026-03-16', + 'product_id' => $idProduct, + 'product_attribute_id' => $idProductAttribute, + 'currency_id' => isset($currency->id) ? (int) $currency->id : null, + 'currency_iso' => isset($currency->iso_code) ? (string) $currency->iso_code : '', + 'price_display_precision' => (int) Configuration::get('PS_PRICE_DISPLAY_PRECISION', null, null, null, _PS_PRICE_DISPLAY_PRECISION_), + 'display_precision_override' => $displayPrecisionOverride === null ? 'null' : (string) $displayPrecisionOverride, + 'param_price' => isset($params['product']['price']) ? (string) $params['product']['price'] : null, + 'param_price_amount' => isset($params['product']['price_amount']) ? (string) $params['product']['price_amount'] : null, + 'param_regular_price' => isset($params['product']['regular_price']) ? (string) $params['product']['regular_price'] : null, + 'computed_fallback' => (string) $fallbackPrice, + 'computed_minimal' => (string) $minimalPrice, + 'has_discount' => !empty($params['product']['has_discount']) ? '1' : '0', + 'forced_fallback_no_pre_discount_history' => $forcedFallbackNoPreDiscountHistory ? '1' : '0', + ], ]); return $this->display(__FILE__, '/views/templates/hook/presta_studio_omnibus_price.tpl'); @@ -194,7 +293,7 @@ class OmnibusEuFree extends Module foreach ($rowValue as $key => $value) { if (isset($OmnibusData[$rowId]['price']) && $key == 'id_currency') { $currency = Currency::getCurrencyInstance((int) $value); - $OmnibusData[$rowId]['price_locale'] = PrestashopCompatibility::formatPrice(_PS_VERSION_, $OmnibusData[$rowId]['price'], $currency); + $OmnibusData[$rowId]['price_locale'] = $this->formatDisplayPrice($OmnibusData[$rowId]['price'], $currency); $OmnibusData[$rowId]['currency_iso_code'] = $currency->iso_code; } elseif ($key == 'id_product_attribute') { diff --git a/modules/omnibuseufree/views/templates/hook/presta_studio_omnibus_price.tpl b/modules/omnibuseufree/views/templates/hook/presta_studio_omnibus_price.tpl index 16192490..660c98d1 100644 --- a/modules/omnibuseufree/views/templates/hook/presta_studio_omnibus_price.tpl +++ b/modules/omnibuseufree/views/templates/hook/presta_studio_omnibus_price.tpl @@ -21,7 +21,7 @@ {l s='Lowest price in %d days before discount: ' sprintf=[$OmnibuseufreeNumberOfDays] mod='omnibuseufree'}{$OmnibuseufreeProductPriceMin} {else} {* when history is empty *} - {l s='Lowest price in %d days: ' sprintf=[$OmnibuseufreeNumberOfDays] mod='omnibuseufree'}{$OmnibuseufreeProductPriceRegular|default:$OmnibuseufreeProductPriceCurrent} + {l s='Lowest price in %d days: ' sprintf=[$OmnibuseufreeNumberOfDays] mod='omnibuseufree'}{$OmnibuseufreeProductPriceFallback|default:$OmnibuseufreeProductPriceCurrent} {/if} {else} {l s='Lowest price in %d days: ' sprintf=[$OmnibuseufreeNumberOfDays] mod='omnibuseufree'}{$OmnibuseufreeProductPriceMin} @@ -29,3 +29,22 @@
{/if} + +{if isset($OmnibuseufreeDebugEnabled) && $OmnibuseufreeDebugEnabled && isset($OmnibuseufreeDebugData)} +
+ OMNIBUS DEBUG
+ marker: {$OmnibuseufreeDebugData.marker}
+ product_id: {$OmnibuseufreeDebugData.product_id}, attr_id: {$OmnibuseufreeDebugData.product_attribute_id}
+ currency: {$OmnibuseufreeDebugData.currency_iso} ({$OmnibuseufreeDebugData.currency_id}), precision: {$OmnibuseufreeDebugData.price_display_precision}
+ precision_override: {$OmnibuseufreeDebugData.display_precision_override}
+ has_discount: {$OmnibuseufreeDebugData.has_discount}
+ param price: {$OmnibuseufreeDebugData.param_price}
+ param price_amount: {$OmnibuseufreeDebugData.param_price_amount}
+ param regular_price: {$OmnibuseufreeDebugData.param_regular_price}
+ computed fallback: {$OmnibuseufreeDebugData.computed_fallback}
+ computed minimal: {$OmnibuseufreeDebugData.computed_minimal}
+ forced_fallback_no_pre_discount_history: {$OmnibuseufreeDebugData.forced_fallback_no_pre_discount_history}
+