назад
24 янв

Храните деньги правильно

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

В ruby для этого используется гем Money.

Однако, у этого гема нет встроенной поддержки Mongoid, поэтому мы сделали свою.

Возможности

Хранение денежных данных с валютой и без валюты:

1
2
money_field :price
money_field :price2, fixed_currency: 'GBP'

Поле может быть обязательным и иметь значение по умолчанию:

1
2
3
4
# Значение по умолчанию
money_field :price3, default: '1.23 RUB'
# Обязательное поле
money_field :price4, required: true, default_currency: nil

Парсинг значений, введенных пользователем из форм, с учетом точек, запятых, и всего прочего мусора, который пользователь может ввести в поле ввода цены: $, %, €, руб, Р, р., 12,15руб, 23,123.25 - чего только не вводят пользователи, даже технически грамотные.

Позже Сергей Малых добавил в гем правильную и красивую поддержку валидации через Numeric Validator:

1
2
# Валидация поля как числового значения (с поддержкой локализованных десятичных разделителей)
validates_numericality_of :price, greater_than: 0

Для чего это нужно

Часто встречается, что программисты хранят деньги в БД в виде значений с плавающей точкой (float). Такой подход имеет множество недостатков, начиная от отсутствия данных о валюте, и заканчивая потерей точности данных и проблем округления при арифметических операциях с суммой денег.

А проще

Если вы храните деньги неправильно, Ваша бухгалтерия может быть очень удивлена и недовольна, узнав что 10 раз по 10 копеек это вовсе не рубль, а 99 копеек, или что если из 1 рубля 03 коп вычесть 42 коп, вовсе не получится 61 копейка.