Merge pull request #7 from kingjaypee12/jp/sales-clean-up

Jp/sales clean up
This commit is contained in:
2026-02-16 02:03:02 +08:00
committed by GitHub
10 changed files with 218 additions and 129 deletions

View File

@@ -0,0 +1,55 @@
<?php
namespace App\Actions\Sales;
use App\Actions\Transactions\CreateRecordTransactionsAction;
use App\Commands\Sales\CreateSaleCommand;
use App\Commands\Series\CreateSeriesCommand;
use App\Models\Sale;
use Illuminate\Support\Facades\DB;
class CreateSaleAction
{
/**
* Create a new class instance.
*/
public function __construct(
private CreateSaleCommand $createSaleCommand,
private CreateSeriesCommand $createSeriesCommand,
){ }
public function __invoke(array $data, array $transactions): Sale
{
$record = $this->createSaleCommand->execute($data);
try {
DB::beginTransaction();
//create transactions for the sale
app(CreateRecordTransactionsAction::class)($record, $transactions);
$accountIds = collect($transactions)
->pluck('account_id')
->filter()
->unique()
->values()
->all();
//sync accounts to sale
app(SyncAccountsAction::class)($record, $accountIds);
//increment current_series
$this->createSeriesCommand->execute([
'branch_id' => $record->branch_id,
'series' => $record->reference_number,
]);
DB::commit();
} catch (\Exception $exception) {
DB::rollBack();
throw new \Exception('Failed to save transactions : '.$exception->getMessage());
}
return $record;
}
}

View File

@@ -0,0 +1,16 @@
<?php
namespace App\Actions\Sales;
use App\Models\Sale;
use Illuminate\Support\Facades\DB;
class SyncAccountsAction
{
public function __invoke(Sale $sale, array $accounts): void
{
DB::transaction(function () use ($sale, $accounts) {
$sale->accounts()->sync($accounts);
}, attempts: 2);
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\Actions\Transactions;
use App\DataObjects\CreateTransactionDTO;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Pipeline;
class CreateRecordTransactionsAction
{
public function __invoke(Model $record, array $transactions): void
{
foreach ($transactions as $transaction) {
$tData = [
'branch_id' => $record->branch_id,
'happened_on' => $record->happened_on,
...$transaction,
];
$payload = new CreateTransactionDTO(data: $tData, transactionable: $record);
Pipeline::send(passable: $payload)->through(
[
CreateTransactionAction::class,
]
)->thenReturn();
}
}
}

View File

@@ -0,0 +1,64 @@
<?php
namespace App\Commands\Clients;
use App\Commands\Command;
use Illuminate\Support\Facades\DB;
class GenerateBaseAccountCommand
{
/**
* Create a new class instance.
*/
public function __construct()
{
//
}
/**
* Execute the command.
*/
public function execute($client): void
{
DB::transaction(function () use ($client) {
$client->accounts()->createMany([
[
'account_type_id' => 1,
'account' => 'Cash',
'normal_balance' => 'debit',
],
[
'account_type_id' => 1,
'account' => 'Input Tax',
'normal_balance' => 'debit',
],
[
'account_type_id' => 1,
'account' => 'Creditable Withholding Tax',
'normal_balance' => 'debit',
],
[
'account_type_id' => 2,
'account' => 'Output Tax',
'normal_balance' => 'credit',
],
[
'account_type_id' => 2,
'account' => 'Payable Withholding Tax',
'normal_balance' => 'credit',
],
[
'account_type_id' => 5,
'account' => 'Vat Exempt Revenue',
'normal_balance' => 'credit',
],
[
'account_type_id' => 4,
'account' => 'Sales Discount',
'normal_balance' => 'debit',
],
]);
});
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Commands\Sales;
use App\Commands\Command;
use App\DataObjects\CreateSaleDTO;
use App\Models\Sale;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
class CreateSaleCommand implements Command
{
public function execute(array $data): Sale
{
return DB::transaction(function () use ($data, &$sale) {
$tData = new CreateSaleDTO(
reference_number: $data['current_series'],
happened_on: \Carbon\Carbon::parse($data['happened_on']),
branch_id: $data['branch_id'],
user_id: Auth::user()->id,
);
return Sale::create($tData->toArray());
});
}
}

View File

@@ -2,6 +2,7 @@
namespace App\Filament\Resources\ClientResource\RelationManagers; namespace App\Filament\Resources\ClientResource\RelationManagers;
use App\Commands\Clients\GenerateBaseAccountCommand;
use App\Filament\Exports\ClientAccountsExporter; use App\Filament\Exports\ClientAccountsExporter;
use App\Models\Account; use App\Models\Account;
use Filament\Actions\Exports\Enums\ExportFormat; use Filament\Actions\Exports\Enums\ExportFormat;
@@ -43,6 +44,20 @@ class AccountsRelationManager extends RelationManager
// //
]) ])
->headerActions([ ->headerActions([
Tables\Actions\Action::make('generate-base-accounts')
->requiresConfirmation()
->label('Generate Base Accounts')
->action(function () {
$client = $this->getOwnerRecord();
if (! $client ) {
return;
}
if($client->accounts()->count() > 0) {
return;
}
app(GenerateBaseAccountCommand::class)->execute($client);
}),
Tables\Actions\ExportAction::make('Export Accounts')->exporter(ClientAccountsExporter::class)->formats([ExportFormat::Csv]), Tables\Actions\ExportAction::make('Export Accounts')->exporter(ClientAccountsExporter::class)->formats([ExportFormat::Csv]),
Tables\Actions\CreateAction::make()->label('New Account')->icon('heroicon-o-plus')->slideOver(), Tables\Actions\CreateAction::make()->label('New Account')->icon('heroicon-o-plus')->slideOver(),
]) ])

