Работа с деньгами в php, лишние копейка в ту или иную сторону при округлении?
Доброго времени суток, от недостатка опыта с деньгами и дробями, получая следующую ситуацию в которой прошу помощи.
1) Работа с деньгами(в базе храниться decimal 16,2)
2) Таблица item_sale, в которой хранится информация о каждом проданном товаре (selling_price(16,2), discount_amount(16,2),quantity(16,3)
3)Появился функционал "скидки на весь чек" указываемый за весь sale, и получается ситуация common_discount делится на quantity(результат деления складывается к discount_amount на позицию), появляется дробь и теряется точность при округлении до двух символов. В итогом чеке бывают ситуации когда 0,1 копейки недостаточно или избыточна.
Если у вас был опыт разработки подобного функционала, подскажите как оно должно выглядеть? Где я прокололся?
Сергей Соколов, Дархан Камалиев, Добавлю. Обсуждать с бухгалтером это обязательно с письменным итогом и подписью бухгалтера. Чтоб в случае вопросов к вам, вы могли предоставить бумажку.
Дархан Камалиев, в случае, если у вас никакой бухгалтерии нет и вы своими силами продаёте (я не в курсе, разрешено ли это законом или нет) - то округление в таком случае делается в пользу покупателя.
Сергей Соколов, на самом деле нет. Но это длинная тема. К примеру? если вкратце: при поступлении 3 позиций "на 100р" отлично списываются 2 позиции по 33.33р и одна на 33.34 р. Как итог оборотки по закрытым партиям не прут копейками и т.п.
Для счетов-фактур - есть свое правило и там рулит "вертикаль" (итого по вертикали - равно сумме, а вот по горизонтали - нет и это нормально), в ККМ (как финишной точке розницы) - допустимая дельта в пределах копейки и более-менее best practics - разбивать количественные позиции (типа 2*33.33 и 1*33.34), феншуй попроще (с потерей копеек) - сдача "лишних" копеек.
Но в любом случае замена decimal/money на int/100 - не несет никакого смысла)
Я вам страшное скажу: в операциях с деньгами не всегда важна математическая точность.
Но очень важно, чтобы результат был в точности такой, как в бухгалтерии.
А там далеко не всегда царит формальная математика, особенно когда числа, которые потом сводятся к одному результату, по-разному налогооблагаются.
Задача программиста здесь - не в том, чтобы компьютер считал правильно, а чтобы результат сошелся до копейки с 1С-кой, например.
Если вы не бухгалтер, то и не вам решать в какую сторону округлять. В бухгалтерии округление делается по своему. Зачастую используется bankers rounding, и можно нагуглить готовое решение на пхп.
Но повторю то, что уже писали: уточняйте в бухгалтера.
Посмотрите этот пакет, в документации есть ответы на ваши вопросы.
A large proportion of the computers in this world manipulate money, so it’s always puzzled me that money isn’t actually a first class data type in any mainstream programming language. The lack of a type causes problems, the most obvious surrounding currencies. If all your calculations are done in a single currency, this isn’t a huge problem, but once you involve multiple currencies you want to avoid adding your dollars to your yen without taking the currency differences into account. The more subtle problem is with rounding. Monetary calculations are often rounded to the smallest currency unit. When you do this it’s easy to lose pennies (or your local equivalent) because of rounding errors.
Implement a reusable Money class in PHP, using all the best practices and taking care of all the subtle intricacies of handling money.
Рекомендую все суммы денег хранить в МИНИМАЛЬНОЙ величине валюты. Т.е. копейки, центы и т.д. Потом проще конвертировать в нормальную валюту. И ничего никуда округлять не надо.
Stroy71, и для чего это Вам сдалось? Если 1 атомарная сущность (пусть будет один шуруп) стоит условные 3 копейки, то лучше идти к большему и умножать, как надо.
1 шуруп 1.3 грамма. 1 кг шурупов ~ 770шурупов. Т.е. 770 * 3 = 2,310коп. за килограмм или 23 рубля и 10 копеек
Вам нужно написать свой класс, который будет обрабатывать цены...
Почитайте документацию к Drupal Commerce, раздел Pricing..
Там достаточно доступно описана ваша беда и как с ней бороться.. ( class Calculator )
Думаю позаимствовать оттуда решение будет проще, чем самому сочинять велосипед..