Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix to MoneyInput #11

Merged
merged 4 commits into from
Feb 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 45 additions & 14 deletions src/Forms/Components/MoneyInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,81 @@ protected function setUp(): void
{
parent::setUp();

$this->inputMode('decimal');
$this->step(0.01);
$this->minValue = 0;

$this->formatStateUsing(function (MoneyInput $component, $state): ?string {

$currency = $component->getCurrency()->getCode();
$state = MoneyFormatter::parseDecimal($state, $currency, $component->getLocale());

$this->prepare($component);

$currency = $component->getCurrency();
$locale = $component->getLocale();

if (is_null($state)) {
return '';
}
if(!is_numeric($state)) {
return $state;
}

return MoneyFormatter::decimalToMoneyString($state / 100, $component->getLocale());
return MoneyFormatter::formatAsDecimal($state, $currency, $locale);
});

$this->dehydrateStateUsing(function (MoneyInput $component, $state): string {

$this->prepare($component);

$currency = $component->getCurrency()->getCode();
$state = MoneyFormatter::parseDecimal($state, $currency, $component->getLocale());

$this->prepare($component);

return $state;
});
}

protected function prepare(MoneyInput $component): void
{
$formattingRules = MoneyFormatter::getFormattingRules($component->getLocale());

$this->prefix($formattingRules->currencySymbol);

if (config('filament-money-field.use_input_mask')) {
$this->mask(RawJs::make('$money($input, \'' . $formattingRules->decimalSeparator . '\', \'' . $formattingRules->groupingSeparator . '\', ' . $formattingRules->fractionDigits . ')'));
}
}

public function minValue(mixed $min): static
{
$this->rule(static function (MoneyInput $component, mixed $state) use ($min) {
return function (string $attribute, mixed $value, \Closure $fail) use ($component, $state, $min) {

$value = MoneyFormatter::parseDecimal(
$state,
$component->getCurrency()->getCode(),
$component->getLocale()
);

if ($value < $min) {
$fail('The :attribute must be greater than or equal to ' . $min . '.');
}
};
});

return $this;
}

public function maxValue(mixed $max): static
{
$this->rule(static function (MoneyInput $component, mixed $state) use ($max) {
return function (string $attribute, mixed $value, \Closure $fail) use ($component, $state, $max) {

$value = MoneyFormatter::parseDecimal(
$state,
$component->getCurrency()->getCode(),
$component->getLocale()
);

if ($value > $max) {
$fail('The :attribute must be less than or equal to ' . $max . '.');
}
};
});

$this->stripCharacters($formattingRules->groupingSeparator);
// OR
$this->stripCharacters([',', '.', ' ',]);
return $this;
}
}
13 changes: 13 additions & 0 deletions src/MoneyFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ public static function format($value, $currency, $locale, $monetarySeparator = n
return $moneyFormatter->format($money);
}

public static function formatAsDecimal($value, $currency, $locale): string
{
if (is_null($value) || $value === '') {
return '';
}

$numberFormatter = self::getNumberFormatter($locale, \NumberFormatter::DECIMAL);
$moneyFormatter = new IntlMoneyFormatter($numberFormatter, new ISOCurrencies());

$money = new Money($value, $currency);
return $moneyFormatter->format($money); // outputs 1.000,00
}

public static function parseDecimal($moneyString, $currency, $locale): string
{
if (is_null($moneyString) || $moneyString === '') {
Expand Down
106 changes: 82 additions & 24 deletions tests/MoneyFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
namespace Pelmered\FilamentMoneyField\Tests;
use Money\Currency;
use Pelmered\FilamentMoneyField\MoneyFormatter;
use PHPUnit\Framework;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\DataProvider;

#[CoversClass(MoneyFormatter::class)]
final class MoneyFormatterTest extends TestCase
{
public static function provideMoneyDataSEK(): array
Expand Down Expand Up @@ -33,6 +35,32 @@ public static function provideMoneyDataSEK(): array
];
}

public static function provideDecimalMoneyDataSEK(): array
{
return [
'thousands' => [
1000000,
'10 000,00',
],
'decimals' => [
10045,
'100,45',
],
'millions' => [
123456789,
'1 234 567,89',
],
'empty_string' => [
'',
'',
],
'null' => [
null,
'',
],
];
}

public static function provideMoneyDataUSD(): array
{
return [
Expand All @@ -59,6 +87,32 @@ public static function provideMoneyDataUSD(): array
];
}

public static function provideDecimalMoneyDataUSD(): array
{
return [
'thousands' => [
1000000,
'10,000.00',
],
'decimals' => [
10045,
'100.45',
],
'millions' => [
123456789,
'1,234,567.89',
],
'empty_string' => [
'',
'',
],
'null' => [
null,
'',
],
];
}

public static function provideDecimalDataSEK(): array
{
return [
Expand Down Expand Up @@ -110,13 +164,17 @@ public static function provideDecimalDataUSD(): array
],
];
}

#[DataProvider('provideMoneyDataUSD')]
public function testMoneyFormatterUSD(mixed $input, string $expectedOutput)
{
self::assertSame(
static::replaceNonBreakingSpaces($expectedOutput),
MoneyFormatter::format($input, new Currency('USD'), 'en_US')
);
}


/**
* @covers MoneyFormatter::format
* @dataProvider provideMoneyDataSEK
*/
#[Framework\CoversClass(MoneyFormatter::class)]
#[DataProvider('provideMoneyDataSEK')]
public function testMoneyFormatterSEK(mixed $input, string $expectedOutput)
{
self::assertSame(
Expand All @@ -125,24 +183,28 @@ public function testMoneyFormatterSEK(mixed $input, string $expectedOutput)
);
}

/**
* @covers MoneyFormatter::format
* @dataProvider provideMoneyDataUSD
*/
#[Framework\CoversClass(MoneyFormatter::class)]
public function testMoneyFormatterUSD(mixed $input, string $expectedOutput)
#[DataProvider('provideDecimalMoneyDataUSD')]
//#[CoversClass(MoneyFormatter::class)]
public function testMoneyDecimalFormatterUSD(mixed $input, string $expectedOutput)
{
self::assertSame(
static::replaceNonBreakingSpaces($expectedOutput),
MoneyFormatter::format($input, new Currency('USD'), 'en_US')
MoneyFormatter::formatAsDecimal($input, new Currency('USD'), 'en_US')
);
}

/**
* @covers MoneyFormatter::parseDecimal
* @dataProvider provideDecimalDataSEK
*/
#[Framework\CoversClass(MoneyFormatter::class)]
#[DataProvider('provideDecimalMoneyDataSEK')]
//#[CoversClass(MoneyFormatter::class)]
public function testMoneyDecimalFormatterSEK(mixed $input, string $expectedOutput)
{
self::assertSame(
static::replaceNonBreakingSpaces($expectedOutput),
MoneyFormatter::formatAsDecimal($input, new Currency('SEK'), 'sv_SE')
);
}

#[DataProvider('provideDecimalDataSEK')]
//#[CoversClass(MoneyFormatter::class)]
public function testMoneyParserDecimalSEK(mixed $input, string $expectedOutput)
{
self::assertSame(
Expand All @@ -151,11 +213,7 @@ public function testMoneyParserDecimalSEK(mixed $input, string $expectedOutput)
);
}

/**
* @covers MoneyFormatter::parseDecimal
* @dataProvider provideDecimalDataUSD
*/
#[Framework\CoversClass(MoneyFormatter::class)]
#[DataProvider('provideDecimalDataUSD')]
public function testMoneyParserDecimalUSD(mixed $input, string $expectedOutput)
{
self::assertSame(
Expand Down
Loading