5 правил работы с суммами

    В современном программном обеспечении очень часто возникает необходимость выполнять различные операции с всевозможными суммами денег. Однако до сих пор мне нигде не попадалось документации, в которой были бы сведены воедино основные правила представления сумм и реализации финансовых вычислений. В этой статье я попробую сформулировать те правила, которые составил сам на основании личного опыта.



    Не используйте double


    О том, что для хранения сумм нельзя использовать двоичный тип с плавающей точкой одинарной точности float, знают все. Однако распространено мнение, что вместо float можно использовать double. Между тем double не намного лучше.

    Дело в том, что в этих типах число представлено в виде сумм степеней с основанием 2. В то время как денежные суммы во всех прайсах и документах представляются в десятичной системе счисления. Большинство дробных чисел в десятичной системе счисления не имеют точного представления в виде конечной суммы степеней двойки.

    Предположим в интернет-магазине продаются перчатки за 599 рублей 99 копеек. Вот как будет выглядеть это число в программах, использующих двоичные типы с плавающей точкой.

    599.99
    Код на Java
    float f = 599.99f;
    System.out.printf("float %s%n", new BigDecimal(f).setScale(6, BigDecimal.ROUND_DOWN));
    double d = 599.99d;
    System.out.printf("double %s%n", new BigDecimal(d).setScale(15, BigDecimal.ROUND_DOWN));
    

    Код на C#
    float f = 599.99f;
    float fi = (long) f;
    float fp = f - fi;
    long fil = (long) fi;
    long fpl = (long) (fp * 1000000);
    Console.WriteLine("float {0}.{1}", fil, fpl);
    double d = 599.99d;
    double di = Math.Truncate(d);
    double dp = d - di;
    long dil = (long) di;
    long dpl = (long) (dp * 1000000000000000);
    Console.WriteLine("double {0}.{1}", dil, dpl);
    

    float 599.989990
    double 599.990000000000009

    То есть программа еще не сделала никаких вычислений, просто сохранила сумму в локальных переменных в двоичном формате, а в ней уже потеряна точность. В случае использования float — в 6-м знаке, в случае с double — в 15-м.

    Ожидаемый пользователем вид сумма примет только при преобразовании ее в строку и неявном округлении числа до определенного десятичного знака. До этого в каждой сумме, в каждом промежуточном значении после каждого вычисления будет содержаться относительно небольшая ошибка. Причем в разных числах ошибка будет в разных позициях, и эта ошибка может накапливаться.

    Гарантировать, что программа на любых объемах будет выдавать точный результат в таких условиях практически невозможно. И double может наоборот усугубить проблему, так как на нем заметить ошибку будет сложнее.

    Проявиться ошибка точности может при сравнении чисел, которые вроде бы должны быть равны между собой, или сравнении остатка с нулем. Вот как это может выглядеть:

    z = 599.99 руб. - 0.98 руб. - 599.00 руб. - 0.01 руб.
    Код на Java
    double z = ((599.99d - 0.98d) - 599.00d) - 0.01d;
    if (z == 0d) {
        System.out.println("z == 0");
    } else if (z > 0d){
        System.out.println("z > 0");
    } else {
        System.out.println("z < 0");
    }
    


    Код на C#
    double z = ((599.99d - 0.98d) - 599.00d) - 0.01d;
    if (z == 0d)
    {
        Console.WriteLine("z == 0");
    }
    else if (z > 0d)
    {
        Console.WriteLine("z > 0");
    }
    else
    {
        Console.WriteLine("z < 0");
    }
    


    Результат
    z < 0

    Вместо double надо использовать представление числа на основе степеней с основанием 10. В Java для этого предусмотрен тип BigDecimal, в C# — decimal.

    Если ваш язык программирования не имеет такого типа, то его можно без труда реализовать. Надо просто создать структуру, содержащую знак ±, длинное целое число (для этого можно даже использовать простую строку цифр) и позицию десятичной точки, а затем реализовать над ней основные арифметические операции.

    Сумма не может быть отрицательной


    Количество денег не может быть меньше 0. Это может показаться странным для программиста в момент, когда он пишет код, но когда тот же программист пойдет в магазин, для него аксиома неотрицательности сумм будет очевидна. Ни разу при осуществлении покупок ни один покупатель не сказал кассиру: «Я вам должен еще минус сто рублей», — вместо: «Дайте мне сдачу сто рублей».

    Дело в том, что при смене знака сумма всегда кардинально меняет смысл. Попробую продемонстрировать это на конкретных примерах.

    Компания, оказывающая услуги ЖКХ, создала веб-сервис, который по номеру лицевого счета возвращает сумму к оплате. Коммерческий банк реализовал сервис оплаты этих услуг на своем сайте. Плательщик в прошлом месяце заплатил за квартиру с запасом. Он заходит в свой личный кабинет в интернет-банке, вводит лицевой счет, и банк предлагает ему провести платеж на -1500 рублей. При попытке совершить данную операцию пользователю сообщают об ошибке, так как сумма платежа должна быть положительной. Несчастный пользователь думает, что у него задолженность, поскольку очень часто в счетах задолженности обозначают со знаком минус, поэтому он исправляет сумму и совершает платеж. Теперь у него переплата 3000 рублей. На самом деле сумма счета может быть только положительной. Вместо отрицательной задолженности в счете должно было быть указано, что клиент должен оплатить ноль рублей, а сумма переплаты должна идти отдельной графой.

    Не так давно в новостях много рассказывалось о так называемом «техническом овердрафте», который якобы образовался на карточных счетах клиентов в одном российском банке. Могу предположить, как это произошло. У клиента на счете не было денег, подошло время списания средств за обслуживание счета, банк сделал проводку со счета клиента на свой счет доходов, в результате чего на счете образовался подозрительный отрицательный баланс. Клиент, конечно, больше никогда не прикоснется к такому счету, не станет больше пополнять его, так как по правилам сложения сумма его перевода сложится с отрицательным остатком на счете, и он потеряет часть своих денег. За клиента в этом плане можно не беспокоиться, а вот банк в таком случае имеет на своем счету доходов виртуальные средства. Если он их потратит на хозяйственную деятельность, то в итоге у него в балансе образуется дыра. А все потому, что на счет доходов записали средства, которых у клиента не было. Вместо этого надо было сделать совсем другую проводку, со счета задолженностей клиента на счет невыполненных обязательств. А поскольку затронуты ошибкой были некредитные карты, то такую проводку физически невозможно было сделать.

    Здесь наглядно видно, что при смене знака сумма сразу меняет свое смысловое значение. Легко заметить, что, позволив суммам уходить в минус, разработчик открывает ящик пандоры, из которого могут вылететь неограниченные убытки для обслуживаемого бизнеса. Лучше заранее проверить сумму на неотрицательность и обезопасить систему от неожиданных финансовых потерь.

    Заведите класс, содержащий сумму и категорию. Категория должна показывать назначение данной суммы: остаток на счете, цена, переплата, задолженность, обороты, сальдо и т. д. Как только в результате какой-либо операции возникает сумма меньше нуля, сразу выбрасывайте исключение или меняйте категорию суммы. Как правило, для полноценного учета хватает двух категорий — дебет и кредит.

    На мой взгляд, выписки по счету, которые предоставляет большинство банков, выглядят нелепо. Что значит покупка на минус две пятьсот? Что значит расходы минус двадцать тысяч? По логике это должно означать, как будто у держателя счета что-то купили или он что-то заработал. Если перед вами стоит задача сделать выписку, то сделайте в выписке 2 столбца, один для списаний, другой для зачислений, и пишите нормально: «покупка в супермаркете 3500 ...», «зарплата… 20000» «всего списаний столько-то, зачислений столько-то».

    Сумма — это не только число, но и валюта


    Еще в средней школе нас всех учили, что в формулах надо указывать размерность величин и проверять ее. Килограммы нельзя складывать с метрами или сравнивать с литрами. Прежде чем умножить скорость на время, надо убедиться, что скорость указана в м/c, а время в секундах. Но при работе с суммами об этом часто забывают. Сумма — это физическая величина, и она имеет размерность. Поэтому надо работать с нею так, как учат на уроках физики.

    Если система имеет дело исключительно с одной национальной валютой, то ее можно опустить, однако так бывает очень редко. Даже в пределах одной страны зачастую в ходу сразу несколько валют. Например, белорусский рубль до деноминации имеет обозначение BYR, а после деноминации — BYN. Если вы их перепутаете, это будет в 10 раз хуже, чем сложить метры с миллиметрами, потому что 1 BYN = 10 000 BYR. А еще говорят был BYB, для которого 1 BYR = 1000 BYB. Тем более важно контролировать размерность сумм в системе, которая работает с валютами разных стран.

    Храните в базе данных и в памяти сумму вместе с валютой. Заведите для этого специальное свойство в классе, представляющем сумму. При выполнении операций контролируйте размерность и в случае ее нарушения выбрасывайте исключение. В качестве идентификатора валюты я обычно использую 3-символьный код ISO-4217.

    Не используйте понятия «покупка» и «продажа»


    Термины «покупка» и «продажа» — это бытовые понятия, которыми оперируют люди при выполнении повседневных задач. Люди ориентируются на систему координат, в которой они находятся в начальной точке отсчета. В финансах же любая сделка одновременно является и покупкой, и продажей.

    Наберите в Яндексе «купить автомобиль», и половина ссылок в выдаче будет на объявления о продаже автомобилей, а другая — на объявления о покупке. То же самое будет, если поискать по запросу «аренда квартир», «сдать», «снять» и т. п.

    Особенно наглядно такая двойственность проявляется при обмене валюты. Банки на своих сайтах предлагают курсы покупки и продажи различных валют. Как понять, что означает курс покупки доллара 56.61 руб.? Это банк по такой цене продает доллары или клиент рубли покупает? На самом деле пользователи, меняющие валюту, помнят, что 1 доллар стоит примерно пятьдесят с чем-то рублей, и что банк меняет валюту таким образом, чтобы получить прибыль, поэтому, когда надо обменять доллары на рубли, они смотрят на меньшую сумму в рублях, а когда надо обменять рубли на доллары — на большую. При этом, как правило, понять, что означают надписи «Покупка» или «Продажа» над цифрами, никто даже не пытается. Еще общая практика заключается в том, что меньшая сумма пишется слева, а большая — справа. Если написать одно предложение «Курс покупки израильского шекеля 15.75 руб.», мало кто угадает, что имеется в виду.

    Когда разработчик пишет код, у него перед глазами нет конкретных значений, нет таблицы, где привычные цифры расположены в определенных местах, поэтому он ориентируется только на названия своих переменных. Если использовать названия типа buySum, sellSum, buyPrice, sellPrice и т. д., можно запросто перепутать обменные курсы. Такая же ситуация возможна и у сотрудников, которые эти курсы будут забивать в справочники.

    Что будет, если клиент обнаружит, что ему предлагают обменять рубли на доллары по курсу 56 долларов за рубль? Он не будет писать в поддержку, он не станет жаловаться в фейсбуке, не будет скринить страницы. Предприимчивый клиент, скорее всего, поменяет все имеющиеся у него рубли и быстренько снимет все, что наменял.

    Помните, что-то подобное уже было в новостях? Там, скорее всего, были нарушены 2 правила: перепутаны покупка с продажей и допущена отрицательная курсовая разница.

    При автоматизации сделок вместе с понятиями «покупка» или «продажа» должны быть уточняющие слова типа «покупка клиентом» или «продажа банком». Но если вы автоматизируете биржу, то у вас и продавец, и покупатель — оба клиенты. Поэтому лучше всего использовать нейтральные понятия «сделка», «обмен», «дебет», «кредит», «зачисление», «списание» и т. д.

    Обменный курс — это вектор из двух сумм


    Примерно так выглядит стандартное предложение обмена валют для клиента:


    Как оно должно быть реализовано в коде? Курс выглядит как сумма, поэтому к нему должны быть применимы общие правила.

    Десятичное представление — OK.
    Неотрицательное значение — OK.
    Размерность —?

    Давайте попробуем определить, какая размерность у тех цифр, которые обычно горят на табло обменных пунктов. На первый взгляд кажется, что там везде рубли, но какие операции мы можем с ними сделать? Можно ли сложить курс покупки доллара 55.61 руб. с остатком на счете 1500.00 руб.? Нельзя, потому что настоящая размерность обменного курса представляет собой руб./доллар или, еще точнее, валюта-1/валюта-2.

    А еще можно вспомнить, что для «удобства» в некоторых валютах используются коэффиценты. Например, для йены используется курс за 100 единиц валюты. Поэтому под суммой в 1-й валюте есть еще коэффициент во 2-й валюте.

    Получается, размерность — валюта-1/(валюта-2 * коэффициент)?

    Если посмотреть внимательно на таблицу значений курсов, то становится понято, что в зависимости от направления обмена, смысл значений меняется на противоположный.

    В случае с «курсом покупки» клиент дает банку 1$ и получает 56.61₽.
    В случае с «курсом продажи» клиент дает банку 58.79₽ и получает 1$.

    То есть у левого числа размерность ₽/$, а у правого — $/₽.



    Вот в таком виде спутать различные обменные курсы никак не получится. Ведь у них размерности разные.

    Только не надо делить 100 йен на 52.79 рублей, так как получившееся число придется округлить, и потеряется точность.

    В итоге, с учетом всех нюансов, курс обмена будет выглядеть как-то так:

    public final class ExchangeRate {
        public static final int PRECISION = 4;
        private final Sum clientGives;
        private final Sum clientTakes;
    
        public ExchangeRate(Sum clientGives, Sum clientTakes) {
            this.clientGives = clientGives;
            this.clientTakes = clientTakes;
        }
     
        public Sum exchange(Sum sum) {
            if (!sum.getCurrency().equals(clientGives.getCurrency())) {
                throw new IllegalArgumentException();
            }
            BigDecimal amount = sum.getAmount().mulitply(clientTakes.getAmount())
                    .divide(clientGives.getAmount(), PRECISION, BigDecimal.ROUND_HALF_UP);
            return new Sum(amount, clientTakes.getCurrency());
        }
    }
    
    Поделиться публикацией
    Похожие публикации
    Реклама помогает поддерживать и развивать наши сервисы

    Подробнее
    Реклама
    Комментарии 241
    • +1
      Дополню.
      Алгоритм округления может отличаться в разных программах. Это приводит к тому что поставщик, выписывающий документы в Аксапте например, и покупатель, приходующий товар в одноэсе получат определенные расхождения в суммах товара.
      • +2
        Поэтому в 1с можно ввести и сумму а не только цену.
        • +3
          А потом «потанцевать» с фискальным чеком =)
          • +1
            Не только поэтому. Есть ещё НДС, который нацело никогда не вычисляется.
            Если у вас есть табличка товар | цена | кол-во | сумма | ндс, и последней строкой у вас идёт «итого», то сумма по столбцу ндс чаще всего не будет равна итого*18%. И налоговая это нормально хавает.
            • +2
              Честно говоря ожидал статью как раз по округлениям и хитростям с ними связанным. А тут только самые общие моменты.
              • –2
                нормальные пацаны ведут учет НДС отдельно. То есть считаем НДС один раз для ИТОГО.
                • +3
                  Ну конечно. Счета-фактуры эти «нормальные пацаны» не принимают, не выставляют и не сдают в налоговую, потому как работают на помойке, так?
                  • 0
                    Ну, ладно вам. Это вам просто законодательство такое не позволяет. В нашей же помойке, если речь не идёт про клиента-физика, все позиции счета идут без НДС, но в конце считаем НДС от всей суммы. Для физиков же позиции указываем цену с НДС, и так же для общей суммы считаем общий НДС. Но это конечно только в нашей помойке такое удобство…
                    • –1
                      Я не понимаю за что заминусили Ваш пост выше любители «красивых счетов-фактур любой ценой», но в какой «помойке» законодательство позволяет (или даже настаивает?) считать НДС построчно и потом суммировать это? Такой подход противоречит самой сути данного налога.
                      • +2
                        А как, извините, применить ваш алгоритм для покупки в которой присутствуют товары со ставками НДС в 18%, 10% и 0%?
                        • –1
                          вам ничто не мешает написать: НДС 18%: 10 руб, НДС 10%: 5 руб
                          А если НДС 0%, то зачем его указывать?
                          Или вы что-то другое имели ввиду?
                          • 0
                            Внутри чека разные ставки НДС, т.е.
                            То есть считаем НДС один раз для ИТОГО.
                            Не получится просто из-за отсутствия единой ставки.
                            • 0
                              Специально для минусителя законодательство РФ:

                              Налоговый кодекс
                              С т а т ь я 153. Налоговая база

                              При применении налогоплательщиками при реализации товаров
                              (работ, услуг) различных налоговых ставок налоговая база
                              определяется отдельно по каждому виду товаров
                              (работ, услуг),
                              облагаемых по разным ставкам. При применении одинаковых ставок
                              налога налоговая база определяется суммарно по всем видам операций,
                              облагаемых по этой ставке.


                              • 0
                                Т.е. как раз внутри одного документа: «налоговая база
                                определяется отдельно по каждому виду товаров (работ, услуг),
                                облагаемых по разным ставкам»
                                • 0
                                  А такие нюансы регулируются подзаконными актами. Прямого указания выписывать одну накладную на товары/услуги с разными ставками НДС я в вашем Налоговом кодексе не нашел. Как, впрочем, и запрет на выписку раздельных накладных.

                                  И внимательно читайте второе выделение.
                                  • +2
                                    Вот именно, в одной накладной можно выписывать разные ставки. А ваша придумка про разные накладные — не нужна.
                              • 0
                                я не вижу проблемы посчитать НДС для каждой ставки.
                                То есть у вас в чеке есть по одной строке для каждой ставки НДС.
                                Но если вы хотели меня поймать на том, что я сказал «считаем НДС один раз для ИТОГО», то считайте что вы победили, но мы говорили немного о другом.
                                • 0
                                  Зачем ловить, вы сами так написали.

                                  Следующей итерацией, можно дойти и до «не вижу проблемы посчитать НДС для каждой строки»
                                  • 0
                                    вот как раз и бессмысленность следующей итерации я и хотел показать.
                              • 0
                                Вообще-то НДС 0% нужно указывать, это не то же самое, что отсутствие НДС (ст. 164 НК). По нулевому НДС также сдается декларация.
                              • –3
                                А как, извините, применить ваш алгоритм для покупки в которой присутствуют товары со ставками НДС в 18%, 10% и 0%?

                                Тупое минусение извинению не подлежит.

                                Речь не об алгоритмах, а о требованиях закона. Товары с разными ставками НДС будьте добры отпускать разными расходными накладными.
                                • +1
                                  «Тупое минусение извинению не подлежит.» это был эвфемизм.
                                  А, извините, где и когда законы требуют такую, извините, странную операцию производить как «Товары с разными ставками НДС отпускать разными расходными накладными.»?
                              • 0
                                А давайте вот у vanxant и спросим. Это же ведь он написал:
                                Если у вас есть табличка товар | цена | кол-во | сумма | ндс, и последней строкой у вас идёт «итого»,

                                • 0
                                  итого для строки это сумма + НДС. Так что, несмотря, на отсутствие поля хранения итого в строке(что плохо, но возможно опущено, также как и ставка НДС), такая ситуация возможна.
                    • 0
                      Более того — алгоритм округления реально может работать по разному на разном железе. Было что при переносе с теста на продуктив получали совершенно неожиданный результат.
                      • +1
                        Такое обычно происходит если вычисления выполняются во float/double (и отдаются на откуп железу). А если использовать decimal-типы, то вам гарантируется одинаковый результат на любом вменяемом железе.
                        • 0
                          В яве можно добавить модификатор strictfp, чтобы эти граблей обойти.
                        • 0
                          Если бы только в этом проблема была! В AXAPTA «не одобряется» использование более 2-х знаков после запятой, зато для 1сников 4...6 знаков для получения «красивых» сумм из-за НДС — почти норма.
                          И сколько «этим» не рассказывай, что при ставке НДС 20% и цене товара 100 грн с НДС (83,[3] грн без НДС) будут копеечки гулять, — они все равно проводят «округления» в 4...6 знаке и потом удивляются, что остальные такие тупые и так не делают.
                          • +1

                            Не нужно 1С-ников под одну гребенку чесать, иногда ситуации патовые, и что там одобряет Аксапта с 1С — дело десятое. С сайта госзакупок приходят цены с торгов, которые по закону включающих в себя налоги. И будьте добры, чтобы итоговая цена в реализациях совпадала с контрактной. Клиенты выкручиваются тем, что правят циферки в Экселе. И не волнует никого, что правильным расчётом эту цену с учётом НДС не получить. Так и появляются эти дикие дроби. Конечно, исходная проблема в том, что нет проверки правильного расчёта цен.

                        • +5
                          Вместо double надо использовать представление числа на основе степеней с основанием 10.

                          Почему бы просто не использовать long и вести все вычисления в монетах наименьшей ценности? Для рубля — в копейках, для доллара — в центах.
                          • 0
                            Какую монету наименьшей ценности выберем для биткоина?
                            • +16
                              У биткоина есть минимальная неделимая единица «сатоши», равная 0.00000001 биткоина.
                              • 0
                                Биткоин в данном случае был плохим примером. А хорошим было бы, например, золото, которое меряется в унциях, граммах, фунтах, килограмах, тоннах — какую наименьшую неделимую массу золота можно предложить эталоном?
                                • +2
                                  Так речь-то шла про валюты, а золото валютой даже с очень большой натяжкой не является.
                                  В отличие от валют, у весовых товаров нет не только минимальной неделимой единицы, но и вообще какой-то естественной единицы.
                                  Для весовых товаров будут свои подходы, отличные от подходов к представлению валют.
                                  • +1
                                    Помимо того что золото немножко не валюта — квант золота обычно прописан в вашей учетной политике, и часто совпадает с ценой деления ваших весов.
                                    • +1
                                      Учтите, что учитывается только химически чистое золото. Что в общем случае не соответствует взвешенным граммам пробных слитков и изделий.
                                    • +1
                                      3.27 x 10^-22 грамма.
                                      • 0
                                        Ну если уж брать в молекулах, то обязательно получим преценденты, когда часть золота может испариться)
                                        • +1
                                          В атомах, у золота нет молекул, ибо это металл.
                                          Ну а вам не все ли равно, в каком виде золото пришло — в твердом, жидком или газообразном? =)
                                          • +1
                                            Ну если уж учитывать разные атомарные состояния, то молекулы у металлов всё-таки есть, правда это одноатомные(и иногда двухатомные) молекулы для газообразного состояния)
                                            Но за поправку спасибо — перечитаю на досуге советскую энциклопедию по химии, освежу память)
                                • +4
                                  Сколько центов дадим за одну копейку?
                                  • 0

                                    Это уже вопрос представления данных.

                                    • 0
                                      Нет, это вопрос предметной области, т.к. часто курсы даются с точностью до сотых долей цента/копейки.
                                      • 0

                                        В случае внутреннего хранения курсов валют как рациональных дробей вопросы вида "сколько центов дадим за одну копейку" становятся именно что вопросом представления — в каком виде показывать курс пользователю.

                                        • 0
                                          Курс не имеет денежной размерности, а имеет размерность отношения.
                                          А суммы везде отражаются с округлением до минимальной единицы. Цента, копейки или сатоши. Взяли курс, взяли сумму в одной валюте, вычислили сумму в другой с учетом наших правил округления, и получили целое число минимальных единиц. Другое дело что могут быть промежуточные этапы вычислений, и могут образоваться нетривиальные ситуации с округлением. Но дело в том, что само округление в любом случае есть.
                                          • +1
                                            курсы даются с точностью до сотых долей цента/копейки


                                            Курс в теории не ограничен количеством знаков после запятой.
                                            ЦБ на сайте выдает до 4 знаков после запятой.
                                            Но при при конвертации миллионов $, с таким курсом можно потерять несколько тысяч рублей.
                                            Поэтому иногда используют курс с 6 — 8 знаками после запятой.
                                            • 0
                                              Поэтому иногда используют курс с 6 — 8 знаками после запятой.

                                              Любые 2-4 к ЦБшному дописывают или строго нули?
                                              • 0
                                                Я это встречал только в банках при хранении внутренного курса банка. Там дописывают те, которые считаю нужным (да и первые цифры тоже от ЦБшных могут отличаться).
                                        • 0
                                          40 nano центов
                                          • 0
                                            Ни одного, и вообще такие операции откажемся проводить — так сейчас считают большинство обменников, с которыми я сталкивался… Есть минимальная сумма, от которой операция разрешается — это округлённое в большую сторону количество копеек за один цент.
                                          • 0

                                            Лог лучше или хуже в данном случае? А то у себя для денег как раз лонг выбрал.

                                            • 0

                                              Это вопрос необходимого уровня абстракции

                                            • 0
                                              Плюсую. В одном конкретном известном мне банке так и делается (про остальные банки просто не в курсе).
                                              • 0
                                                Веселье начинается обычно с вычисляемыми денежными суммами. Например, процентами на остаток на счете за некоторый период. Они изначально имеют не целый тип. Но про хранение копеек в лонге все равно плюсую.
                                                • 0
                                                  в банках в абс деньги хранятся в базе в обычных decimal. Сам виде.. делал
                                                  • +1
                                                    Боюсь, что в банках в этом плане полный зоопарк. В пределах одной АБС может быть в одной таблице decimal, а в другом bigint или даже float. Поскольку нигде нет документации, где сказано: «Вот делайте так, и да пребудет с вами Cила».
                                                    • 0
                                                      то, что decimal лучше подходит для хранения денежных сумм, это да, не спорю. Но если, например, от 1353 рублей 65 копеек нужно взять 18,5 % за несколько дней, то результат легко может быть разным в случае округления до целых копеек до суммирования по дням и в другом случае, когда округление выполняется после суммирования.
                                                      Ниже уже написали, все это должно быть прописано в нормативных документах банка.
                                                      • 0
                                                        ну реальность такова, что на все расчеты нормативки не напасешься. Плюс в половине случаев даже аналитики не знают где ее искать. Но это так, лирика.
                                                        • 0
                                                          В основном в кредитных договорах формула тщательно расписана, включая краевые эффекты, прямо в договоре. Полагаю формула в договоре согласована с формулой в софте.
                                                • 0
                                                  Цена с НДС 2311 «монеток» — сколько это будет без НДС? а сколько будет величина НДС? -)
                                                  • 0
                                                    Стоимость без НДС = Стоимость с НДС / 118 * 100 (если НДС 18%)
                                                    НДС = Стоимость с НДС / 118 * 18 (если НДС 18%)
                                                    • 0
                                                      Hint: не все числа с точностью 2 знака после запятой можно безболезненно разделить на 1.18 =)

                                                      Ну или попроще «3 шарикоподшипника на сумму 100 руб.» -)
                                                      • 0
                                                        Всегда можно найти компромиссы: либо стоимость с НДС делать кратным 1.18, либо к любой стоимости без НДС добавлять НДС (избавить себя от лишних расчётов).
                                                        • 0
                                                          Ога-ога =)
                                                          Заодно построить поставщиков на предмет кратности -)

                                                          p.s. Next Level: счет-фактура и фискальный чек — там несколько взаимоисключающе вычисления -)

                                                          p.p.s. Собственно решения для всех этих случаев есть, не всегда бескостыльные, но тут увы…
                                                          • 0

                                                            Точно. Особенно, если контракт с сайта госзакупок пришёл

                                                            • 0
                                                              Хватает даже просто контрактов с полугосами, по которым после отгрузки вылезает отказ в оплате типа «в документе хххх на сумму 100500 миллионов рублей 37 копеек в строчке 47645 указана цена за единицу 13.11 копеек и количество 0.01, а в контракте на странице 873 оговаривалась цена 13.10 копеек без НДС» -))
                                                • –1
                                                  я человек простой. прочел. понравилось. говорю автору спасибо!
                                                  з.ы. и это, друг, в 3:30 лучше спасть, а не на хабр писать xD
                                                  • +2

                                                    А может он из Владивостока

                                                    • +1
                                                      где-то тут была статья про время…
                                                  • +7
                                                    Те кто не когда не работал в банках может что то и откроют для себя новое, но реально все гораздо сложнее.
                                                    В нормальных системах существует цела иерархия объектов и классов предназначенных для работы с денежными объектами. И она существенно сложнее чем вы описываете.
                                                    Есть правила расчетов – то с какой точностью ведутся расчёты для примера для рубля РФ это чаще всего 4 знака после запятой(т.е. с точностью до 0,01 коп.)
                                                    Правила округления, правила отображения и печати сумм. Вводится понятие операция: кредитовая или дебетовая. И еще много вроде бы очевидных вещей, но наличие «стандарта» на них обязательно.
                                                    А уж если вводился понятие счет (объект для хранения сумм и правил работы с ними) то описания подобных вещей реально взрывает мозг. Там и связанные счета и активные и пассивные. А сверху это цементируется понятием «проводка» чтобы исполнялся закон сохранения энергии — закон сохранения денег.
                                                    И все это ноу-хау о которых разработчики не очень любят распространяться.
                                                    • +3
                                                      Это никакое не ноу-хау, это знание предметной области.
                                                      • +6
                                                        При всем уважении к производителям банковского софта я бы не решился назвать описанные вами нюансы очень сложными. И что-то пока даже по работе ведущих банков не заметно, чтобы разработчики сами хорошо владели своим ноу-хау.
                                                    • +1
                                                      Спасибо, очень доходчиво
                                                      • +4
                                                        Не так давно в новостях много рассказывалось о так называемом «техническом овердрафте», который якобы образовался на карточных счетах клиентов в одном российском банке.

                                                        Технический овердрафт по карточному счету это немного другое.
                                                        Сложилось так, что кредитовый карточные продукты (с точки зрения платежной системы) выдают в банках клиентам, у которых нет кредитного лимита. В результате возникают такие уродцы как "Золотые дебетовые карты Visa и MasterCard".
                                                        Кредитная карта (по правилам платежной системы) допускает операции в offline без жесткого контроля лимита, а у клиента кредитного лимита в банке нет.
                                                        И такие ситуации (на счете 0, а приходит presentment по операции сделанной ранее в offline), скромно называют "технический овердрафт".
                                                        Назначая драконовские проценты и т.д. Забавно все это...


                                                        Вообще то, для дебетового счета существуют дебетовые карты (типа Visa Electron). Технология которых подразумевает только on-line авторизации (по правилам платежной Системы), что в какой то мере гарантирует "дебетовость". Про извраты с приемом дебетовых карт в offline лучше печально промолчать.


                                                        Само наличие у человека кредитной карты (кредитные карточные продукты) в других странах означает: Банк клиенту доверяет и открыл ему кредитную линию. Gold кому попало не дают. Поэтому для аренды машины, бронирования и пр. карту кредитную (кредитовый карточный продукт Платежной Системы).


                                                        А у нас даже бомжу (если почитать на сайтах Российских банков) могут Visa Platinum выдать на дебетовый счет.

                                                        • –1
                                                          Так ли часто бывает, что у держателя карты нет денег на счету, а он этой картой за границей расплачивается? Как же ему визу дали?

                                                          Думаю, в основной массе там имело место списание платы за обслуживание. И вот тут как раз вопрос, куда они эти средства зачислили. Если в доходы, то это провал.
                                                          • 0
                                                            Так ли часто бывает, что у держателя карты нет денег на счету, а он этой картой за границей расплачивается?

                                                            Да сплошь и рядом. Сам так попадал. Не ту карту сунешь второпях..


                                                            Как же ему визу дали

                                                            C визой это никакой связи не имеет. Причем здесь деньги на счету. Никто это не контролирует. Всегда только справку о доходах на шанген подавал (и дают его на 3-5 лет обычно).


                                                            Типичный способ попасть на теховер:


                                                            1. несколько карт.
                                                            2. Перепутал карту. (воспользовался специально выделенной дебетовой с минимальным остатком для paypal и/или покупок в Азии)
                                                            3. не удосужился проконтролировать остаток перед поездкой
                                                            4. и пр.

                                                            Оплачиваешь услуги типа платной дороги, кофе в вендинговой машине, проезд в метро и тп. и тд. (суммы мелкие и как правило в offline).
                                                            Запросто можно выйти за пределы остатка и "попасть" на так называемый теховер.


                                                            Да еще эти транзакции в банк могут приползти через неделю или больше.


                                                            Думаю, в основной массе там имело место списание платы за обслуживание.

                                                            Типично банки просто карту блокируют если средств на очередную плату за обслуживание не хватает. А поскольку плата берется каждый месяц (и авансом), то потери банков от "на счете 0, клиент забил на платеж и исчез" минимальны. И никто особо по этому не беспокоится.


                                                            Что там проскочило в новостях (без всяких подробностей)… Уровень журналистов знаю и поэтому такие "желтые" новости всегда делю на 10 минимум.

                                                            • 0
                                                              за границей можно и в интернете расплатиться, и если за 1-2 дня курс резко скакнул вверх, то легко попасть в теховер — авторизация (блокировка средств) приходит по курсу даты совершения операции, а списание фактически происходит через 2-3 дня по курсу того дня, когда оно пришло в банк.
                                                              день Х — на карте 5600 рублей, курс бакса 56, покупка на 100 баксов прошла успешно
                                                              день Х+2 — курс 58 рублей, пришло списание 100 баксов, с карты списалось 5800 баксов и клиент должен банку 200 рублей (тех овер).

                                                              Ну и еще миллиард способов попасть в тех овер — типа штрафов за прокат машины, выпитый минибар в отеле и т.д.
                                                              • +1
                                                                Теховер может возникнуть и из-за того, что деньги на карте фиксируются в двух местах — в процессинговом центре карты и в банке на счете. В процессинговом центре суммы обновляются быстрее, чем в банке, хотя банк и обменивается информацией с процессингом, но реально операции по счету совершенные с помощью карты фиксируются позже, после подтверждения с терминала или банкомата. Это и порождает различные ситуации, например пополняешь карту в банкомате, через некоторое время рассчитываешься картой, в банк сперва пришла информация, о том что деньги потрачены, образуется теховер, потом приходит информация о пополнении карты, теховер закрывается. Еще можно снять деньги в кассе а потом если успеть потратить деньги в магазине, пока системы не обменялись информацией, также попасть в технический овердрафт, только гасить его придется самому.
                                                                • 0
                                                                  это вообще из эпохи 20 летней давности кейс похоже(пока слип бумажный по почте идет), или просто полет фантазии.
                                                                  Если в процессинге еще нет информации о зачислении и средств для авторизации не хватает, то он просто отобьет ее, а не загонит клиента в овер.
                                                                  • +1
                                                                    просто полет фантазии.

                                                                    Нравятся мне такие без безапелляционные заявления…
                                                                    Вы вообще в этой обрасти работали когда ни будь?
                                                                    Я так уже больше 15 лет платежными картами занимаюсь.
                                                                    Слипы блин…
                                                                    У меня вот на моей личной EMV карте лимит offline есть. Хотя она к дебетовому счету привязана. Сам лично в служебном ПО ее ковырял и профиль анализировал. Чисто из любопытства.
                                                                    Зачем банк такие карты заказывал — ХБЗ.

                                                                    • 0
                                                                      А разве оффлайн лимит небольшой в некоторых случаях не штатная функция?
                                                                      Просто вспоминаются покупки через Samsung Pay с использованием дебетовой карты, место такое что связи там нет, оплата проходит успешно, ИБ платеж не видел несколько дней хотя обычно сразу видит. Суммы в этих случаях всегда меньше 1000 рублей были.

                                                                      • +1
                                                                        А разве оффлайн лимит небольшой в некоторых случаях не штатная функция?

                                                                        Штатная для кредитных карт, привязанных к банковскому счету с кредитной линией.
                                                                        В иных случаях (дебетовый счет) запросто может возникнуть ситуация "технический овердрафт".
                                                                        Есть Кредитный карточный продукт Платежной Системы. Он четко описан правилами конкретной платежной системы. Кредитные карточные продукты технологически допускают транзакций без online обращения к эмитенту (к процессингу эмитента). Это означает, что если эквайрер выполнил все требования ПС по авторизации (выполнил без обращения к хосту эмитента), то это не его дело есть деньги на счету клиента или нет.
                                                                        Это проблема банка/организации эмитента карт.


                                                                        По простому… (исторически сложилось… слипы..), если карта с "выпуклыми цифрами" — то это кредитный карточный продует. Если с "давленными", то дебетовый.


                                                                        Кстати, никто не мешает эквайреру обслуживать и, например, Maestro в offline (видел и такое извращение), особенно если эмитента = эквайрер.
                                                                        Но в общем случае по дебетовым картам технический овердрафт не получить.


                                                                        Хотя я видел и Maestro и Electron (логотип) эмбоссированных как будто это Кредитный карточный продукт. Уж не знаю, как они апрув получили на эмиссию такого дизайна.


                                                                        В общем, не надо путать Карточный продукт Платежной Системой с тем, как какой счет в банке. "Снаружи" никто и не знает дебетовый у вас счет или с кредитной линией.

                                                                        • 0
                                                                          Оффлайн лимит, CVM-лист и тип продукта вообще ни как не связаны.
                                                                          Про эмбоссинг/индент тоже чушь :) разница только в том, можно ли ее катать в импринтере или нет.
                                                                          • 0
                                                                            Про эмбоссинг/индент тоже чушь :) разница только в том, можно ли ее катать в импринтере или нет.

                                                                            Да ну? А Вы не в курсе про требования к продуктовому дизайну карт, рекомендованным профилям персонализации (куда CVM входит) и согласование эмиссии с ПС (Visa|MC|CUP|Мир)?
                                                                            Что не разу не сталкивалиcь? Ни разу такие документы от ПС не видели и процедуру согласования эмиссии не проходили?


                                                                            И правила для эквайреров по настройке терминалов/обслуживания разных карточных продуктов (по AID, по логотипам) ни разу не читали?


                                                                            Что то меня сомнения берут насчет вашего опыта в 12 лет...

                                                                            • 0
                                                                              да все это согласование это заполнение трех экселек-опросников :)
                                                                              хорошо если бизнес вообще понимает что туда пишется и сколько денег за это платить :) а так туда можно вообще все что угодно запихать и мпс радостно согласует — любой каприз за ваши деньги.
                                                                              • 0

                                                                                Ну да. Только в опроснике обычно ссылка идет на типовой профиль.
                                                                                А если что то не типовое, то переписка с ПС (а можно так?).
                                                                                Возможно эта переписка перестраховка. Но кому хочется брать на себя ответственность?
                                                                                Бизнесу все подешевле… бы…
                                                                                И появляются уродцы типа Maestro|Electron instant карта с эмбоссированием и дизайном косящим под visa infinite. "А чо круто же смотрится".

                                                                            • 0

                                                                              чего то я начал через чур активно возмущаться; )
                                                                              Задевают фразы "чушь".
                                                                              Извините.
                                                                              Предлагаю прекратить и общаться покорректнее.


                                                                              А тип продукта и профили и дизайн все же связаны.
                                                                              Получить от Плат. Системы добро на "нестандартный" дизайн/профиль — практически не реально

                                                                              • 0
                                                                                делали в мпс на букву М голдовую карту с индентом по бину зарегистрированному как кредитный. без смс и регистрации.
                                                                                • 0

                                                                                  Наверное у вас крупный банк, что MC так пошел навстречу.
                                                                                  Голд с идент это что очень странная комбинация. ATM все равно. Хоть Gold, хоть Cirus.


                                                                                  А смысл Голда, на мой взгляд, помахать им в аэропорту что бы в VIP lounge попасть. Но Gold с идентом…
                                                                                  Народ (сотрудники сервиса) то привык к конкретному внешнему виду карт. Им же "буквари с картинками" показывают..


                                                                                  Впрочем, я и не говорил, что не бывает. Приводя пример Electron c эмбоссированием.
                                                                                  Но как объяснить обычному человеку как на беглый взгляд отличить разные карточные продукты? Логотип и тип печати.
                                                                                  Тип печати нагляднее и понятнее и в 99% верен.
                                                                                  Разве не так?

                                                                                  • 0
                                                                                    в наш чудный век от этого всего лучше вообще абстрагироваться :)
                                                                                    договор заключенный с банком — вот что важно, а карта это просто разрисованный кусок пвх :)
                                                                                    • 0

                                                                                      Карта это то же весчь бывает.
                                                                                      Валяются образы пластика (рекламные):


                                                                                      1. Светящиеся (Не помню чьи)
                                                                                      2. Прозрачные с голограммой бабочки (шлямбурже еще)
                                                                                      3. С запахом. Уже не пахнут… (Gеmplus)
                                                                                      4. Бесконтактные в разном форм-факторе (только в зубную щетку не догадались засунуть)

                                                                                      Даже обидно, что рано или поздно будет вытеснены другими средствами платежа.


                                                                                      Даже самые первые Java карты Gemplus (еще с усеченном 3DES) валяются. И VisualBasic OS карта и диск Microsoft SDK для нее (2000год).
                                                                                      RIP карте MS..

                                                                                      • 0
                                                                                        И VisualBasic OS карта

                                                                                        Что это за зверь?
                                                                                        • +2

                                                                                          Была неудачная попытка Microsoft выйти на рынок смарт карт. В пику Java картам. VB в качестве языка написания апплетов… Вызвала неподдельный (скептический) интерес на конференции в 2000 году.
                                                                                          Нашел у себя диск тех времен и из ностальгических воспоминаний памятнику ему сделал: )


                                                                                          • 0
                                                                                            Хм, это они смело. Спасибо.
                                                                          • 0
                                                                            это кейс когда авторизация в онлайне вообще в процессинг не летит, в банк через системы файлового обмена с платежными системами только финансовое требование на возмещение прилетает за авторизованную в оффлайне сумму
                                                                          • 0
                                                                            здравствуйте коллега :) 12 лет в отрасли :)
                                                                            как вы знаете по своему опыту — оффлайн операция прилетит в клиринге, а это лаг минимум в 1-2 дня. Если в банке пополнение карты через АТМ происходит через АБС сперва а синхронизация АБС-Процессинг имеет лаг больше 1-2 дней, то мое утверждение про кейс 20-летней давности и/или полет фантазии справедливо.

                                                                            Однако если вы 15 лет печатаете пин-конверты, то скорее всего этого не знаете, хотя и работаете в этой отрасли: Р
                                                                            • 0
                                                                              cинхронизация АБС-Процессинг имеет лаг больше 1-2 дней

                                                                              Это кейз 20 летной давности. Голубиной почтой…
                                                                              Не встречал банк, который бы не требовал синхронизации минимум раз в день.
                                                                              А большинство вообще через on-line интерфейс с процессингом предпочитают.
                                                                              Впрочем, без конкретных примеров АБС+процессинг — это разговор ни о чем.


                                                                              Если в банке пополнение карты через АТМ происходит

                                                                              Если уж корректно говорить, то функция пополнения счета наличными в АТМ с идентификацией (аутентификацией) по карте, это не стандартная операция и вариантов реализации существует много. И процессинг (если это его сетка) может поддерживать это. И в АБС может напрямую (через on-line API) зачисления идти.


                                                                              Однако если вы 15 лет печатаете пин-конверты, то скорее всего этого не знаете, хотя и работаете в этой отрасли: Р

                                                                              Начнем бодать и меряться? Так смысла нет. Если вы еще в этой области работаете, то прекрасно понимаете, что конкретными примерами я не могу оперировать (иначе по шапке получу).


                                                                              А на счет PIN конвертов… А что, вам известны какие то другие способы кроме:


                                                                              1. Выдачи карты с конвертом.
                                                                              2. Выдачи карты с собственоручным вводм клиентом нового PIN в служебном терминале.
                                                                              3. Выдачи PIN через AVRS (телефон)
                                                                          • 0
                                                                            в процессинге информация то есть, а вот в банке — еще пока нет.
                                                                            • 0
                                                                              разрешение на снятие средст с карты (авторизацию) как раз процессинг и дает.
                                                                              Нет средств — в авторизации откажут с 51 кодом.
                                                                              • 0
                                                                                На карте есть деньги
                                                                                ПЦ об этом знает (как следствие разрешение на авторизацию ПЦ дает)
                                                                                Банк — не знает
                                                                                В Банке открывается теховер, не в процессинге, а в банке.
                                                                                • 0
                                                                                  так не бывает :) просто в банке ни чего не открывается и не происходит.
                                                                                  счета ведутся в АБС, а не где-то в вакууме в банке.
                                                                                  Теховер это задолжность по счету неразрешенной задолженности. Задолжность по счету образуется в результате банковских проводок. Проводки по банковским картам попадают в АБС в результате появления требований с клиентского счета от платежных систем или собственных устройств. Эти требования в первую очередь появляются в процессинге (если свое устройство то от устройства при проведении операции, если другого банка то в результате файлового обмена с платежной системой — виза/мс/мир).

                                                                                  Если о пополнении карты процессинг знает и дает разрешение на авторизацию, то и проводки по пополнению он тоже выгрузит — одновременно с требованием по операции списания.

                                                                                  Хотя конечно нарукожопить можно все что угодно. Например требования выгружать в течении всего дня, а пополнения выгружать только при закрытии дня(или вообще после инкассации кеш-ин банкомата :) ).
                                                                          • 0
                                                                            В актуальных системах конкретно описанные вами сценарии не пройдут. Процессинг знает, на какую сумму он одобрил вам транзакций, и не даст уйти в минус (отклонит транзакцию). Но, я вполне верю, что такие ситуации возможны в какой-нибудь условной Оклахоме, где используются системы тридцатилетней давности, импринтеры, слипы, вот это всё.

                                                                            Реальный сценарий, возникающий из-за разделения авторизации и финансового представления: вы купили товар за 100$ = 5867р, и остался у вас на счету 1р. А представление пришло через неделю, и обработалось по курсу 59.00р/$, вот вам и минус на счету.
                                                                            • +1
                                                                              В актуальных системах конкретно описанные вами сценарии не пройдут.

                                                                              Проезд на транспорте по банковской бесконтактной карте — практически никто не использует авторизацию в on-line. (Авторизации проводятся позже пакетно. С утерянной выгодой мирятся).
                                                                              Вендинговые машины в Европе… везде offline.
                                                                              Оплата платных дорог — везде offline.
                                                                              Курьез — оплата туалета на ЖД вокзале в Норвегии (точно не помню какой) — картой в off-line.


                                                                              Ага… системы 30 летней давности… слипы…
                                                                              Off-line лимит на VSDC|UP|MChip карте — это отнюдь не "off-line остаток". А просто типично сбрасываемый в начальное значение лимит при любой успешной online авторизации.
                                                                              Сделан под кредитные банковские продукты. А не под дебетовые.


                                                                              То что Вы никогда не сталкивались с off-line платежами по чиповым картам совсем не означает, что это их не бывает.

                                                                              • 0
                                                                                Перечитайте пожалуйста оригинальный сценарий, на который отвечали — там кейс с тем что пополнение дольше обрабатывается чем списание.
                                                                                • –1

                                                                                  Ну да. Там сумбурно написано. Сходу понял не так.
                                                                                  Перечитал еще раз.


                                                                                  Это и порождает различные ситуации, например пополняешь карту в банкомате, через некоторое время рассчитываешься картой, в банк сперва пришла информация, о том что деньги потрачены, образуется теховер, потом приходит информация о пополнении карты, теховер закрывается.

                                                                                  Такого конечно не бывает. Теховер по on-line операциям (снятия нала в АТМ) естественно не возможен.

                                                                          • 0
                                                                            Как же ему визу дали?
                                                                            Занимаешь денег у друзей на день. Кладёшь их на счёт в банке. Берёшь справку с этого счёта. Снимаешь деньги. Раздаёшь занятое. Профит.
                                                                            • +1
                                                                              А потом уходишь в минус и гуляешь без денег по Парижу в поисках, чего бы пожрать…

                                                                              Эх, как же скучно я живу.
                                                                              • 0
                                                                                Да и виза делается раз и несколько раньше поездки (я начал делать за три месяца до неё). А после справки три списания ипотеки (я забыл про это и у меня на следующий после справки списали), платежи по кредитке и ещё много чего. Наличная валюта для поездки у меня в руках была, а не на счёте. Так что эта справка вообще ни о чём не говорит.
                                                                          • 0
                                                                            С Visa Electron тоже может не прокатить — «Зачисление проводится раз в сутки, поэтому денег, которые вы только что положили на карту, на счёте нет, они есть только на карте».
                                                                          • 0
                                                                            Хорошо написано. Может когда-нибудь и пригодится. Спасибо!
                                                                            • 0
                                                                              Еще один проблемный вопрос из банковской практики обработки денежных сумм. При суммировании вычисленных денежных величин делать округление к целым копейкам до суммирования или после? Есть вполне реальные условия, при стечении которых это приведет к реально противоположным результатам.
                                                                              • +2
                                                                                На это в кредитной организации должны быть нормативные документы. Разработчик тут решать не может. В отсутствие четких требований я бы сформулировал следующие правила:

                                                                                • Количество округлений должно быть минимизировано
                                                                                • Если промежуточное значение фиксируется в документах, то его надо округлить
                                                                                • 0
                                                                                  > На это в кредитной организации должны быть нормативные документы. Разработчик тут решать не может.

                                                                                  Абсолютно согласен
                                                                                  • 0

                                                                                    Именно потому что округление все равно нужно, правило "не используйте double потому что сложно округлять" бессмысленно.


                                                                                    Если много операций, то double будет на порядок быстрее BigDecimal. Не всё так однозначно.

                                                                                    • +1
                                                                                      О, спасибо. Вспомнил 6-е правило: не экономьте на вычислениях с суммами.
                                                                                      • +3

                                                                                        Если давать советы, то нужно объяснять не только минусы, но и плюсы. А то придут новички, прочитают и бездумно применят.


                                                                                        У нас был отличный пример как разработали систему в которой все immutable, stateless и BigDecimal. Проблема с этой системой только в том, что ей нужно 20Gb Heap, чтобы показать табличку пользователям. Максимум 5 пользователей.

                                                                                        • 0

                                                                                          Так может использовать long, а не BigDecimal?

                                                                                          • 0

                                                                                            У меня, к сожалению, нет опыта использования long. В принципе должно сработать, если везде передавать: long amount + int precision.


                                                                                            Disclaimer: не пытайтесь повторить это дома и в бухгалтерской системе где скорость не важна :)

                                                                                          • 0
                                                                                            Вообще да, mutable BigDecimal был бы очень полезен. Так как каждое значение в новый объект запихивать может быть очень накладно. Его можно для своих нужд быстренько сделать или готовый скачать.

                                                                                            Я, пожалуй, погорячился насчет экономии, но ради производительности double применять все равно не стоит.
                                                                                    • 0
                                                                                      не делать округлений при выполенении операций, делать их только в момент получения из внешних источников и хранить у себя так как есть
                                                                                      • 0
                                                                                        К сожалению, не панацея. Например, при начислении процентов по вкладам или кредитам.
                                                                                        • 0
                                                                                          Проценты начисляются за полный период с его начала до даты начисления, затем округляются до копеек, затем уменьшаются на количество начисленных на конец прошлого периода. Таким образом достигается минимум ошибки округления, и она не накапливается со временем. Все это — в разрезе каждого договора. Сложностей и чудес нет.
                                                                                          • 0
                                                                                            Есть вот такая сложность. Допустим 10000 рублей лежит на депозите 100 дней. По ним за 100 дней получается некоторая сумма процентов. И берем второй случай, когда 10000 положили на депозит, через 50 дней сняли, открыли другой депозит, положили на него те же 10000 рублей еще на 50 дней. В итоге с высокой вероятностью получится, что начисленная сумма процентов за 100 дней на одинаковую сумму будет различаться на копейки. Казалось бы — мелочь. Но в реальности может оказаться головной болью для кредитной организации.
                                                                                            • 0
                                                                                              На практике никто не сравнивает суммы процентов за 100 дней по одному договору и за 50+50 по двум другим, у банка нет обязанности поддерживать их одинаковыми до копейки, а следовательно, нет и проблемы.

                                                                                              Более того, сумма процентов по первым 50 дням должна до копейки быть равна сумме по вторым 50. Таким образом, возможность выравнивания ошибки округления на горизонте 100 дней отсутствует также как и необходимость.
                                                                                              • 0
                                                                                                Хорошо, если и в самом деле так.
                                                                                                Просто когда я работал разработчиком ПО в банке, то на такой фразе:
                                                                                                > у банка нет обязанности поддерживать их одинаковыми до копейки
                                                                                                у нас люди не успокаивались ))

                                                                                                Фактически, в этом банке расчет начисляемых процентов по вкладам и кредитам идет на остаток на счете за каждый отдельный день, затем округление до копеек и суммирование процентов по дням за заданный период. Тогда проблема с вкладами на 100 и на 50 дней не возникает. Правда, и у этого метода есть недостаток. Так, если на двух депозитах на 1 год под 10% лежат суммы 10000р. и 10000р. 10к., то сумма процентов за год получится по ним одинаковая. Хотя, должна отличаться на 1 копейку.

                                                                                                ИМХО, все это должно быть прописано в правильно составленной учетной политике банка, на которую должен ссылаться любой договор между банком и клиентом. Тогда у банка будет чуть больше прикрытия от желающих доставить ему юридические проблемы по надуманным поводам.
                                                                                                • 0
                                                                                                  в этом банке расчет начисляемых процентов по вкладам и кредитам идет на остаток на счете за каждый отдельный день, затем округление до копеек и суммирование

                                                                                                  При таком расчете копится ошибка округления, причем немаленькая. А мелкие суммы (ниже 30 или 15 рублей, в зависимости от способа округления) могут вообще неопроцентиться никогда.

                                                                                                  При изменении суммы вклада (а также процентной ставки или любых других условий, влияющих на расчет процентов, например, количества дней в году) в рамках действия одного договора вводится понятие «периода постоянства условий начисления», период с начала действия договора по дату начисления разбивается на «периоды постоянства...» по ним проходят начисления процентов с округлением до копеек, затем начисленные проценты складываются.

                                                                                                  Вот такие ноу-хау. Иногда настолько хау, что большинство внедренцев АБС ни разу ни ноу (печальный опыт)
                                                                                    • +4

                                                                                      А ещё "сумму" лучше называть не sum, а amount.

                                                                                      • 0
                                                                                        У меня там внутри класса Sum поле amount.
                                                                                        • +2

                                                                                          Кажется, Amount.value было бы корректнее.

                                                                                      • +3

                                                                                        Про неотрицательные суммы — не согласен. В приведенном вами примере вы, фактически, предлагаете заменить одну проверку двумя (нужна была проверка на неотрицательность дебетового счета, предлагается ввести неотрицательность любого счета, автоматический кредит при нехватке средств и запрет кредита на дебетового счете). Но ведь проблема-то и заключалась в том, что программисты даже одну проверку — и ту забыли написать!


                                                                                        Чтобы избежать таких вот ошибок — надо не усложнять модель, а вводить внутреннее API, которое просто не даст совершить некорректную проводку.


                                                                                        А отрицательные суммы на уровне модели очень даже полезны. Вот недавно был пост про двойную бухгалтерию, где было показано, что простая смена знака пассивным счетам позволяет объединить в один все типы проводок.

                                                                                        • 0
                                                                                          Это значит, что признак дебета-кредита сохранили внутри числа в знаковом бите. При этом в команде должен быть супергуру, который помнит, что на пассивных счетах отрицательные суммы означают дебет, положительные кредит, а на активных наоборот. Остальные же разработчики воспринимают эти понятия как магию и боятся заглядывать в код, который ее реализует.

                                                                                          Мой подход таков: Каждый переход суммы через 0 — это инцидент, требующий анализа. Когда же мы используем знак, то мы просто откладываем расследование этого инцидента со стадии разработки в рантайм.
                                                                                          • +1
                                                                                            Почему в рантайм?
                                                                                            Знак числа никоим образом не может быть единственным источником типа счета.
                                                                                            Это даже не вопрос грамотной нормализации и т.п., а просто неизбежный факт — возможность существования нулевых значений у счета делает данный признак бессмысленным.
                                                                                            На самом деле у любого действия с деньгами (будь то проводка или «кварковая проводка» моих оппонентов, не суть) есть информация о том с каким счетом мы работаем. И этот счет «знает» свои правила. В простейшем случае — активные счета не могут быть отрицательными, пассивные — положительными. В реальной жизни таких валидаций может быть много разных. И на суммы транзакции, и на «неснижаемые остатки» и счета у которых всегда ноль, и только ноль и т.п.
                                                                                            Соответственно если у нас стоит ограничения что бывают только активные и пассивные счета, а активно-пассивных нет в принципе (а это достижимо даже в регламентированном учете), то в рантайме как раз переходов через ноль не будет физически, ибо валидатор просто не пропустит такую операцию. Так что разбираться придется еще на этапе разработки или тестирования.
                                                                                            • 0
                                                                                              Просто мы с вами используем разный понятийный аппарат. То, что вы называете «отрицательным активным счетом» я называю «кредитовым сальдо по активному счету». Когда вы говорите, что «пассивный счет не может быть положительным», я говорю:
                                                                                              «Образование в конце дня в учете дебетового сальдо по пассивному счету или кредитового по активному счету не допускается».

                                                                                              Поскольку я обхожусь без понятий о