- Add discount_type column to transactions table via migration - Update Sale model to use fillable instead of guarded for better security - Implement discount account ledger creation when discount is applied - Fix net amount calculation to include discount in CreateSaleAction - Remove unused "Exempt" column from sale transaction table - Make discount_type required when discount is enabled in form - Update form data mutation to properly handle discount calculations
178 lines
6.1 KiB
PHP
178 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace App\Actions\Transactions;
|
|
|
|
use App\Actions\Balances\CreateBalanceAction;
|
|
use App\Actions\BaseAction;
|
|
use App\Actions\Ledgers\CreateLedgerAction;
|
|
use App\DataObjects\CreateLedgerDTO;
|
|
use App\DataObjects\CreateTransactionDTO;
|
|
use App\Models\Account;
|
|
use Closure;
|
|
use Illuminate\Support\Facades\Pipeline;
|
|
use Spatie\LaravelData\Data;
|
|
|
|
class CreateTransactionAction extends BaseAction
|
|
{
|
|
public function __invoke(CreateTransactionDTO|Data $payload, Closure $next)
|
|
{
|
|
$payload->transaction = $payload->transactionable->transactions()->create($payload->data);
|
|
|
|
$this->transactionAccountLedger($payload);
|
|
|
|
$this->withHoldingAccountLedger($payload);
|
|
|
|
$this->cashAccountLedger($payload);
|
|
|
|
if ($payload->transaction->discount !== 0) {
|
|
$this->discountAccountLedger($payload);
|
|
}
|
|
|
|
return $next($payload);
|
|
}
|
|
|
|
public function transactionAccountLedger($payload): void
|
|
{
|
|
$branch = $payload->transaction->branch;
|
|
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
|
$type = $isExpense ? 'debit' : 'credit';
|
|
|
|
$discount = $payload->transaction->discount ?? 0.00;
|
|
|
|
if ($branch->isClientVatable) {
|
|
//create transaction account ledger
|
|
$ledgerPayload = new CreateLedgerDTO(
|
|
branch_id: $payload->transactionable->branch_id,
|
|
amount: $payload->transaction->net_amount + $discount ?? 0.00,
|
|
transaction: $payload->transaction,
|
|
account: $payload->transaction->account,
|
|
type: $type,
|
|
);
|
|
$this->ledgerPipe($ledgerPayload);
|
|
|
|
$this->taxAccountLedger($payload, $isExpense);
|
|
} else {
|
|
//create transaction account ledger
|
|
$ledgerPayload = new CreateLedgerDTO(
|
|
branch_id: $payload->transactionable->branch_id,
|
|
amount: $payload->transaction->gross_amount ?? 0.00,
|
|
transaction: $payload->transaction,
|
|
account: $payload->transaction->account,
|
|
type: $type,
|
|
);
|
|
$this->ledgerPipe($ledgerPayload);
|
|
}
|
|
|
|
}
|
|
|
|
public function ledgerPipe(CreateLedgerDTO $ledgerPayload): mixed
|
|
{
|
|
return Pipeline::send(passable: $ledgerPayload)->through([
|
|
CreateLedgerAction::class,
|
|
CreateBalanceAction::class,
|
|
])->thenReturn();
|
|
}
|
|
|
|
public function taxAccountLedger($payload, bool $isExpense): void
|
|
{
|
|
$accountName = $isExpense ? 'Input Tax' : 'Output Tax';
|
|
$type = $isExpense ? 'debit' : 'credit';
|
|
$clientId = $payload->transactionable->branch->client_id;
|
|
|
|
$taxAccount = Account::query()
|
|
->where('account', $accountName)
|
|
->where('client_id', $clientId)
|
|
->first();
|
|
|
|
$amount = $isExpense
|
|
? ($payload->transactionable->input_tax ?? 0.00)
|
|
: ($payload->transactionable->output_tax ?? 0.00);
|
|
|
|
if ($taxAccount && $amount > 0) {
|
|
$ledgerPayload = new CreateLedgerDTO(
|
|
branch_id: $payload->transactionable->branch_id,
|
|
amount: $amount,
|
|
transaction: $payload->transaction,
|
|
account: $taxAccount,
|
|
type: $type,
|
|
);
|
|
$this->ledgerPipe($ledgerPayload);
|
|
}
|
|
}
|
|
|
|
public function withHoldingAccountLedger($payload): void
|
|
{
|
|
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
|
$accountName = $isExpense ? 'Payable Withholding Tax' : 'Creditable Withholding Tax';
|
|
$type = $isExpense ? 'credit' : 'debit';
|
|
$clientId = $payload->transactionable->branch->client_id;
|
|
|
|
$withholdingAccount = Account::query()
|
|
->where('account', $accountName)
|
|
->where('client_id', $clientId)
|
|
->first();
|
|
|
|
$amount = $payload->transaction->payable_withholding_tax ?? 0.00;
|
|
|
|
if ($withholdingAccount && $amount > 0) {
|
|
$ledgerPayload = new CreateLedgerDTO(
|
|
branch_id: $payload->transactionable->branch_id,
|
|
amount: $amount,
|
|
transaction: $payload->transaction,
|
|
account: $withholdingAccount,
|
|
type: $type,
|
|
);
|
|
$this->ledgerPipe($ledgerPayload);
|
|
}
|
|
}
|
|
|
|
public function cashAccountLedger($payload): void
|
|
{
|
|
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
|
$type = $isExpense ? 'credit' : 'debit';
|
|
$wht = $isExpense ? ($payload->transaction->payable_withholding_tax ?? 0) : ($payload->transaction->creditable_withholding_tax ?? 0);
|
|
$amount = ($payload->transaction->gross_amount ?? 0) - $wht;
|
|
$clientId = $payload->transactionable->branch->client_id;
|
|
|
|
$cashAccount = Account::query()
|
|
->where('account', 'Cash')
|
|
->where('client_id', $clientId)
|
|
->first();
|
|
|
|
if ($cashAccount && $amount > 0) {
|
|
$ledgerPayload = new CreateLedgerDTO(
|
|
branch_id: $payload->transactionable->branch_id,
|
|
amount: $amount,
|
|
transaction: $payload->transaction,
|
|
account: $cashAccount,
|
|
type: $type,
|
|
);
|
|
$this->ledgerPipe($ledgerPayload);
|
|
}
|
|
}
|
|
|
|
public function discountAccountLedger($payload): void
|
|
{
|
|
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
|
$type = $isExpense ? 'credit' : 'debit';
|
|
$amount = $payload->transaction->discount ?? 0.00;
|
|
$clientId = $payload->transactionable->branch->client_id;
|
|
|
|
$discountAccount = Account::query()
|
|
->where('account', 'Sales Discount')
|
|
->where('client_id', $clientId)
|
|
->first();
|
|
|
|
if ($discountAccount && $amount > 0) {
|
|
$ledgerPayload = new CreateLedgerDTO(
|
|
branch_id: $payload->transactionable->branch_id,
|
|
amount: $amount,
|
|
transaction: $payload->transaction,
|
|
account: $discountAccount,
|
|
type: $type,
|
|
);
|
|
$this->ledgerPipe($ledgerPayload);
|
|
}
|
|
}
|
|
}
|