Правила за код с пари: Никога не викайте `longValue()` върху бакшиш

Три малки правила, които пазят платежния код от изгубени центове, удвоени плащания и йени, таксувани като евро.

Във всеки платежен проект има по един такъв ред. Написан е в тих следобед от напълно разумен човек:

long cents = (amount * 100).longValue()

Компилира се. Минава теста с 10.00. Качва се на продукция. И докато съществува, тихо взима по една стотинка от част от плащанията.

В Bakshish го имаше на шест места. Намерихме ги при един одит и ги махнахме всичките. Ето с какво ги заменихме - и кои са другите две правила, които вървят с него.

Правило 1: парите се закръглят, не се режат

longValue() не закръглява. Отрязва. Вземете 5% такса на платформата върху бакшиш от 5,55:

  • 5,55 x 0,05 = 0,2775
  • В центове: 27,75
  • longValue() казва 27. Закръгляването "нагоре" казва 28.

Една стотинка. На едно плащане не се вижда. За месец всяка такса, която не е цяло число, върви в една и съща посока: винаги надолу. Това не е шум, а систематична грешка - и счетоводната ви книга започва да се разминава с платежния доставчик с малко повече всеки ден.

Решението е една функция, през която минава всяка сума:

amount.setScale(2, RoundingMode.HALF_UP).movePointRight(2).longValueExact()

Две подробности тук са от значение:

  1. HALF_UP е написано изрично - никой не гадае какво закръгляване се има предвид.
  2. longValueExact() хвърля грешка, ако числото не се побира, вместо тихо да върне грешна стойност.

Шумна грешка в три следобед е за предпочитане пред тиха в сметките.

Правило 2: десетичните знаци не винаги са два

Нашата функция получава и валутата. Еврото има два знака след запетаята. Японската йена няма нито един: 500 йени е 500, не 50000. Умножете всичко по 100 и бакшиш от 500 йени става такса от 50 000.

Ние работим в евро, затова това никога не ни се е случвало. Но точно затова му е мястото в помощната функция: в деня, в който някой добави нова валута, грешката не трябва да го чака. Списък с валутите без десетични знаци и fractionDigits(currency) са точно дванайсет реда код.

Правило 3: записвайте плащането точно веднъж

Третото правило не е за аритметика. То е за ситуациите, в които едно и също плащане пристига два пъти.

Бакшишът се потвърждава от браузъра, но платежният доставчик го съобщава и чрез уебхук (webhook) - в случай че браузърът така и не е върнал отговор. Двата пътя свършват в един и същ метод. Обикновено единият печели със секунда-две. Понякога обаче идват едновременно.

Затова записването на плащане трябва да е безопасно при повторение (идемпотентно):

  1. Потърсете плащането по номера му при доставчика. Ако вече е записано, върнете записа и спрете.
  2. В противен случай го вмъкнете с уникален индекс върху този номер в базата данни.
  3. Ако две заявки минат заедно покрай стъпка 1, индексът отхвърля втората. Тя опитва още веднъж, намира вече записания победител и го връща.

Проверката в кода е просто любезност. Индексът е истинската гаранция. Искате базата данни да каже „не“, защото само тя вижда абсолютно всички заявки.

Със събитията от уебхуци е същото: всяко се пази по източник и номер на събитие. Така доставчик, който изпрати събитие повторно (а всички го правят рано или късно), не може да плати на някого два пъти.

Накратко

Кодът за пари е код, в който скучните случаи имат голямо значение. Правилата са прости:

  • Преобразувайте стойностите на едно място, закръглявайте изрично, чупете се шумно.
  • Нека валутата решава колко са десетичните знаци.
  • Направете „запиши това плащане“ безопасно за двойно извикване и оставете базата данни да го налага.

Нищо от това не е прекалено хитро. Именно в това е смисълът. Хитростта е за онези части на системата, където една стотинка няма значение.

Потърсете longValue() в кода си още днес. Ако стои до цена, имате какво да оправите преди обяд.

Искате бурканът ви да отговаря на въпроси?

Заявете демо и вижте как Bakshish работи за вашето заведение: QR код на масата, бакшиш за секунди и ясна справка за екипа.

Заявете демо

Още от блога

3 мин четене

Бакшиш за 3 секунди

Всяко излишно докосване е още един шанс гостът да размисли.

← Всички публикации