Загалом виникла така проблема: На сайті в валюті гривня прибрано копійки. та виникла така проблема що при замовленні декількох штук товару сума не співпадає. Причин в тому що округлення не діє на операцію множення чи то додавання, а тільки на кінцеві суми, що, я вважаю, не є вірним. Виникають незручні ситуації. Приклад:
Хто зтикався з такою ситуацією? Як вирішити таку проблему?
вітання, вважаю таку проблему порушенням бізнес-логіки і досить критичним багом, прошу написати, як можна відтворити (змоделювати) баг на бойовому проекті ?
так, то на бойовому поекті, відтворити досить просто, взяти повар в якого ціна, наприклад 1 у.о., візьмемо курс 28.15, або ж пропишемо вартість 28.15, якщо базова валюта гривня, та замовимо 20 штук, по ідеї сума при округленні має бути 560 а в реалії 563.
логічно, бо по налаштуванням. забрано "не показувати десяті", але нема логіки на "не враховувати при округленні", як на мене, все логічно. а як би мало бути правильним на твою думку ?
логічно при вартості яку я бачу в 1 гривню за куплені мною 100 штук я мав би оплатити 100 гривень а не 101-149 грн. тобто сума має вираховуватись від фактично вказаної на сайті а не братися з аналів... Якщо сума виявилась меншою, то можна вважати за знижку а от якщо сума виявиться більшою, то вже якесь ошуканство. От прийшов я в магазин, купую цукерку, вона коштує 1 гривню, а якщо хочу купити 100 цукерок, то мені вже кажуть 140гривень... чи то є справедливим?
@yura_co не погоджусь, те що не виводить 10-ті, не значить, що нівелюються ці дані. по суті я проблему зрозумів і вона випливає саме з "курсу", а от яке б рішення було максимально корректним, мені важко зрозуміти, тому що, наприклад, продаючи за гривню чи рубель на сайті, а вводячи ціну в $ в адмінці, та прибираючи "кількість знаків після коми" я не можу гарантувати наступне: 0. курс $ до гривні = 1 до 28.15, якщо товар коштує 18 долярів, то його ціна повинна бути: 506,7 грн., незважаючи навіть на те, що кількість знаків після коми "0", ми отримуємо 506, якщо ми купляємо 10-ть таких товарів, то нам потрібно оплатити за них: 5 067 грн., по вашій логіці, потрібно нівелювати копійками при конвертуванні чи при сумі товарів, на якому етапі було б корректно ?
@Baco, тобто виходить щоб зекономити 7 гривень мені потрібно зробити 10 замовлень? або я наприклад замовляю 20 товарів, вартість яких має дробну частину яка округлюється до меншого, але в сумі вартість буде вищою ніж замовити по одному товару, і то може бути прийняте клієнтом за шахрайство з боку магазину. Нівелювання копійками відбувається саме тоді коли адміністратор виставляє кількість знаків після коми . і 20х10 має бути 200 а не інша сума.
@Baco, тобто виходить щоб зекономити 7 гривень мені потрібно зробити 10 замовлень? або я наприклад замовляю 20 товарів, вартість яких має дробну частину яка округлюється до меншого, але в сумі вартість буде вищою ніж замовити по одному товару, і то може бути прийняте клієнтом за шахрайство з боку магазину. Нівелювання копійками відбувається саме тоді коли адміністратор виставляє кількість знаків після коми . і 20х10 має бути 200 а не інша сума.
отут і питання, на якому етапі потрібно нівелювати копійкою ? при формуванні суми на рівні library/cart ? чи на рівні currency->format ? чи взагалі, при формуванні кінцевого сумарного чеку ? на мою скромну думку, потрібно саме на рівні library\cart\cart.php|currency.php
@yura_co як твої міркування щодо цього моменту ? Слава корректно запропонував обробку на рівні total робить, як по твоєму, є ще місця, де потрібно підкорректувати даний недолік ?
@Baco, так, є, якщо тільки тотал, то всерівно будуть місця не сума не збігається. наприклад в випадаючій корзині, хоча можливо я не про той тотал думаюякщо за цей: $total = $this->currency->format($unit_price * $product['quantity'], $this->session->data['currency']); то він не вирішує проблеми, плюс в кого стоїть сімпла, також матимуть проблему, там також потрібно правити але то вже інша проблема. і я не зрозумів як формується тотал для декількох товарів, там потрібно також дивитись. Можливо потрібно зробити модом, для можливих подальших доповнень.
є халепа, по факту данного фіксу, які продемонстрував @yura_co на своєму сайті: коли базова валюта, від котрої розрахунок ведеться ціни в адмінці, має 0 знаків та валюта на котру конвертується значення, в результаті неправильні цифри. тому тут потрібно подумати більш детально, як би то грамотно знайти рішення.
давайте розберемось разом з таким ребусом: дано: 0. товар по ціні 14 USD 1. ціна основна магазину USD (та, що прописується в валютах як 1.00000000) 2. конвертація 1 USD до UAH = 28,15 3. валюта по замовчуванню для вітрини UAH 4. приховування символів після коми, в момент конвертації на вітрині знайти: яким чином, ми можемо корректно конвертувати товари, якщо в налаштуванні прописано "нівелювати * символів після коми", в результаті чого, на вітрині повинна бути відображена сума (14 * 28,15) = 394 , а ось така, більш корректна логіка (14 * 28) = 392 UAH ?
p.s. рішення з
PHP:
$value = round($value, (int)$decimal_place);
вирішує частково проблему, оскільки є ще одна змінна в задачі, наприклад: основна валюта RUB, котра до гривні має конвертацію в 1.124 (для прикладу), тобто товар, поставлений за 400 RUB, на вітрині корректно повинен бути відображеним в сумі 450 UAH, але при "нівелюванні * символів після коми" ми отримуємо не 450, а 400 UAH
проблема в тому що округлення валюти не припустиме, потрібно округлювати саме ціну але є проблема, скрізь береться $product['price'] саме базової валюти ,потім множиться на кількість а потім множиться на курс, звідси і трабли. Правильним рішенням було б спочатку множити на курс а потім на кількість. як приклад: Замість існуючої стрічки
це вже Дмитра персональний метод, він до ОС і до бро в цілому не має відношення, але торкає цю проблему, тому можно тему залишити, для лінкування на неї при такій же проблемі у інших розробників. Щодо вашої ситуації, то давайте змоделюємо, що вийде в результаті такої логіки:
тобто кінцевою ціною, по формулі: ціна в сконвертованій валюті множиться на кількість товару, і ТОДІ тільки округляється чи округляється в момент конвертації ? чи округляється після того, як множиться на кількість ? а) ((14 * 28,15)) * 1 б) (14 * (28)) * 1 в) ((14 * 28,15) * 1) [логіку округлення виділив червоними дужками з підкресленням]
почув, перевірю все ретельно на локальному сервері, та відпишусь тут по тріггерним містам, де то все є і обраховується і якщо логіка максимально прийнятна, то реалізую в синглі
чесно кажучи я не розумію чому саме так зроблено. але якщо фіксувати тотали, то вони просто скрізь, в швидкому замовленні, в кошиках, в випадаючих корзинах...... просто жах якийсь. інший шаблон не дай боже зі своєю корзиною і все.... Я переглянув пару корзин, в них все перекочувало ще з 2ї версії (а може й раніше), невже не виникало ні в кого запитань по округленню цін? Чому б не зробити єдиний тотал для всьго? Але то може моє бачення того ,мені аби все простіше, бо я вже голову зламав вивчаючи звідки яка перемінна береться та що вона означає.
як на мене, то логіка вірна, як не крути... чому ? ось: на сайті я торгую мандаринами, купляю за ларі, один кг. мандаринів беру за 2.7 лар, базова валюта в мене - ларі і я не хочу показувати копійки і на вітрині відображення в гривні, конвертація лар ло гривні: 1 лар = 10,42, в адмінці я вказую ціну: 2.7,\за кг., і на вітрині виходить: 2.7 * 10.42 = 28.13, округлюємо і маємо 28, як на мене - все вірно, думаю що пес закопаний саме в налаштуваннях базова ціна до конвертованої і валюта, у котрої округляти залишок.
@Baco, тут 2 логіки виходить, одна округлюю, бо не хочу показувати копійки, але торгую всерівно з копійками, а інша то табличка множення. ну не може бути, щоб 2 Х 2 було 5-ть. Зрозуміло що я як продавець хочу щоб 2 х 2 було якомога більше а от як покупець, я хочу щоб все було чесно. Тим паче в Україні є закон, який забороняє продавати дорожче ніж вказано на ціннику. А враховуючи що в Україні деякі номінали копійок виведені з обігу, не можна вказувати ціну, яка суперечить номіналам, що досить тяжко зробити виходячи з ситуації. З валютами я прораховував купу варіантів, не виходить, все ж таки все зводиться до тоталів.
податкова поможе)) жартую звісно, я теж за чесний рахунок, тому пробую зрозуміти і вашу логіку, опишіть будь ласка, чому не можна базову ціну зробити ціною закупки, в адмінці вказувати ціну закупки, а на вітрині виводити конвертаційну ціну, залишик заокругливши ? тобто: є товар, по закупочній ціні в 400 р., то і вказати базову в р., а конвертувати як і виходить, і тільки в кінці округлювати. або опишіть якось з цифрами більш аргументовано, бо я поки що абстракцію не можу привести до порядку.
податкова поможе)) жартую звісно, я теж за чесний рахунок, тому пробую зрозуміти і вашу логіку, опишіть будь ласка, чому не можна базову ціну зробити ціною закупки, в адмінці вказувати ціну закупки, а на вітрині виводити конвертаційну ціну, залишик заокругливши ? тобто: є товар, по закупочній ціні в 400 р., то і вказати базову в р., а конвертувати як і виходить, і тільки в кінці округлювати. або опишіть якось з цифрами більш аргументовано, бо я оки що абстракцію не можу привести до порядку.
Ну якщо виходячи з конкретного прикладу, то базова валюта обиралась як тест, але якщо взяти загалом, то більшість товарів імпортного виробництва та ціни в них прив'язані до якоїсь валюти. частіше то долар або євро, і залежно від курсу валют буде коливатись ціна нац. валюти продажу. Можливо зробити інакше, вести облік в потрібній валюті, а при зміні курсу просто завантажувати нові ціни в нац. валюті, зробивши її базовою. Але я зараз підняв питання саме порушення математичної логіки, коли в магазині за основу взята логіка саме продавця, тим самим покресливши математику, бо наразі виходить: 2х2= а скільки потрібно? а інфляцію враховувати?
з приводу математичної логіки: Як зроблено зараз: ((базова ціна *кількість)округлена по умові валюти)*курс Я вважаю потрібно : ((базова ціна*курс )округлена по умові валюти)*кількість З моєї точки зору то є більш математично правильним і не порушує округлення до будь-якого знаку.
повертаючись до нашої розмови по тел. все ж аргументую цифрами свою позицію: 0. базова валюта в $ 1. курс грн. 28.55 2. ціна товару 5$ ___ в результаті маємо: з 2-ма символами після коми: ціна товару: 142.75 ціна в корзині 11 штук: 1570.25 з 0 символами після коми: ціна товару: 143 ціна в корзині 11 штук: 1570 (що на 3 гривні менше 143 * 11 = 1573), проте корректно, по відношенню до валюти і конвертації
все ж знайшов логічне вирішення проблеми, дякуючи Даніелю чи тому розробнику, хто створив класс валюти, в котрому маємо ось такі аргументи в методі format:
PHP:
$number, $currency, $value = '', $format = true
$number - базова цифра, котра конвертується відповідно до курсу (зазвичай множиться на кількість і тоді конвертується (з чим і є проблема в поточній темі) $currency - сюди передається параметр коду валюти вибраної користувачем, по замовчуванню, це валюта з налаштувань магазину, по факту - вибрана з налаштувань користувача $value - кастомна конвертація, розписувати не буду, покажу фокус, котрий закладено в опенкарті $format - маркер, котрий дозволяє виводити числовий формат ціни, якщо в положенні false, або ж повний (з символами зліва, справа) ___ а тепер сама магія, що як і до чого комбінується, щоб отримати корректні цифри: крок 0: отримуємо ціну за товар без форматування:
по факту, отримуємо округлену ціну за 1-ну одиницю товару, без додаткових символів (зліва\справа) крок 1: перераховуємо загальну сумму по сконвертованій (корректно) сумі за одиницю:
ось і все вирішення цієї проблеми. тему вважаю закритою, та знову звернусь до спільноти, щодо внесення змін до збірки, дякую @rifle та @yura_co за фідбєк, тема досить важлива в рамках корректного обрахування товару.
вот взяли и разобрались, без меня если моё мнение учитывается, то я бы не просто внёс данное изменение в бро, но и дал инструкцию Димону и всем, кто использует $total при подсчете в своих модификаторах.
перевірив кілька місць, потрібно все ж напильником обробляти деякі місця, не всюди корректно обраховує, хоча логіка вірна побудови такого підходу, багато місць, як вже описав @yura_co, де потрібно корректувати з (базова ціна * кількість) * курс конвертації, на (базова ціна * курс конвертації) * кількість, де перша половина логічної операції округлює дані і тільки потім, корректну суму множити на кількість.
Щож, рішення знайдене, і воно може стати однією з фішок збірки. Впевнено можна сказати що в нас округлення цін відбувається правильно, скільки знаків після коми не постав. Але то є фактична відмінність абсолютно з усіма модулями які мені відомі і доведеться робити фікси під популярні модулі. або ж запропонувати наше рішення для всієї спільноти опенкарт, так сказати масовий фікс.