From 49387e79232dba051788339acbf7a73bfa6adb4c Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sat, 7 Mar 2026 13:13:14 +0700 Subject: [PATCH] refactor: Improve quantity and monetary value handling in DelayedGoodForm and DelayedGoodsTable, enhancing state management and formatting for better user experience. --- .../DelayedGoods/Schemas/DelayedGoodForm.php | 82 +++++++++++++------ .../DelayedGoods/Tables/DelayedGoodsTable.php | 21 ++--- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/app/Filament/Resources/DelayedGoods/Schemas/DelayedGoodForm.php b/app/Filament/Resources/DelayedGoods/Schemas/DelayedGoodForm.php index 088a7b3..1e645dd 100644 --- a/app/Filament/Resources/DelayedGoods/Schemas/DelayedGoodForm.php +++ b/app/Filament/Resources/DelayedGoods/Schemas/DelayedGoodForm.php @@ -14,16 +14,47 @@ class DelayedGoodForm { public static function configure(Schema $schema): Schema { - $recalculateTotal = function (callable $get, callable $set): void { - $quantity = (int) str()->replace('.', '', (string) ($get('quantity') ?? 0)); - $unitPrice = (int) str()->replace('.', '', (string) ($get('unit_price') ?? 0)); + $unmaskQty = function ($state) { + if (blank($state)) { + return 0; + } + + if (is_int($state) || is_float($state)) { + return $state; + } + + return (float) str($state) + ->replace(',', '.') + ->toString(); + }; + + $unmaskMoney = function ($state) { + if (blank($state)) { + return 0; + } + + if (is_int($state) || is_float($state)) { + return $state; + } + + return (float) str($state) + ->replace('.', '') + ->replace(',', '.') + ->toString(); + }; + + $recalculateTotal = function (callable $get, callable $set) use ($unmaskMoney, $unmaskQty): void { + $quantity = $unmaskQty($get('quantity')); + $unitPrice = $unmaskMoney($get('unit_price')); + $totalAmount = $quantity * $unitPrice; + $set('total_amount', number_format($totalAmount, 0, ',', '.')); }; - $recalculateRemaining = function (callable $get, callable $set): void { - $paidAmount = (int) str()->replace('.', '', (string) ($get('paid_amount') ?? 0)); - $totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); + $recalculateRemaining = function (callable $get, callable $set) use ($unmaskMoney): void { + $paidAmount = $unmaskMoney($get('paid_amount')); + $totalAmount = $unmaskMoney($get('total_amount')); $remaining = max(0, $totalAmount - $paidAmount); @@ -61,8 +92,9 @@ public static function configure(Schema $schema): Schema $recalculateTotal($get, $set); $recalculateRemaining($get, $set); }) - ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) - ->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))), + ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 2) + ->formatStateUsing(fn($state) => $state === null ? null : (float) $state) + ->dehydrateStateUsing($unmaskQty), TextInput::make('unit_price') ->label('Harga per Satuan') @@ -72,7 +104,7 @@ public static function configure(Schema $schema): Schema ->required() ->live() ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) - ->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))) + ->dehydrateStateUsing($unmaskMoney) ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateTotal, $recalculateRemaining): void { $recalculateTotal($get, $set); $recalculateRemaining($get, $set); @@ -97,9 +129,9 @@ public static function configure(Schema $schema): Schema ->required() ->live() ->formatStateUsing( - fn ($state) => number_format((int) ($state ?? 0), 0, ',', '.') + fn($state) => number_format((float) ($state ?? 0), 0, ',', '.') ) - ->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))), + ->dehydrateStateUsing($unmaskMoney), TextInput::make('paid_amount') ->label('Jumlah yang Sudah Dibayar (DP)') @@ -109,10 +141,10 @@ public static function configure(Schema $schema): Schema ->required() ->live() ->prefix('Rp') - ->readOnly(fn (callable $get) => $get('is_paid')) - ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining): void { - $paidAmount = (int) str()->replace('.', '', (string) ($state ?? 0)); - $totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); + ->readOnly(fn(callable $get) => $get('is_paid')) + ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void { + $paidAmount = $unmaskMoney($state); + $totalAmount = $unmaskMoney($get('total_amount')); $recalculateRemaining($get, $set); @@ -129,7 +161,7 @@ public static function configure(Schema $schema): Schema } }) ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) - ->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))), + ->dehydrateStateUsing($unmaskMoney), TextInput::make('remaining_amount') ->label('Sisa Pembayaran') @@ -138,9 +170,9 @@ public static function configure(Schema $schema): Schema ->prefix('Rp') ->default(0) ->live() - ->formatStateUsing(function ($state, callable $get) { - $paidAmount = (int) str()->replace('.', '', (string) ($get('paid_amount') ?? 0)); - $totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); + ->formatStateUsing(function ($state, callable $get) use ($unmaskMoney) { + $paidAmount = $unmaskMoney($get('paid_amount')); + $totalAmount = $unmaskMoney($get('total_amount')); $remaining = max(0, $totalAmount - $paidAmount); return number_format($remaining, 0, ',', '.'); @@ -151,11 +183,11 @@ public static function configure(Schema $schema): Schema ->label('Lunas') ->default(false) ->live() - ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining): void { - $totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); + ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void { + $totalAmount = $unmaskMoney($get('total_amount')); if ($state) { - $set('paid_amount', $totalAmount); + $set('paid_amount', number_format($totalAmount, 0, ',', '.')); if (! $get('payment_date')) { $set('payment_date', now()); @@ -172,9 +204,9 @@ public static function configure(Schema $schema): Schema ->label('Tanggal Pembayaran Lunas') ->native(false) ->displayFormat('l, d F Y') - ->visible(function (callable $get) { - $paidAmount = (int) str()->replace('.', '', (string) ($get('paid_amount') ?? 0)); - $totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); + ->visible(function (callable $get) use ($unmaskMoney) { + $paidAmount = $unmaskMoney($get('paid_amount')); + $totalAmount = $unmaskMoney($get('total_amount')); return $paidAmount >= $totalAmount && $totalAmount > 0; }), diff --git a/app/Filament/Resources/DelayedGoods/Tables/DelayedGoodsTable.php b/app/Filament/Resources/DelayedGoods/Tables/DelayedGoodsTable.php index 67bd39d..c84852b 100644 --- a/app/Filament/Resources/DelayedGoods/Tables/DelayedGoodsTable.php +++ b/app/Filament/Resources/DelayedGoods/Tables/DelayedGoodsTable.php @@ -36,8 +36,9 @@ public static function configure(Table $table): Table TextColumn::make('quantity') ->label('Jumlah') - ->suffix(fn ($record) => ' '.$record->unit?->alias) - ->numeric() + ->getStateUsing(function ($record) { + return str_replace('.', ',', (float) $record->quantity) . " {$record->unit?->alias}"; + }) ->sortable(), TextColumn::make('unit_price') @@ -54,14 +55,14 @@ public static function configure(Table $table): Table ->label('Sudah Dibayar') ->money('IDR', decimalPlaces: 0) ->sortable() - ->color(fn ($record) => $record->paid_amount >= $record->total_amount ? 'success' : 'warning'), + ->color(fn($record) => $record->paid_amount >= $record->total_amount ? 'success' : 'warning'), TextColumn::make('remaining_amount') ->label('Sisa') - ->getStateUsing(fn ($record) => max(0, $record->total_amount - $record->paid_amount)) + ->getStateUsing(fn($record) => max(0, $record->total_amount - $record->paid_amount)) ->money('IDR', decimalPlaces: 0) ->sortable() - ->color(fn ($record) => $record->paid_amount >= $record->total_amount ? 'success' : 'danger'), + ->color(fn($record) => $record->paid_amount >= $record->total_amount ? 'success' : 'danger'), IconColumn::make('is_paid') ->label('Status') @@ -86,24 +87,24 @@ public static function configure(Table $table): Table ->filters([ TrashedFilter::make() ->native(false) - ->visible(fn (): bool => auth()->user()->hasRole(RoleEnum::DEVELOPER)), + ->visible(fn(): bool => auth()->user()->hasRole(RoleEnum::DEVELOPER)), ]) ->recordActions([ Action::make('pelunasan') ->label('Pelunasan') ->icon(Heroicon::CurrencyDollar) ->color('success') - ->visible(fn ($record) => ! $record->is_paid) + ->visible(fn($record) => ! $record->is_paid) ->schema([ TextInput::make('amount') ->label('Jumlah yang dibayar') ->required() - ->default(fn ($record) => max(0, $record->total_amount - $record->paid_amount)) - ->helperText(fn ($record) => 'sisa: Rp '.number_format(max(0, $record->total_amount - $record->paid_amount), 0, ',', '.')) + ->default(fn($record) => max(0, $record->total_amount - $record->paid_amount)) + ->helperText(fn($record) => 'sisa: Rp ' . number_format(max(0, $record->total_amount - $record->paid_amount), 0, ',', '.')) ->prefix('Rp') ->live() ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) - ->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))), + ->dehydrateStateUsing(fn($state) => (float) str()->replace(',', '.', str()->replace('.', '', (string) ($state ?? 0)))), ]) ->requiresConfirmation() ->action(function (array $data, $record) {