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) use ($unmaskMoney): void { $paidAmount = $unmaskMoney($get('paid_amount')); $totalAmount = $unmaskMoney($get('total_amount')); $remaining = max(0, $totalAmount - $paidAmount); $set('remaining_amount', number_format($remaining, 0, ',', '.')); }; return $schema->components([ Grid::make(2) ->schema([ DatePicker::make('stored_date') ->label('Tanggal Penyimpanan') ->default(now()) ->required() ->native(false) ->displayFormat('l, d F Y'), Select::make('customer_id') ->label('Pelanggan') ->relationship('customer', 'name') ->searchable() ->preload() ->native(false) ->required(), ]), Grid::make(3) ->schema([ TextInput::make('quantity') ->label('Jumlah Barang') ->placeholder('0') ->autocomplete(false) ->required() ->live() ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateTotal, $recalculateRemaining): void { $recalculateTotal($get, $set); $recalculateRemaining($get, $set); }) ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 2) ->formatStateUsing(fn ($state) => $state === null ? null : (float) $state) ->dehydrateStateUsing($unmaskQty), TextInput::make('unit_price') ->label('Harga per Satuan') ->placeholder('0') ->autocomplete(false) ->prefix('Rp') ->required() ->live() ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) ->dehydrateStateUsing($unmaskMoney) ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateTotal, $recalculateRemaining): void { $recalculateTotal($get, $set); $recalculateRemaining($get, $set); }), Select::make('unit_id') ->label('Satuan') ->relationship('unit', 'alias') ->searchable() ->preload() ->native(false) ->required(), ]), Grid::make(3) ->schema([ TextInput::make('total_amount') ->label('Total') ->placeholder('0') ->readOnly() ->prefix('Rp') ->required() ->live() ->formatStateUsing( fn ($state) => number_format((float) ($state ?? 0), 0, ',', '.') ) ->dehydrateStateUsing($unmaskMoney), TextInput::make('paid_amount') ->label('Jumlah yang Sudah Dibayar (DP)') ->placeholder('0') ->default(0) ->autocomplete(false) ->required() ->live() ->prefix('Rp') ->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); if (! $get('is_paid')) { $set('is_paid', $paidAmount >= $totalAmount && $totalAmount > 0); } if ($paidAmount >= $totalAmount && $totalAmount > 0 && ! $get('payment_date')) { $set('payment_date', now()); } if ($paidAmount < $totalAmount) { $set('payment_date', null); } }) ->currencyMask(thousandSeparator: '.', decimalSeparator: ',', precision: 0) ->dehydrateStateUsing($unmaskMoney), TextInput::make('remaining_amount') ->label('Sisa Pembayaran') ->placeholder('0') ->readOnly() ->prefix('Rp') ->default(0) ->live() ->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, ',', '.'); }) ->dehydrated(false), Toggle::make('is_paid') ->label('Lunas') ->default(false) ->live() ->afterStateUpdated(function ($state, callable $get, callable $set) use ($recalculateRemaining, $unmaskMoney): void { $totalAmount = $unmaskMoney($get('total_amount')); if ($state) { $set('paid_amount', number_format($totalAmount, 0, ',', '.')); if (! $get('payment_date')) { $set('payment_date', now()); } } else { $set('paid_amount', 0); $set('payment_date', null); } $recalculateRemaining($get, $set); }), DatePicker::make('payment_date') ->label('Tanggal Pembayaran Lunas') ->native(false) ->displayFormat('l, d F Y') ->visible(function (callable $get) use ($unmaskMoney) { $paidAmount = $unmaskMoney($get('paid_amount')); $totalAmount = $unmaskMoney($get('total_amount')); return $paidAmount >= $totalAmount && $totalAmount > 0; }), ]), Textarea::make('notes') ->label('Catatan') ->placeholder('...') ->autocomplete(false) ->columnSpanFull(), ]) ->columns(1); } }