diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json index e3a47524..b4edcd3b 100644 --- a/.vscode/ftp-kr.sync.cache.json +++ b/.vscode/ftp-kr.sync.cache.json @@ -310,8 +310,8 @@ }, "omnibuseufree.php": { "type": "-", - "size": 29422, - "lmtime": 1772664207383, + "size": 29536, + "lmtime": 1773275664802, "modified": false }, "Readme.md": { @@ -589,8 +589,8 @@ }, "presta_studio_omnibus_price.tpl": { "type": "-", - "size": 1401, - "lmtime": 1772664072085, + "size": 1444, + "lmtime": 1773275797861, "modified": false } }, @@ -699,13 +699,314 @@ "modified": false }, "src": {}, - "themes": {}, + "themes": { + "classic": { + "assets": { + "css": { + "00b1fb69fb78ff50fd555de80b2fb45e.ttf": { + "type": "-", + "size": 174048, + "lmtime": 0, + "modified": false + }, + "016d41b1da3f1f5aaa44a7e20baee117.woff": { + "type": "-", + "size": 32904, + "lmtime": 0, + "modified": false + }, + "04be689c12d686c595032705f6b3cf6c.svg": { + "type": "-", + "size": 848, + "lmtime": 0, + "modified": false + }, + "057cc3c927dc0b2e8dbb739a306bd3a3.otf": { + "type": "-", + "size": 73016, + "lmtime": 0, + "modified": false + }, + "0ba57b3ea460c3d7d0c46d6138f088a8.svg": { + "type": "-", + "size": 3780, + "lmtime": 0, + "modified": false + }, + "0f099f4e4d67aeb18ab6da291367a93f.woff": { + "type": "-", + "size": 32596, + "lmtime": 0, + "modified": false + }, + "12a47ed5fd5585f0f4227fa035a1a607.woff2": { + "type": "-", + "size": 60840, + "lmtime": 0, + "modified": false + }, + "1e81f33d197ccdb39d4edce581ff50ec.woff": { + "type": "-", + "size": 30148, + "lmtime": 0, + "modified": false + }, + "250c120c3f8b2b0bb58ea27ee36153fc.woff2": { + "type": "-", + "size": 29860, + "lmtime": 0, + "modified": false + }, + "29acb3c63123183305b02ebc9844b2ef.otf": { + "type": "-", + "size": 73124, + "lmtime": 0, + "modified": false + }, + "33e7446832ac7aa84b959a6ea8efb915.svg": { + "type": "-", + "size": 891, + "lmtime": 0, + "modified": false + }, + "38fa559ad8e8cbaee0c7a2178d308df5.woff2": { + "type": "-", + "size": 27760, + "lmtime": 0, + "modified": false + }, + "3a94078d659136527abfe39bc3432628.svg": { + "type": "-", + "size": 1013, + "lmtime": 0, + "modified": false + }, + "40ef5dc59db6eeef16942fc6a0baa8de.otf": { + "type": "-", + "size": 71000, + "lmtime": 0, + "modified": false + }, + "479700ea91d964d295d75c6b67bd0b28.eot": { + "type": "-", + "size": 69177, + "lmtime": 0, + "modified": false + }, + "47f13bcaf75af86613bca9721d6e858f.svg": { + "type": "-", + "size": 901, + "lmtime": 0, + "modified": false + }, + "4903fb37c04676f5a805be194ad59b2b.svg": { + "type": "-", + "size": 1560, + "lmtime": 0, + "modified": false + }, + "4db1ea0d15010c761ee577d7c0f5a0a0.otf": { + "type": "-", + "size": 70960, + "lmtime": 0, + "modified": false + }, + "52260854eea2d38939bf40e9e9687830.woff2": { + "type": "-", + "size": 29756, + "lmtime": 0, + "modified": false + }, + "56b65c6bec8f40445da4f7853f2553ec.otf": { + "type": "-", + "size": 70940, + "lmtime": 0, + "modified": false + }, + "57a1d494b0e76131f062c5c9c2d4960d.woff2": { + "type": "-", + "size": 30220, + "lmtime": 0, + "modified": false + }, + "64041bf784575b30a79fa31900c79cf6.otf": { + "type": "-", + "size": 70404, + "lmtime": 0, + "modified": false + }, + "726b87682d18d1e8307635d146fe58cc.svg": { + "type": "-", + "size": 3103, + "lmtime": 0, + "modified": false + }, + "740f1557cae714dc4b180b4d5de69375.svg": { + "type": "-", + "size": 5233, + "lmtime": 0, + "modified": false + }, + "7acb0ff3a9a16ba3806d7f16b745af38.svg": { + "type": "-", + "size": 1192, + "lmtime": 0, + "modified": false + }, + "83131b9daba3e9a7b2c7ae7e47d2d503.woff": { + "type": "-", + "size": 31392, + "lmtime": 0, + "modified": false + }, + "882e1291e47c7d9d5dd7633845caa204.svg": { + "type": "-", + "size": 891, + "lmtime": 0, + "modified": false + }, + "895e092292d88717adaa347e532822ab.woff2": { + "type": "-", + "size": 28776, + "lmtime": 0, + "modified": false + }, + "91fc2885f1aa34fb73f63e9ef538fe1c.svg": { + "type": "-", + "size": 1145, + "lmtime": 0, + "modified": false + }, + "a7360927bb3673ed7814d6f607d122cb.woff2": { + "type": "-", + "size": 29856, + "lmtime": 0, + "modified": false + }, + "a8af1233a958bd1e96edcad65791a0d3.woff": { + "type": "-", + "size": 32840, + "lmtime": 0, + "modified": false + }, + "b252849e892c264f4f220c7e7cb0207a.svg": { + "type": "-", + "size": 1198, + "lmtime": 0, + "modified": false + }, + "b2efa71e4ca1cd26b0f4df4e71e531a8.svg": { + "type": "-", + "size": 357, + "lmtime": 0, + "modified": false + }, + "c472ea2ef3e5b37438730a4ab00513b4.svg": { + "type": "-", + "size": 901, + "lmtime": 0, + "modified": false + }, + "c80d4fb11dcc2140b26007ce39cfa521.woff": { + "type": "-", + "size": 32508, + "lmtime": 0, + "modified": false + }, + "cbeba06698c00a61e82219b76357ce42.svg": { + "type": "-", + "size": 1020, + "lmtime": 0, + "modified": false + }, + "custom.css": { + "type": "-", + "size": 97853, + "lmtime": 1773275854119, + "modified": false + }, + "custom.css.map": { + "type": "-", + "size": 235820, + "lmtime": 1773275854119, + "modified": false + }, + "custom.scss": { + "type": "-", + "size": 103002, + "lmtime": 1773275853024, + "modified": false + }, + "dce0916af972e3040aa191f74b17dd46.woff2": { + "type": "-", + "size": 30428, + "lmtime": 0, + "modified": false + }, + "de69cd9e672c81725abcde04ecf022ee.woff": { + "type": "-", + "size": 33400, + "lmtime": 0, + "modified": false + }, + "error.css": { + "type": "-", + "size": 742, + "lmtime": 0, + "modified": false + }, + "f2a0933406f7830651524f477ba2f543.woff": { + "type": "-", + "size": 79612, + "lmtime": 0, + "modified": false + }, + "f56d95737d55e2bdba95baa528b2583b.svg": { + "type": "-", + "size": 3780, + "lmtime": 0, + "modified": false + }, + "fa3993a997a0b84e9900ee168b18b919.svg": { + "type": "-", + "size": 848, + "lmtime": 0, + "modified": false + }, + "fd2d932b381003546821288ecde6e370.otf": { + "type": "-", + "size": 71180, + "lmtime": 0, + "modified": false + }, + "theme.css": { + "type": "-", + "size": 192439, + "lmtime": 0, + "modified": false + }, + "theme.css.map": { + "type": "-", + "size": 544940, + "lmtime": 0, + "modified": false + }, + "theme.scss": { + "type": "-", + "size": 255419, + "lmtime": 0, + "modified": false + } + } + } + } + }, "tmp": {}, "tools": {}, "translations": {}, "update_price_log.csv": { "type": "-", - "size": 1233708, + "size": 1251796, "lmtime": 0, "modified": true }, 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/gm_omniprice/.DS_Store b/modules/gm_omniprice/.DS_Store deleted file mode 100644 index f85fc7e6..00000000 Binary files a/modules/gm_omniprice/.DS_Store and /dev/null differ diff --git a/modules/omnibuseufree/omnibuseufree.php b/modules/omnibuseufree/omnibuseufree.php index 346c0163..0ddd71a7 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}
+