Нотатки · жовтень 2026
Повернення, більше за замовлення: €500 записано за замовленням на €29,99.
Магазин трикотажу зібрали в Claude Code за 17 повідомленнями звичайними словами. Це демонстраційний магазин, зібраний для кейсу, з вигаданими покупцями й тестовими даними. У ньому є сторінка повернень: власник схвалює повернення, речі надходять назад, і власник повертає за них гроші. Оплати карткою повертаються на картку через Stripe. Якщо платили банківським переказом, власник надсилає гроші з банку й позначає повернення як виплачене, вписуючи суму, яку надіслав.
Цю суму перевіряли лише на одне: чи це число. Stripe не повернув би €500 на картку. Діра — у тому, що записав магазин: у замовленні, у звітах за місяць і в листі покупцеві.
Що сталося
Покупець повернув одну пару шкарпеток із замовлення на €29,99. Власник вписав 500 у поле суми й натиснув «Mark as refunded».
- Суму прийнято. У замовленні значилося: повернуто €500.
- Повернення за місяць на дашборді й у звітах зросли на €500.
- Покупець отримав лист «Your refund of €500 is on its way».
- Записане повернення потім не можна було виправити.
Вводити 500 навмисно нікому не треба. Те саме зробить одрук в одній цифрі або десяткова кома в полі, яке мовчки її відкидає: 23,99 від людини, звиклої до європейського запису чисел, перетворюється на 2399.
«Але ж Stripe не поверне більше, ніж заплатили»
Це правда, і саме тому цю діру легко проґавити. Stripe відмовляє в поверненні, більшому за те, що лишилося від платежу, тож сама картка в безпеці. Усе інше — ні:
- повернення, які записують вручну: банківські перекази, готівка, повернення, зроблене в кабінеті Stripe, а потім позначене в застосунку;
- запис замовлення, дашборд і звіти за місяць;
- облік, який бухгалтер веде за цими звітами;
- лист, що повідомляє покупцеві, скільки грошей до нього надійде.
Саме туди й дивляться власник і бухгалтер. У цьому магазині повернення на картку йшло через Stripe, і Stripe його обмежував; повернення за банківський переказ лише записувалося, і обмеження не мало зовсім.
Ще два шляхи до тієї самої діри
- Два часткові повернення з одного замовлення. Дві речі з одного замовлення повернули окремо, двома поверненнями. Для кожного сторінка пропонувала ціну речі плюс вартість доставки. Погодьтеся з обома пропозиціями — і доставку повернуть двічі: за замовленням повернуто більше, ніж заплатив покупець, хоча ніде немає жодного одруку.
- Два повернення в один момент. Та сама форма відкрита у двох вкладках, або поверненнями займаються двоє людей. Перевірка, яка живе лише на сторінці («чи це менше за залишок?»), пропускає обидва, бо кожне читає замовлення раніше, ніж інше встигає в нього записати.
Виправлення
Обмеження тепер стоїть у базі даних, а не лише на сторінці. Повернення відхиляється, якщо воно більше за те, що лишилося від заплаченого покупцем, тобто за суму замовлення мінус усе, що вже повернуто. Поки йдуть перевірка й запис, замовлення заблоковане, тож два повернення за одним замовленням ідуть одне за одним, і друге бачить перше. Сторінка показує залишок ще до того, як щось надіслано.
Перша версія виправлення принесла власну проблему, і так буває часто. Для деяких замовлень завелике повернення записали ще до появи обмеження. Для них уже нічого не «лишалося повернути», тож їхні відкриті повернення взагалі не вдавалося закрити, навіть на €0, і вони лишалися відкритими назавжди. Остаточна версія дозволяє закрити таке повернення з нульовою сумою і не надсилає покупцеві листа, що повернення €0 уже в дорозі.
Кожен із цих випадків тепер — тест, який перевіряє саму базу даних: повернення, більше за сплачене, два часткові повернення, що разом дають забагато, два повернення одночасно і повернення, закрите, коли повертати вже нічого. Тести запускаються з кожною зміною, тож діра не може тихо повернутися.
Перевірте свій застосунок за п'ять хвилин
- Знайдіть кожне місце, де записується повернення: сторінку в адмінці, кнопку «mark as refunded», обробник події Stripe
charge.refunded, автоматизацію, яка записує повернення в таблицю. - Введіть суму, більшу за замовлення. Її відхиляють ще до збереження чи лише повідомленням на сторінці?
- Зробіть за одним замовленням два часткові повернення, які разом перевищують сплачене.
- Відкрийте форму повернення у двох вкладках і надішліть обидві одночасно.
- Після кожної спроби подивіться на три речі: замовлення, суму повернень за місяць і лист, який отримав покупець.
Якщо хоч щось із цього проходить, обмеження живе лише на сторінці або ніде. Його місце — у базі даних, поруч із записом, під тим самим блокуванням.