mirror of
https://github.com/archtechx/money.git
synced 2025-12-12 11:24:03 +00:00
feat: extract currency from the formatted string
This commit is contained in:
parent
fa337d29b4
commit
93aeb2c300
4 changed files with 57 additions and 3 deletions
15
README.md
15
README.md
|
|
@ -172,7 +172,7 @@ $money = Money::new(123456, CZK::class);
|
||||||
$money->rawFormatted(); // 1 235,56 Kč
|
$money->rawFormatted(); // 1 235,56 Kč
|
||||||
```
|
```
|
||||||
|
|
||||||
And converting the formatted value back to the Money instance is also possible:
|
And converting the formatted value back to the Money instance is also possible. The package tries to extract the currency from the provided string.
|
||||||
```php
|
```php
|
||||||
$money = money(1000);
|
$money = money(1000);
|
||||||
$formatted = $money->formatted(); // $10.00
|
$formatted = $money->formatted(); // $10.00
|
||||||
|
|
@ -180,7 +180,18 @@ $fromFormatted = Money::fromFormatted($formatted);
|
||||||
$fromFormatted->is($money); // true
|
$fromFormatted->is($money); // true
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: `fromFormatted()` misses the cents if the [math decimals](#math-decimals) are greater than [display decimals](#display-decimals).
|
Optional overrides for the [currency specification](#currency-logic) are accepted too.
|
||||||
|
```php
|
||||||
|
$money = money(1000);
|
||||||
|
$formatted = $money->formatted(); // $10.00
|
||||||
|
$fromFormatted = Money::fromFormatted($formatted, USD::class, ['decimalSeparator' => ',', 'prefix' => '$ ', 'suffix' => ' USD']);
|
||||||
|
$fromFormatted->is($money); // true
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
1) If currency is not specified and none of the currencies match the prefix and suffix, an exception will be thrown.
|
||||||
|
2) If currency is not specified and multiple currencies use the same prefix and suffix, an exception will be thrown.
|
||||||
|
3) `fromFormatted()` misses the cents if the [math decimals](#math-decimals) are greater than [display decimals](#display-decimals).
|
||||||
|
|
||||||
### Rounding money
|
### Rounding money
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,10 @@ final class Money implements JsonSerializable, Arrayable, Wireable
|
||||||
/** Create a Money instance from a formatted string. */
|
/** Create a Money instance from a formatted string. */
|
||||||
public static function fromFormatted(string $formatted, Currency|string $currency = null, mixed ...$overrides): self
|
public static function fromFormatted(string $formatted, Currency|string $currency = null, mixed ...$overrides): self
|
||||||
{
|
{
|
||||||
|
$currency = isset($currency)
|
||||||
|
? currency($currency)
|
||||||
|
: PriceFormatter::extractCurrency($formatted);
|
||||||
|
|
||||||
$decimal = PriceFormatter::resolve($formatted, currency($currency), variadic_array($overrides));
|
$decimal = PriceFormatter::resolve($formatted, currency($currency), variadic_array($overrides));
|
||||||
|
|
||||||
return static::fromDecimal($decimal, currency($currency));
|
return static::fromDecimal($decimal, currency($currency));
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ 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. */
|
/** Extract the decimal from the formatted string as per the currency's specifications. */
|
||||||
public static function resolve(string $formatted, Currency $currency, array $overrides = []): float
|
public static function resolve(string $formatted, Currency $currency, array $overrides = []): float
|
||||||
{
|
{
|
||||||
$currency = Currency::fromArray(
|
$currency = Currency::fromArray(
|
||||||
|
|
@ -41,4 +41,25 @@ class PriceFormatter
|
||||||
|
|
||||||
return (float) str_replace($currency->decimalSeparator(), '.', $removeNonDigits);
|
return (float) str_replace($currency->decimalSeparator(), '.', $removeNonDigits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Tries to extract the currency from the formatted string. */
|
||||||
|
public static function extractCurrency(string $formatted): Currency
|
||||||
|
{
|
||||||
|
$possibleCurrency = null;
|
||||||
|
|
||||||
|
foreach (currencies()->all() as $currency) {
|
||||||
|
if (
|
||||||
|
str_starts_with($formatted, $currency->prefix())
|
||||||
|
&& str_ends_with($formatted, $currency->suffix())
|
||||||
|
) {
|
||||||
|
if ($possibleCurrency) {
|
||||||
|
throw new \Exception('Multiple currencies are using the same prefix and suffix. Please specify the currency of the formatted string.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$possibleCurrency = $currency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $possibleCurrency ?? throw new \Exception('None of the currencies are using the prefix and suffix that would match with the formatted string.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,6 +159,24 @@ test('money can be created from a raw formatted string', function () {
|
||||||
expect($money->value())->toBe(123456);
|
expect($money->value())->toBe(123456);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('an exception is thrown if none of the currencies match the prefix and suffix', function () {
|
||||||
|
$money = money(1000);
|
||||||
|
$formatted = $money->formatted();
|
||||||
|
|
||||||
|
currencies()->remove(USD::class);
|
||||||
|
|
||||||
|
pest()->expectException(\Exception::class);
|
||||||
|
Money::fromFormatted($formatted);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('an exception is thrown if multiple currencies are using the same prefix and suffix', function () {
|
||||||
|
currencies()->add(['code' => 'USD2', 'name' => 'USD2', 'prefix' => '$']);
|
||||||
|
$money = money(1000);
|
||||||
|
|
||||||
|
pest()->expectException(\Exception::class);
|
||||||
|
Money::fromFormatted($money->formatted());
|
||||||
|
});
|
||||||
|
|
||||||
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