refactor: Improve quantity and monetary value handling in DelayedGoodForm and DelayedGoodsTable, enhancing state management and formatting for better user experience.

This commit is contained in:
Yoga Pangestu 2026-03-07 13:13:14 +07:00
parent 48b182cd4b
commit 49387e7923
2 changed files with 68 additions and 35 deletions

View File

@ -14,16 +14,47 @@ class DelayedGoodForm
{ {
public static function configure(Schema $schema): Schema public static function configure(Schema $schema): Schema
{ {
$recalculateTotal = function (callable $get, callable $set): void { $unmaskQty = function ($state) {
$quantity = (int) str()->replace('.', '', (string) ($get('quantity') ?? 0)); if (blank($state)) {
$unitPrice = (int) str()->replace('.', '', (string) ($get('unit_price') ?? 0)); 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; $totalAmount = $quantity * $unitPrice;
$set('total_amount', number_format($totalAmount, 0, ',', '.')); $set('total_amount', number_format($totalAmount, 0, ',', '.'));
}; };
$recalculateRemaining = function (callable $get, callable $set): void { $recalculateRemaining = function (callable $get, callable $set) use ($unmaskMoney): void {
$paidAmount = (int) str()->replace('.', '', (string) ($get('paid_amount') ?? 0)); $paidAmount = $unmaskMoney($get('paid_amount'));
$totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); $totalAmount = $unmaskMoney($get('total_amount'));
$remaining = max(0, $totalAmount - $paidAmount); $remaining = max(0, $totalAmount - $paidAmount);
@ -61,8 +92,9 @@ public static function configure(Schema $schema): Schema
$recalculateTotal($get, $set); $recalculateTotal($get, $set);
$recalculateRemaining($get, $set); $recalculateRemaining($get, $set);
}) })
->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 2)
->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))), ->formatStateUsing(fn($state) => $state === null ? null : (float) $state)
->dehydrateStateUsing($unmaskQty),
TextInput::make('unit_price') TextInput::make('unit_price')
->label('Harga per Satuan') ->label('Harga per Satuan')
@ -72,7 +104,7 @@ public static function configure(Schema $schema): Schema
->required() ->required()
->live() ->live()
->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) ->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 { ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateTotal, $recalculateRemaining): void {
$recalculateTotal($get, $set); $recalculateTotal($get, $set);
$recalculateRemaining($get, $set); $recalculateRemaining($get, $set);
@ -97,9 +129,9 @@ public static function configure(Schema $schema): Schema
->required() ->required()
->live() ->live()
->formatStateUsing( ->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') TextInput::make('paid_amount')
->label('Jumlah yang Sudah Dibayar (DP)') ->label('Jumlah yang Sudah Dibayar (DP)')
@ -109,10 +141,10 @@ public static function configure(Schema $schema): Schema
->required() ->required()
->live() ->live()
->prefix('Rp') ->prefix('Rp')
->readOnly(fn (callable $get) => $get('is_paid')) ->readOnly(fn(callable $get) => $get('is_paid'))
->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining): void { ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void {
$paidAmount = (int) str()->replace('.', '', (string) ($state ?? 0)); $paidAmount = $unmaskMoney($state);
$totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); $totalAmount = $unmaskMoney($get('total_amount'));
$recalculateRemaining($get, $set); $recalculateRemaining($get, $set);
@ -129,7 +161,7 @@ public static function configure(Schema $schema): Schema
} }
}) })
->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0)
->dehydrateStateUsing(fn ($state) => (int) str()->replace('.', '', (string) ($state ?? 0))), ->dehydrateStateUsing($unmaskMoney),
TextInput::make('remaining_amount') TextInput::make('remaining_amount')
->label('Sisa Pembayaran') ->label('Sisa Pembayaran')
@ -138,9 +170,9 @@ public static function configure(Schema $schema): Schema
->prefix('Rp') ->prefix('Rp')
->default(0) ->default(0)
->live() ->live()
->formatStateUsing(function ($state, callable $get) { ->formatStateUsing(function ($state, callable $get) use ($unmaskMoney) {
$paidAmount = (int) str()->replace('.', '', (string) ($get('paid_amount') ?? 0)); $paidAmount = $unmaskMoney($get('paid_amount'));
$totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); $totalAmount = $unmaskMoney($get('total_amount'));
$remaining = max(0, $totalAmount - $paidAmount); $remaining = max(0, $totalAmount - $paidAmount);
return number_format($remaining, 0, ',', '.'); return number_format($remaining, 0, ',', '.');
@ -151,11 +183,11 @@ public static function configure(Schema $schema): Schema
->label('Lunas') ->label('Lunas')
->default(false) ->default(false)
->live() ->live()
->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining): void { ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void {
$totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); $totalAmount = $unmaskMoney($get('total_amount'));
if ($state) { if ($state) {
$set('paid_amount', $totalAmount); $set('paid_amount', number_format($totalAmount, 0, ',', '.'));
if (! $get('payment_date')) { if (! $get('payment_date')) {
$set('payment_date', now()); $set('payment_date', now());
@ -172,9 +204,9 @@ public static function configure(Schema $schema): Schema
->label('Tanggal Pembayaran Lunas') ->label('Tanggal Pembayaran Lunas')
->native(false) ->native(false)
->displayFormat('l, d F Y') ->displayFormat('l, d F Y')
->visible(function (callable $get) { ->visible(function (callable $get) use ($unmaskMoney) {
$paidAmount = (int) str()->replace('.', '', (string) ($get('paid_amount') ?? 0)); $paidAmount = $unmaskMoney($get('paid_amount'));
$totalAmount = (int) str()->replace('.', '', (string) ($get('total_amount') ?? 0)); $totalAmount = $unmaskMoney($get('total_amount'));
return $paidAmount >= $totalAmount && $totalAmount > 0; return $paidAmount >= $totalAmount && $totalAmount > 0;
}), }),

View File

@ -36,8 +36,9 @@ public static function configure(Table $table): Table
TextColumn::make('quantity') TextColumn::make('quantity')
->label('Jumlah') ->label('Jumlah')
->suffix(fn ($record) => ' '.$record->unit?->alias) ->getStateUsing(function ($record) {
->numeric() return str_replace('.', ',', (float) $record->quantity) . " {$record->unit?->alias}";
})
->sortable(), ->sortable(),
TextColumn::make('unit_price') TextColumn::make('unit_price')
@ -54,14 +55,14 @@ public static function configure(Table $table): Table
->label('Sudah Dibayar') ->label('Sudah Dibayar')
->money('IDR', decimalPlaces: 0) ->money('IDR', decimalPlaces: 0)
->sortable() ->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') TextColumn::make('remaining_amount')
->label('Sisa') ->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) ->money('IDR', decimalPlaces: 0)
->sortable() ->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') IconColumn::make('is_paid')
->label('Status') ->label('Status')
@ -86,24 +87,24 @@ public static function configure(Table $table): Table
->filters([ ->filters([
TrashedFilter::make() TrashedFilter::make()
->native(false) ->native(false)
->visible(fn (): bool => auth()->user()->hasRole(RoleEnum::DEVELOPER)), ->visible(fn(): bool => auth()->user()->hasRole(RoleEnum::DEVELOPER)),
]) ])
->recordActions([ ->recordActions([
Action::make('pelunasan') Action::make('pelunasan')
->label('Pelunasan') ->label('Pelunasan')
->icon(Heroicon::CurrencyDollar) ->icon(Heroicon::CurrencyDollar)
->color('success') ->color('success')
->visible(fn ($record) => ! $record->is_paid) ->visible(fn($record) => ! $record->is_paid)
->schema([ ->schema([
TextInput::make('amount') TextInput::make('amount')
->label('Jumlah yang dibayar') ->label('Jumlah yang dibayar')
->required() ->required()
->default(fn ($record) => max(0, $record->total_amount - $record->paid_amount)) ->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, ',', '.')) ->helperText(fn($record) => 'sisa: Rp ' . number_format(max(0, $record->total_amount - $record->paid_amount), 0, ',', '.'))
->prefix('Rp') ->prefix('Rp')
->live() ->live()
->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) ->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() ->requiresConfirmation()
->action(function (array $data, $record) { ->action(function (array $data, $record) {