To seamlessly integrate account functionality into your Laravel models and keep track of transactions, follow the steps outlined below.
Begin by installing the package via Composer:
composer require abather/mini-accounting
Next, publish and run the migrations:
php artisan vendor:publish --tag="mini-accounting-migrations"
php artisan migrate
You can also publish the configuration file:
php artisan vendor:publish --tag="mini-accounting-config"
The contents of the published configuration file (config/mini-accounting.php
) will look like this:
return [
"prevent_duplication" => true,
"currency_precision" => 2
];
This package links two entities: Accountable (a model with an account) and Referencable (a document triggering account deposits or withdrawals).
To make a model accountable, use the HasAccountMovement
trait:
<?php
namespace App\Models;
use Abather\MiniAccounting\Traits\HasAccountMovement;
use Illuminate\Database\Eloquent\Model;
class System extends Model
{
use HasAccountMovement;
// Your code
}
Now you can deposit or withdraw any amount from it by referring to any reference model:
$system->deposit("Description Of The Transaction", 350, $bill);
You can also provide notes or extra data in JSON format to any transaction:
$system->deposit("Description Of The Transaction", 350, $bill, "Extra Notes", $json);
To get the model's current balance:
$system->balance
You can also retrieve the model's balance at the end of any month:
$system->balanceAtEndOfMonth(10)
// Returns the system balance at the end of month 10
you can also pass the year for this function if you went any year other than this year balanceAtEndOfMonth(6, 1990)
also you can get the balance for any given year:
$system->balanceAtEndOfYear()
// Returns the system balance at the end of this year
as end of month balance you can specify the year balanceAtEndOfYear(1990)
Make any model referencable by using the Referencable
trait and implementing the Referencable
interface:
<?php
namespace App\Models;
use Abather\MiniAccounting\Contracts\Referencable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Bill extends Model implements Referencable
{
use \Abather\MiniAccounting\Traits\Referencable;
use HasFactory;
public function defaultTransactions(): array
{
return [];
}
}
Define the defaultTransactions(): array
method. This method will be described later. Similar to the accountable model,
you can deposit and withdraw from the referencable model, affecting different accounts simultaneously. For example, when
a user buys from a market, the bill will deposit the amount into the market's account and withdraw the same amount from
the user's account:
$bill = Bill::first();
$bill->deposit("Deposit", $bill->amount, $bill->market);
$bill->withdraw("Withdraw", $bill->amount, $bill->user);
Assuming you have another transaction caused by the bill, such as a commission, your code would be:
$bill = Bill::first();
$bill->deposit("Deposit", $bill->amount, $bill->market);
$bill->withdraw("Withdraw", $bill->amount, $bill->user);
$bill->withdraw("Withdraw", $bill->amount * 0.1, $bill->market);
$bill->deposit("Deposit", $bill->amount * 0.1, $system);
To simplify, define the default transactions for each referencable model using the defaultTransactions
method:
public function defaultTransactions(): array
{
return [
Withdraw::make($this, "description")
->setAccount(Account::make(\App\Models\User::class)->relationship("user"))
->setCalculation(Equal::make($this, "amount")),
Deposit::make($this, "any description")
->setAccount(Account::make(\App\Models\Market::class)->relationship("market"))
->setCalculation(Equal::make($this, "amount")),
Withdraw::make($this, "other description")
->setAccount(Account::make(\App\Models\Market::class)->relationship("market"))
->setCalculation(Percentage::make($this, "amount")
->factor(StaticFactor::make(10))
),
Deposit::make($this, "other description")
->setAccount(Account::make(\App\Models\System::class, System::first()))
->setCalculation(Percentage::make($this, "amount")
->factor(DynamicFactor::make($this, 'percentage'))
),
];
}
For each object (either Deposit
or Withdraw
), set the affected account and the calculation method used to determine the transaction amount.
- you can have meta-Data with the transactions using :
$transaction->data = [
'foo' => 'bar'
];
$transaction->data // ['foo' => 'bar']
- also you can add note to the transaction via
->setNote("note")
Refer to the desired account in three ways: direct relationship from the current model, using a foreign key from the current model, or giving it any ID for reference:
Account::make(\App\Models\Market::class)->relationship("market");
In this example, specify the model in the make
method; during calculation, the account will be the market linked with
the current entity ($bill->market
). Other settings include:
variable('market_id')
: Provide any key from your model referring to the entity ($bill->market_id
).static(3)
: Lock the record with the ID3
. Also, pass a second parameter to themake()
method to specify the entity being referred to:
Account::make(\App\Models\Market::class, $this->market)
In this way, you do not need to provide any other functions.
For calculation, use the following objects:
Abather\MiniAccounting\Objects\Calculations\Equal
Abather\MiniAccounting\Objects\Calculations\Subtraction
Abather\MiniAccounting\Objects\Calculations\Addition
Abather\MiniAccounting\Objects\Calculations\Percentage
For each object, provide make($resource, $attribute)
. In our previous example, make($this, "amount")
means
the calculation will be on $bill->amount
. Except for Equal
, you must also define factor
, which is the other side
of each equation. Factor
can be either dynamic or a static value:
StaticFactor::make(10)
: The other side of the equation is 10 (e.g.,$bill->amount - 10
).DynamicFactor::make($this, 'percentage')
: The other side of the equation is$bill->percentage
.
After defining defaultTransactions()
, use it by calling executeDefaultTransactions()
. You are free to define as
many transactions
methods as needed. Keep in mind that the name of each method should end with Transactions
, and you
can run these transactions by calling the function with "execute" at the beginning of the method name (
e.g., cancelTransactions()
runs transactions using executeCancelTransactions()
).
Note:
If you ever use __call($method, $parameters)
in
your Accountable
or Referencable
models, please add the following lines:
- Accountable:
public function __call($method, $parameters)
{
if (in_array($method, ["deposit", 'withdraw'])) {
return $this->createAccountMovement(strtoupper($method), ...$parameters);
}
// Your code ...
return parent::__call($method, $parameters);
}
- Referencable:
public function __call($method, $parameters)
{
if (str_starts_with($method, "execute") && str_ends_with($method, "Transactions")) {
$method = str_replace("execute", "", $method);
$method = lcfirst($method);
return $this->executeTransactions($method);
}
if (in_array($method, ["deposit", 'withdraw'])) {
return $this->createAccountMovement(strtoupper($method), ...$parameters);
}
// Your code ...
return parent::__call($method, $parameters);
}
This documentation pertains to a Laravel package designed to enhance models' capabilities by linking them to their accounts. Additionally, it establishes links with other models to serve as reference documents, such as bills or refunds.
composer test
Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
The MIT License (MIT). Please see License File for more information.