View File

@@ -2,15 +2,13 @@
namespace App\Filament\Resources\ExpenseResource\Pages; namespace App\Filament\Resources\ExpenseResource\Pages;
use App\Actions\Transactions\CreateTransactionAction; use App\Actions\Transactions\CreateRecordTransactionsAction;
use App\DataObjects\CreateTransactionDTO;
use App\Filament\Resources\ClientResource; use App\Filament\Resources\ClientResource;
use App\Filament\Resources\ExpenseResource; use App\Filament\Resources\ExpenseResource;
use App\Models\Client; use App\Models\Client;
use Exception; use Exception;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Pipeline;
use Symfony\Component\Console\Exception\LogicException; use Symfony\Component\Console\Exception\LogicException;
class CreateExpense extends CreateRecord class CreateExpense extends CreateRecord
@@ -76,24 +74,7 @@ class CreateExpense extends CreateRecord
$transactions = $this->form->getState()['transactions'] ?? []; $transactions = $this->form->getState()['transactions'] ?? [];
try { try {
$branch = $this->getRecord()->branch; app(CreateRecordTransactionsAction::class)($this->getRecord(), $transactions);
foreach ($transactions as $transaction) {
$data = [
'branch_id' => $branch->id,
'happened_on' => $this->getRecord()->happened_on,
...$transaction,
];
$payload = new CreateTransactionDTO(data: $data, transactionable: $this->getRecord());
Pipeline::send(passable: $payload)->through(
[
CreateTransactionAction::class,
]
)->thenReturn();
}
$accountIds = collect($transactions) $accountIds = collect($transactions)
->pluck('account_id') ->pluck('account_id')

View File

@@ -2,19 +2,22 @@
namespace App\Filament\Resources\SaleResource\Pages; namespace App\Filament\Resources\SaleResource\Pages;
use App\Actions\Transactions\CreateTransactionAction; use App\Actions\Sales\CreateSaleAction;
use App\DataObjects\CreateTransactionDTO; use App\Actions\Sales\SyncAccountsAction;
use App\Actions\Transactions\CreateRecordTransactionsAction;
use App\Commands\Clients\GenerateBaseAccountCommand;
use App\Filament\Resources\ClientResource; use App\Filament\Resources\ClientResource;
use App\Filament\Resources\SaleResource; use App\Filament\Resources\SaleResource;
use App\Models\Branch; use App\Models\Branch;
use App\Models\Client; use App\Models\Client;
use App\Models\Sale; use App\Models\Sale;
use App\Services\Sales\SaleService; use App\Services\Sales\SaleService;
use Filament\Actions\Action;
use Filament\Forms\Components\Actions;
use Filament\Resources\Pages\CreateRecord; use Filament\Resources\Pages\CreateRecord;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr; use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Pipeline;
class CreateSale extends CreateRecord class CreateSale extends CreateRecord
{ {
@@ -81,41 +84,7 @@ class CreateSale extends CreateRecord
public function processCreate(array $data, array $transactions): Model public function processCreate(array $data, array $transactions): Model
{ {
try { $record = app(CreateSaleAction::class)($this->getFormDataMutation($data), $transactions);
DB::beginTransaction();
$record = app(SaleService::class)->create($this->getFormDataMutation($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();
}
$accountIds = collect($transactions)
->pluck('account_id')
->filter()
->unique()
->values()
->all();
$record->accounts()->sync($accountIds);
DB::commit();
} catch (\Exception $exception) {
DB::rollBack();
throw new \Exception('Failed to save transactions : '.$exception->getMessage());
}
return $record; return $record;
} }

View File

@@ -2,6 +2,7 @@
namespace App\Observers; namespace App\Observers;
use App\Commands\Clients\GenerateBaseAccountCommand;
use App\Models\Client; use App\Models\Client;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
@@ -12,45 +13,7 @@ class ClientObserver
*/ */
public function created(Client $client): void public function created(Client $client): void
{ {
DB::transaction(function () use ($client) { app(GenerateBaseAccountCommand::class)->execute($client);
$client->accounts()->createMany([
[
'account_type_id' => 1,
'account' => 'Cash',
'normal_balance' => 'debit',
],
[
'account_type_id' => 1,
'account' => 'Input Tax',
'normal_balance' => 'debit',
],
[
'account_type_id' => 1,
'account' => 'Creditable Withholding Tax',
'normal_balance' => 'debit',
],
[
'account_type_id' => 2,
'account' => 'Output Tax',
'normal_balance' => 'credit',
],
[
'account_type_id' => 2,
'account' => 'Payable Withholding Tax',
'normal_balance' => 'credit',
],
[
'account_type_id' => 5,
'account' => 'Vat Exempt Revenue',
'normal_balance' => 'credit',
],
[
'account_type_id' => 4,
'account' => 'Sales Discount',
'normal_balance' => 'debit',
],
]);
});
} }
/** /**

View File

@@ -1,31 +0,0 @@
<?php
namespace App\Services\Sales;
use App\DataObjects\CreateSaleDTO;
use App\Models\Sale;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;
class SaleService
{
/**
* Create a new class instance.
*/
public function __construct()
{
//
}
public function create(array $data): Sale
{
$tData = new CreateSaleDTO(
reference_number: $data['current_series'],
happened_on: Carbon::parse($data['happened_on']),
branch_id: $data['branch_id'],
user_id: Auth::user()->id,
);
return Sale::create($tData->toArray());
}
}