Работа с денежными суммами

Для работы с деньгами heap-таблицы поддерживают специальный тип поля  Money , который представляет собой семантически корректное представление денежных сумм. Обладает следующими свойствами:

  • Хранит сумму вместе с валютой.

  • Значения представлены в виде экземпляров специального класса  Money , который предоставляет методы для корректных с точки зрения округления и валюты операций над деньгами.

  • Методы фильтрации и сортировки таблицы поддерживают специальный синтаксис и семантику для денежного типа

Фильтрация

Фильтрация по денежному типу поддерживает несколько вариантов:

  • По деньгам в целом - сумма с учётом валюты. Наиболее "безопасный" вариант.

  • По сумме без учёта валюты. Можно выстрелить себе в ногу, но в умелых руках может быть полезно.

  • Отдельно по валюте.

Безопасная фильтрация по деньгам с учётом валюты

Если у в таблице объявлено поле  money: Heap.Money() , то вы можете "сравнивать" его в фильтрации:

  • С объектом класса Money

    import { Money } from '@app/heap'
    await table.findAll(ctx, { where: { money: new Money(10, 'RUB')} }
    
  • С парой сумма+валюта вида [10, 'RUB']

    await table.findAll(ctx, { where: { money: { $lte: [1000, 'RUB'] } } }
    
  • С нулём. Сравнение с любыми другими значениями суммы без валюты небезопасно.

    await table.findAll(ctx, { where: { money: { $gt: 0 } } }
    

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

В этом режиме не поддерживается IN-фильтрация, когда в правой части указан массив со списком значений. Если необходимо сравнить со списком значений, можно использовать сравнение с псевдо-полем amount (см. ниже).

Фильтрация отдельно по сумме и валюте (псевдо-поля  amount  и  currency )

Для случаев, когда разработчик знает, что делает, поля типа Heap.Money поддерживают фильтрацию отдельно по сумме, отдельно по валюте, а также их комбинации. Для этого в фильтре можно использовать специальные дочерние псевдо-поля amount и currency. Для каждого из них поддерживается IN-фильтрация по списку значений, но для currency не поддерживаются стандартные операторы сравнения.

  • Только сумма:

    await table.findBy(ctx, { money: { amount: { $gt: 100 } } })
    await table.findAll(ctx, { where: { money: { amount: [10, 20, 30, 40] } } })
    
  • Только валюта:

    await table.findBy(ctx, { money: { currency: 'USD' } })
    await table.findAll(ctx, { where: { money: { currency: ['RUB', 'EUR'] } } })
    
  • Когда указаны оба поля, это сооветствует двум условиям, объединённым через AND :

    await table.findBy(ctx, { money: { amount: [10, 20, 30, 40] currency: 'USD' } })
    await table.findAll(ctx, { where: { money: { amount: { $lt: 1000 }, currency: ['USD', 'EUR'] } } })
    

Сортировка

Если поле с типом Heap.Money используется в свойстве order метода findAll, то действуют следующие принципы:

  • Сначала записи сортируются по коду валюты в алфавитном порядке (в соответствии с выбранным направлением сортировки).
  • Группа каждой валюты сортируется по числовому значению суммы отдельно в соответствии с выбранным направлением сортировки.

Сортировка по сумме без учёта валюты, а также по отдельно по валюте не имеет практического смысла и поэтому не поддерживается. Если необходимо получить строго упорядоченный по сумме список, следует отфильтровать его по одной валюте с помошью псевдо-поля currency.

await table.findAll(ctx, { where: { money: { currency: 'USD' } },
order: { money: 'desc' } })

Автоматическое приведение значений к единой валюте для корректной сортировки также не поддерживается, но легко выполнимо в обычном js-коде, если имеются курсы обмена валют.

❤️ Made with love on Chatium

ООО "Чатиум"

Информация о компании