mirror of
https://github.com/archtechx/money.git
synced 2025-12-12 03:14:03 +00:00
feature: money instance creation from a formatted string
This commit is contained in:
parent
8bdf0d1a2b
commit
38c6326a4d
4 changed files with 53 additions and 2 deletions
20
README.md
20
README.md
|
|
@ -143,7 +143,7 @@ $money->decimals(); // 100.0
|
||||||
|
|
||||||
### Formatting money
|
### Formatting money
|
||||||
|
|
||||||
You can format money using the `->formatted()` method:
|
You can format money using the `->formatted()` method. It takes [display decimals](#display-decimals) into consideration.
|
||||||
|
|
||||||
```php
|
```php
|
||||||
$money = Money::fromDecimal(40.25, USD::class);
|
$money = Money::fromDecimal(40.25, USD::class);
|
||||||
|
|
@ -166,6 +166,22 @@ $money = Money::fromDecimal(40.25, USD::class);
|
||||||
$money->formatted(['decimalSeparator' => ',', 'prefix' => '$ ', 'suffix' => ' USD']);
|
$money->formatted(['decimalSeparator' => ',', 'prefix' => '$ ', 'suffix' => ' USD']);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
There is also a `->rawFormatted()` if you wish to use [math decimals](#math-decimals) instead of [display decimals](#display-decimals).
|
||||||
|
```php
|
||||||
|
$money = Money::new(123456, CZK::class);
|
||||||
|
$money->rawFormatted(); // 1 235,56 Kč
|
||||||
|
```
|
||||||
|
|
||||||
|
And converting the formatted value back to the Money instance is also possible:
|
||||||
|
```php
|
||||||
|
$money = money(1000);
|
||||||
|
$formatted = $money->formatted(); // $10.00
|
||||||
|
$fromFormatted = Money::fromFormatted($formatted);
|
||||||
|
$fromFormatted->is($money); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: `fromFormatted()` misses the cents if the [math decimals](#math-decimals) are greater than [display decimals](#display-decimals).
|
||||||
|
|
||||||
### Rounding money
|
### Rounding money
|
||||||
|
|
||||||
Some currencies, such as the Czech Crown (CZK), generally display final prices in full crowns, but use cents for the intermediate math operations. For example:
|
Some currencies, such as the Czech Crown (CZK), generally display final prices in full crowns, but use cents for the intermediate math operations. For example:
|
||||||
|
|
@ -414,7 +430,7 @@ For the Czech Crown (CZK), the display decimals will be `0`, but the math decima
|
||||||
|
|
||||||
For the inverse of what was just explained above, you can use the `rawFormatted()` method. This returns the formatted value, **but uses the math decimals for the display decimals**. Meaning, the value in the example above will be displayed including cents:
|
For the inverse of what was just explained above, you can use the `rawFormatted()` method. This returns the formatted value, **but uses the math decimals for the display decimals**. Meaning, the value in the example above will be displayed including cents:
|
||||||
```php
|
```php
|
||||||
money(123456, new CZK)->rawFormatted(); // 1 235,56 Kč
|
money(123456, new CZK)->rawFormatted(); // 1 234,56 Kč
|
||||||
```
|
```
|
||||||
|
|
||||||
This is mostly useful for currencies like the Czech Crown which generally don't use cents, but **can** use them in specific cases.
|
This is mostly useful for currencies like the Czech Crown which generally don't use cents, but **can** use them in specific cases.
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,14 @@ final class Money implements JsonSerializable, Arrayable, Wireable
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Create a Money instance from a formatted string. */
|
||||||
|
public static function fromFormatted(string $formatted, Currency|string $currency = null, mixed ...$overrides): self
|
||||||
|
{
|
||||||
|
$decimal = PriceFormatter::resolve($formatted, currency($currency), variadic_array($overrides));
|
||||||
|
|
||||||
|
return static::fromDecimal($decimal, currency($currency));
|
||||||
|
}
|
||||||
|
|
||||||
/** Get the string representation of the Money instance. */
|
/** Get the string representation of the Money instance. */
|
||||||
public function __toString(): string
|
public function __toString(): string
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,19 @@ class PriceFormatter
|
||||||
|
|
||||||
return $currency->prefix() . $decimal . $currency->suffix();
|
return $currency->prefix() . $decimal . $currency->suffix();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Extract the decimal from the formatter string as per the currency's specifications. */
|
||||||
|
public static function resolve(string $formatted, Currency $currency, array $overrides = []): float
|
||||||
|
{
|
||||||
|
$currency = Currency::fromArray(
|
||||||
|
array_merge(currency($currency)->toArray(), $overrides)
|
||||||
|
);
|
||||||
|
|
||||||
|
$formatted = ltrim($formatted, $currency->prefix());
|
||||||
|
$formatted = rtrim($formatted, $currency->suffix());
|
||||||
|
|
||||||
|
$removeNonDigits = preg_replace('/[^\d'.preg_quote($currency->decimalSeparator()).']/', '', $formatted);
|
||||||
|
|
||||||
|
return (float) str_replace($currency->decimalSeparator(), '.', $removeNonDigits);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,18 @@ test('money can be formatted without rounding', function () {
|
||||||
)->toBe('10,34 Kč');
|
)->toBe('10,34 Kč');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('money can be created from a formatted string', function () {
|
||||||
|
$money = Money::fromFormatted('$10.40');
|
||||||
|
expect($money->value())->toBe(1040);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('money can be created from a raw formatted string', function () {
|
||||||
|
currencies()->add([CZK::class]);
|
||||||
|
|
||||||
|
$money = Money::fromFormatted('1 234,56 Kč', CZK::class);
|
||||||
|
expect($money->value())->toBe(123456);
|
||||||
|
});
|
||||||
|
|
||||||
test('converting money to a string returns the formatted string', function () {
|
test('converting money to a string returns the formatted string', function () {
|
||||||
expect(
|
expect(
|
||||||
(string) Money::fromDecimal(10.00, USD::class)
|
(string) Money::fromDecimal(10.00, USD::class)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue