Money.Input.Validator (Money.Input v0.1.0)

View Source

Business-rule validation for Money.t/0 values.

Why this is separate from Money.Input.Cast

Money.Input.Cast.cast/2 answers the question "can I turn this user input into a Money?" — shape and parse validation only. It rejects missing currencies and unparseable amounts.

This module answers the question "is this Money acceptable under my business rules?" — bounds (:min/:max), required-ness, an enforced currency, and currency-aware fractional-digit precision (USD ≤ 2, JPY ≤ 0, BHD ≤ 3). Money.new(:JPY, "1.5") is shape-valid but business-invalid for most apps.

Both pieces are usually wired through the Ecto.Changeset helpers in Money.Input.Changesetcast_money/3 then validate_money/3.

Summary

Functions

Validates a Money.t/0 against bounds, precision, and required-ness.

Functions

validate_money(value, options \\ [])

@spec validate_money(term(), Keyword.t()) ::
  :ok | {:error, Money.Input.ValidationError.t()}

Validates a Money.t/0 against bounds, precision, and required-ness.

Arguments

  • value is a Money.t/0 or nil.

  • options is a keyword list of options.

Options

  • :required — when true, nil is rejected.

  • :min — minimum allowed value. A Money.t/0, or any value Money.new/2 accepts (e.g. a Decimal or string) — when the latter, the bound takes the value's currency.

  • :max — maximum allowed value. Same shape options as :min.

  • :currency — when set, enforces that the value's currency matches.

Returns

  • :ok when every check passes.

  • {:error, %Money.Input.ValidationError{errors: [{atom(), String.t()}]}} with one entry per failing check, in the order :required, :currency, :decimals, :min, :max. Money.Input.Changeset.validate_money/3 unpacks the entries into per-field changeset errors.

Examples

iex> Money.Input.Validator.validate_money(Money.new(:USD, "1234.56"), max: Money.new(:USD, "10000"))
:ok

iex> {:error, %Money.Input.ValidationError{errors: errors}} =
...>   Money.Input.Validator.validate_money(Money.new(:USD, "1.234"), max: Money.new(:USD, "10000"))
iex> errors
[{:decimals, "must have at most 2 fractional digits"}]

iex> {:error, %Money.Input.ValidationError{errors: errors}} =
...>   Money.Input.Validator.validate_money(Money.new(:USD, 1), currency: :EUR)
iex> errors
[{:currency, "must be EUR"}]