pelmered / filament-money-field

Money field powered by Money PHP
MIT License
61 stars 21 forks source link

Set 4 Decimal points to be saved in the Database #61

Open hizmarck opened 1 month ago

hizmarck commented 1 month ago

Describe the bug I have the next use case, which is to save 4 decimal digits:

Steps To Reproduce

MoneyInput::make('total_cents')
                            ->decimals(4)

.env

MONEY_DEFAULT_LOCALE=es_MX
MONEY_DEFAULT_CURRENCY=MXN
MONEY_DECIMAL_DIGITS=4

composer.json

"php": "^8.2",
"laravel/framework": "^11.9",
"filament/filament": "^3.2",
"pelmered/filament-money-field": "^1.4",

If I insert this value = 19.5455, the saved one is 19.5500

Expected behavior and actual behavior Let the MoneyInput save the configured decimal digits.

Additional context I debugged the code a little and found that the MoneyFormatter use the $moneyParser = new IntlLocalizedDecimalParser($numberFormatter, new ISOCurrencies);

in which we have 2 minor units:

'MXN' =>
  array (
    'alphabeticCode' => 'MXN',
    'currency' => 'Mexican Peso',
    'minorUnit' => 2,
    'numericCode' => 484,
  ),

I can understand that for Money calculations this configuration is correct and that at the end we need to round the final changes, so maybe this is not a bug, but for my use case is almost impossible to find a solution, ty very much.

pelmered commented 3 weeks ago

Thanks for the report! Sorry for the late reply. I've been very busy the last month.

I was able to reproduce this. I looks like the number formatted gets properly configured with the MONEY_DECIMAL_DIGITS var, but IntlLocalizedDecimalParser does not respect that.

The problem is in IntlLocalizedDecimalParser as you said where it does not allow for more decimals then the minor unit for that currency. The only solution I can think of to fix this would be to allow that you inject your own Decimal parser that implements Money\MoneyParser and replaces IntlLocalizedDecimalParser.

Is that something you would want?

hizmarck commented 2 weeks ago

Hi @pelmered, ty for your response. That sure will work for me.

I also was thinking of a way only to inject the currencies:

new CurrencyList([ 'MXN' => 4, // minor unit pairs 'USD' => 2 // minor unit pairs ])

instead of the ISOCurrencies.

new IntlLocalizedDecimalParser($numberFormatter, new ISOCurrencies);

But, reading your response, I can see better control if we can implement our own Money\MoneyParser.

Regards.