feat(sales): add discount support with ledger accounting
- 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
This commit is contained in:
11
.devdbrc
Normal file
11
.devdbrc
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "My test MySQL database",
|
||||||
|
"type": "mysql",
|
||||||
|
"host": "192.168.100.105",
|
||||||
|
"port": "3306",
|
||||||
|
"username": "root",
|
||||||
|
"password": "root",
|
||||||
|
"database": "mkm_admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -24,7 +24,6 @@ class CreateSaleAction
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
|
|
||||||
//create transactions for the sale
|
//create transactions for the sale
|
||||||
app(CreateRecordTransactionsAction::class)($record, $transactions);
|
app(CreateRecordTransactionsAction::class)($record, $transactions);
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ class CreateTransactionAction extends BaseAction
|
|||||||
|
|
||||||
$this->cashAccountLedger($payload);
|
$this->cashAccountLedger($payload);
|
||||||
|
|
||||||
|
if ($payload->transaction->discount !== 0) {
|
||||||
|
$this->discountAccountLedger($payload);
|
||||||
|
}
|
||||||
|
|
||||||
return $next($payload);
|
return $next($payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,11 +37,13 @@ class CreateTransactionAction extends BaseAction
|
|||||||
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
$isExpense = $payload->transactionable instanceof \App\Models\Expense;
|
||||||
$type = $isExpense ? 'debit' : 'credit';
|
$type = $isExpense ? 'debit' : 'credit';
|
||||||
|
|
||||||
|
$discount = $payload->transaction->discount ?? 0.00;
|
||||||
|
|
||||||
if ($branch->isClientVatable) {
|
if ($branch->isClientVatable) {
|
||||||
//create transaction account ledger
|
//create transaction account ledger
|
||||||
$ledgerPayload = new CreateLedgerDTO(
|
$ledgerPayload = new CreateLedgerDTO(
|
||||||
branch_id: $payload->transactionable->branch_id,
|
branch_id: $payload->transactionable->branch_id,
|
||||||
amount: $payload->transaction->net_amount ?? 0.00,
|
amount: $payload->transaction->net_amount + $discount ?? 0.00,
|
||||||
transaction: $payload->transaction,
|
transaction: $payload->transaction,
|
||||||
account: $payload->transaction->account,
|
account: $payload->transaction->account,
|
||||||
type: $type,
|
type: $type,
|
||||||
@@ -144,4 +150,28 @@ class CreateTransactionAction extends BaseAction
|
|||||||
$this->ledgerPipe($ledgerPayload);
|
$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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class SaleResource extends Resource
|
|||||||
Header::make('Charge Account'),
|
Header::make('Charge Account'),
|
||||||
Header::make('Description'),
|
Header::make('Description'),
|
||||||
Header::make('Gross Amount'),
|
Header::make('Gross Amount'),
|
||||||
Header::make('Exempt'),
|
// Header::make('Exempt'),
|
||||||
Header::make('Vatable Amount'),
|
Header::make('Vatable Amount'),
|
||||||
Header::make('Output Tax'),
|
Header::make('Output Tax'),
|
||||||
Header::make('Withholding Tax'),
|
Header::make('Withholding Tax'),
|
||||||
@@ -110,7 +110,7 @@ class SaleResource extends Resource
|
|||||||
Header::make('Charge Account'),
|
Header::make('Charge Account'),
|
||||||
Header::make('Description'),
|
Header::make('Description'),
|
||||||
Header::make('Gross Amount'),
|
Header::make('Gross Amount'),
|
||||||
Header::make('Exempt'),
|
// Header::make('Exempt'),
|
||||||
Header::make('Vatable Amount'),
|
Header::make('Vatable Amount'),
|
||||||
Header::make('Output Tax'),
|
Header::make('Output Tax'),
|
||||||
Header::make('Withholding Tax'),
|
Header::make('Withholding Tax'),
|
||||||
@@ -133,6 +133,7 @@ class SaleResource extends Resource
|
|||||||
TextInput::make('exempt')
|
TextInput::make('exempt')
|
||||||
->numeric()
|
->numeric()
|
||||||
->live()
|
->live()
|
||||||
|
->hidden()
|
||||||
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
||||||
static::setDefaultFormValues($get, $set, $old, $state);
|
static::setDefaultFormValues($get, $set, $old, $state);
|
||||||
})->default(0),
|
})->default(0),
|
||||||
@@ -155,16 +156,16 @@ class SaleResource extends Resource
|
|||||||
->numeric()
|
->numeric()
|
||||||
->live()
|
->live()
|
||||||
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
->afterStateUpdated(function (Get $get, Set $set, ?string $old, ?string $state) {
|
||||||
|
|
||||||
static::setDefaultFormValues($get, $set, $old, $state);
|
static::setDefaultFormValues($get, $set, $old, $state);
|
||||||
})->default(0),
|
})->default(0),
|
||||||
TextInput::make('discount')
|
TextInput::make('discount')
|
||||||
->numeric()
|
->numeric()
|
||||||
->readOnly()
|
// ->readOnly()
|
||||||
->visible(fn (Get $get) => $get('../../with_discount'))
|
->visible(fn (Get $get) => $get('../../with_discount'))
|
||||||
->live(),
|
->live(),
|
||||||
Select::make('discount_type')
|
Select::make('discount_type')
|
||||||
->options(fn (Get $get) => static::getDiscountOptions($get))
|
->options(fn (Get $get) => static::getDiscountOptions($get))
|
||||||
|
->required(fn (Get $get) => $get('../../with_discount'))
|
||||||
->visible(fn (Get $get) => $get('../../with_discount')),
|
->visible(fn (Get $get) => $get('../../with_discount')),
|
||||||
TextInput::make('net_amount')->numeric()->default(0),
|
TextInput::make('net_amount')->numeric()->default(0),
|
||||||
];
|
];
|
||||||
@@ -225,7 +226,7 @@ class SaleResource extends Resource
|
|||||||
}
|
}
|
||||||
|
|
||||||
$set('output_tax', number_format($outputTax, 2, '.', ''));
|
$set('output_tax', number_format($outputTax, 2, '.', ''));
|
||||||
$set('discount', number_format($discount, 2, '.', ''));
|
// $set('discount', number_format($discount, 2, '.', ''));
|
||||||
$set('vatable_amount', number_format($vatableAmount, 2, '.', ''));
|
$set('vatable_amount', number_format($vatableAmount, 2, '.', ''));
|
||||||
$set('net_amount', number_format($netAmount, 2, '.', ''));
|
$set('net_amount', number_format($netAmount, 2, '.', ''));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,10 +76,11 @@ class CreateSale extends CreateRecord
|
|||||||
$data['vatable_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['vatable_amount'] ?? 0));
|
$data['vatable_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['vatable_amount'] ?? 0));
|
||||||
$data['output_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['output_tax'] ?? 0));
|
$data['output_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['output_tax'] ?? 0));
|
||||||
$data['payable_withholding_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['payable_withholding_tax'] ?? 0));
|
$data['payable_withholding_tax'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['payable_withholding_tax'] ?? 0));
|
||||||
$data['discount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['discount'] ?? 0));
|
$discount = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['discount'] ?? 0));
|
||||||
$data['net_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['net_amount'] ?? 0));
|
$data['discount'] = $discount;
|
||||||
|
$data['net_amount'] = collect($transactions)->sum(fn (array $transaction) => (float) ($transaction['net_amount'] ?? 0)) + $discount;
|
||||||
|
|
||||||
return Arr::except($data, ['client', 'transactions', 'with_discount']);
|
return Arr::except($data, ['client', 'transactions']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function processCreate(array $data, array $transactions): Model
|
public function processCreate(array $data, array $transactions): Model
|
||||||
|
|||||||
@@ -12,7 +12,14 @@ class Sale extends Model
|
|||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $guarded = [];
|
protected $fillable = [
|
||||||
|
'branch_id',
|
||||||
|
'user_id',
|
||||||
|
'client_id',
|
||||||
|
'happened_on',
|
||||||
|
'reference_number',
|
||||||
|
'buyer'
|
||||||
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
'happened_on' => 'date:Y-m-d',
|
'happened_on' => 'date:Y-m-d',
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('transactions', function (Blueprint $table) {
|
||||||
|
$table->string('discount_type')->after('with_discount')->nullable();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('transactions', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('discount_type');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user