refactor: streamline sales and expenses management in client resource

- Move create/edit logic from relation managers to dedicated resource pages
- Add transaction handling with proper rollback in sale create/update
- Fix expense transaction creation by using correct array access
- Set default client from query parameter in sale/expense forms
- Exclude 'type' field from balance creation to prevent errors
This commit is contained in:
Jp
2026-02-10 15:05:36 +08:00
parent 0e4da559d6
commit 0131193b8d
8 changed files with 123 additions and 426 deletions

View File

@@ -2,10 +2,16 @@
namespace App\Filament\Resources\SaleResource\Pages;
use App\Actions\Transactions\CreateTransactionAction;
use App\DataObjects\CreateTransactionDTO;
use App\Filament\Resources\SaleResource;
use App\Models\Branch;
use App\Models\Sale;
use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Pipeline;
class CreateSale extends CreateRecord
{
@@ -16,11 +22,48 @@ class CreateSale extends CreateRecord
return $this->getFormDataMutation($data);
}
protected function handleRecordCreation(array $data): Model
{
$transactions = $this->data['transactions'] ?? [];
return $this->processCreate($data, $transactions);
}
public function getFormDataMutation(array $data): array
{
return Arr::except($data, ['client', 'transactions', 'with_discount']);
}
public function processCreate(array $data, array $transactions): Model
{
try {
DB::beginTransaction();
$record = Sale::create($data);
$branch = $record->branch;
foreach ($transactions as $transaction) {
$tData = [
'branch_id' => $branch->id,
'happened_on' => $record->happened_on,
...$transaction,
];
$payload = new CreateTransactionDTO(data: $tData, transactionable: $record);
Pipeline::send(passable: $payload)->through(
[
CreateTransactionAction::class,
]
)->thenReturn();
}
DB::commit();
} catch (\Exception $exception) {
DB::rollBack();
throw new \Exception('Failed to save transactions : '.$exception->getMessage());
}
return $record;
}
protected function afterCreate(): void
{
$branch = Branch::find($this->data['branch_id']);

View File

@@ -2,9 +2,15 @@
namespace App\Filament\Resources\SaleResource\Pages;
use App\Actions\Transactions\CreateTransactionAction;
use App\DataObjects\CreateTransactionDTO;
use App\Filament\Resources\SaleResource;
use Filament\Actions;
use Filament\Resources\Pages\EditRecord;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Pipeline;
class EditSale extends EditRecord
{
@@ -16,4 +22,61 @@ class EditSale extends EditRecord
Actions\DeleteAction::make(),
];
}
protected function mutateFormDataBeforeSave(array $data): array
{
return $this->getFormDataMutation($data);
}
protected function handleRecordUpdate(Model $record, array $data): Model
{
$transactions = $this->data['transactions'] ?? [];
return $this->processUpdate($record, $data, $transactions);
}
public function getFormDataMutation(array $data): array
{
return Arr::except($data, ['client', 'transactions', 'with_discount']);
}
public function processUpdate(Model $record, array $data, array $transactions): Model
{
try {
DB::beginTransaction();
$record->update($data);
$branch = $record->branch;
// Delete existing transactions and their related ledgers/balances
$record->transactions->each(function ($transaction) {
$transaction->ledgers->each(function ($ledger) {
$ledger->balances()->delete();
$ledger->delete();
});
$transaction->delete();
});
// Create new transactions
foreach ($transactions as $transaction) {
$tData = [
'branch_id' => $branch->id,
'happened_on' => $record->happened_on,
...$transaction,
];
$payload = new CreateTransactionDTO(data: $tData, transactionable: $record);
Pipeline::send(passable: $payload)->through(
[
CreateTransactionAction::class,
]
)->thenReturn();
}
DB::commit();
} catch (\Exception $exception) {
DB::rollBack();
throw new \Exception('Failed to save transactions : '.$exception->getMessage());
}
return $record;
}
}