---
title: "Money, units & currency lock — Coupons for Laravel | Roundly"
description: "How a coupon’s value is stored — minor units or basis points — and when a coupon must be locked to a single currency."
url: https://roundly-consulting.com/open-source/docs/coupons-for-laravel/money-and-units
language: en
---

[All packages](https://roundly-consulting.com/open-source.md)

[Coupons for Laravel](https://roundly-consulting.com/open-source/docs/coupons-for-laravel.md)

# Money, units & currency lock

Every amount is a RoundlyConsulting\\Money\\Money from money-for-laravel: exact minor units as an integer string, in a registered currency with its real exponent — no floats anywhere. A coupon’s integer value column means something different per discount type:

| Type | value means | Example |
| --- | --- | --- |
| `Fixed` | Minor units of the coupon’s currency | 500 + EUR = 5.00 EUR off |
| `Percentage` | Whole basis points, 0..10 000 | 2500 = 25 %, 1250 = 12.5 % |
| `FreeShipping` | Ignored (0) | — |

Minor units follow each currency’s real exponent, so zero- and three-decimal currencies are exact:

```php
use RoundlyConsulting\Money\Money;

Money::ofMinor(500, 'EUR');    // 5.00 EUR
Money::ofMinor(500, 'JPY');    // 500 JPY   (zero-decimal currency)
Money::ofMinor(1500, 'BHD');   // 1.500 BHD (three-decimal currency)
```

## The currency lock

A coupon with a non-null currency only applies to prices in that currency. A coupon must be locked when it is Fixed, or when it has a minimum\_spend or max\_discount — both are stored as Money sharing the coupon’s currency column. Percentage and free-shipping coupons without a minimum spend or cap may stay unlocked and apply to any currency; the discount is then computed in the price’s currency.

```php
$coupon->currency;                 // ?Currency — null = any currency, or the lock
$coupon->minimum_spend;            // ?Money    — null = no minimum
$coupon->max_discount;             // ?Money    — null = uncapped

$coupon->appliesToCurrency($price);   // bool — unlocked, or locked to $price's currency
$coupon->meetsMinimumSpend($price);   // bool — no minimum, or $price >= minimum_spend
```

- CreateCouponAction enforces the lock: a Fixed coupon without a currency throws InvalidCouponDefinition.
- A minimum spend or cap in another currency than the lock throws money’s CurrencyMismatch.
- A percentage is stored as whole basis points (0.01 %): CreateCouponData::percentage('12.5') works, '12.345' throws money’s RoundingNecessary.
- A Fixed row written around the action without a currency is refused when it’s used — Coupon::discount() throws InvalidCouponDefinition.

## Filling a model directly

If you write coupon attributes yourself instead of going through CreateCouponAction, set currency before minimum\_spend and max\_discount: money’s cast refuses to re-denominate a currency column that already holds a different code. Writing around the action also skips its validation, so prefer CreateCouponData where you can.

```php
use RoundlyConsulting\Coupons\Enums\DiscountType;
use RoundlyConsulting\Coupons\Models\Coupon;
use RoundlyConsulting\Money\Money;

// currency first: minimum_spend and max_discount share that column.
$coupon = new Coupon([
    'code' => 'SPRING10',
    'type' => DiscountType::Percentage,
    'value' => 1000,                                // 10 %
    'currency' => 'EUR',
    'minimum_spend' => Money::ofMinor(2000, 'EUR'),
]);

$coupon->save();
```

## Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

[More ways to support, including crypto](https://roundly-consulting.com/support-us.md)

By donating, you agree to our [donation terms](https://roundly-consulting.com/donation-terms.md).

[Support our open source work (opens in a new tab)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Join us on Patreon (opens in a new tab)](https://www.patreon.com/cw/roundly)

## Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.

[Get a quote in 48 hours](https://roundly-consulting.com/contact.md) [Browse all packages](https://roundly-consulting.com/open-source/docs/coupons-for-laravel.md)
