Skip to content

Commit

Permalink
Update: Add attachments to Transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
ekmungai committed Feb 19, 2024
1 parent a5b2bdd commit 448e66e
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 46 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 5.0.2 - 2024-02-19

- Add Attachments to Transactions
## 5.0.1 - 2023-04-18

- Add Laravel 10 Compatibility
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class AddTransactionAttachmentsColumns extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table(
config('ifrs.table_prefix') . 'transactions',
function (Blueprint $table) {
$table->unsignedBigInteger('attachment_id')->nullable();
$table->string('attachment_type')->nullable();
}
);
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table(
config('ifrs.table_prefix') . 'transactions',
function (Blueprint $table) {
if (config('database.default') == 'sqlite') {
DB::statement('PRAGMA foreign_keys = OFF;'); // sqlite needs to drop the entire table to remove a column, which fails because the table is already referenced
}
$table->dropColumn('attachment_id');
}
);

Schema::table(
config('ifrs.table_prefix') . 'transactions',
function (Blueprint $table) {
$table->dropColumn('attachment_type');
}
);
}
}
89 changes: 48 additions & 41 deletions src/Models/Transaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ class Transaction extends Model implements Segregatable, Recyclable, Clearable,
'transaction_type',
'transaction_no',
'entity_id',
'attachment_id',
'attachment_type'
];

protected $dates = [
Expand Down Expand Up @@ -194,9 +196,7 @@ private static function getCompoundEntrytype(bool $credited): string
*/
protected function addCompoundEntry(array $compoundEntry, bool $credited): void
{
$this->compoundEntries[
Transaction::getCompoundEntrytype($credited)][$compoundEntry['id']
] = $compoundEntry['amount'];
$this->compoundEntries[Transaction::getCompoundEntrytype($credited)][$compoundEntry['id']] = $compoundEntry['amount'];
}

/**
Expand Down Expand Up @@ -333,6 +333,16 @@ public function lineItems()
return $this->hasMany(LineItem::class, 'transaction_id', 'id');
}

/**
* The model attached to the transaction.
*
* @return \Illuminate\Database\Eloquent\Relations\MorphTo
*/
public function attachment()
{
return $this->morphTo();
}

/**
* Instance Type Translator.
*
Expand Down Expand Up @@ -384,22 +394,21 @@ public function getAmountAttribute(): float
if ($this->is_posted) {

$query = $ledger->newQuery()
->selectRaw("SUM(amount/rate) as amount")
->where([
"transaction_id" => $this->id,
"entry_type" => Transaction::getCompoundEntrytype($this->credited),
"currency_id" => $this->currency_id
]);

if(!$this->compound){
->selectRaw("SUM(amount/rate) as amount")
->where([
"transaction_id" => $this->id,
"entry_type" => Transaction::getCompoundEntrytype($this->credited),
"currency_id" => $this->currency_id
]);

if (!$this->compound) {
$query->where("post_account", $this->account_id);
}

$amount = $query->get()[0]->amount;

} else {
foreach ($this->getLineItems() as $lineItem) {
if($lineItem->credited != $this->credited){
if ($lineItem->credited != $this->credited) {
$amount += $lineItem->amount * $lineItem->quantity;
if (!$lineItem->vat_inclusive) {
$amount += $lineItem->vat['total'];
Expand All @@ -417,18 +426,14 @@ public function getAmountAttribute(): float
*/
public function getCompoundEntries()
{
if($this->compound){
$this->compoundEntries[
Transaction::getCompoundEntrytype($this->credited)
][$this->account_id] = floatval($this->main_account_amount);

if ($this->compound) {
$this->compoundEntries[Transaction::getCompoundEntrytype($this->credited)][$this->account_id] = floatval($this->main_account_amount);

foreach ($this->lineItems as $lineItem) {
$this->compoundEntries[
Transaction::getCompoundEntrytype($lineItem->credited)
][$lineItem->account_id] = $lineItem->amount * $lineItem->quantity;
$this->compoundEntries[Transaction::getCompoundEntrytype($lineItem->credited)][$lineItem->account_id] = $lineItem->amount * $lineItem->quantity;
}
}

return $this->compoundEntries;
}

Expand Down Expand Up @@ -456,12 +461,12 @@ public function getVatAttribute(): array
{
$vats = ['total' => 0];
foreach ($this->getLineItems() as $lineItem) {
foreach($lineItem->vat as $type => $amount)
if (array_key_exists($type, $vats)) {
$vats[$type] += $amount;
} else {
$vats[$type] = $amount;
}
foreach ($lineItem->vat as $type => $amount)
if (array_key_exists($type, $vats)) {
$vats[$type] += $amount;
} else {
$vats[$type] = $amount;
}
}
return $vats;
}
Expand Down Expand Up @@ -525,7 +530,7 @@ public function addLineItem(LineItem $lineItem): bool
throw new RedundantTransaction();
}

if(!$this->compound){
if (!$this->compound) {
$lineItem->credited = !$this->credited;
}

Expand Down Expand Up @@ -555,9 +560,9 @@ public function removeLineItem(LineItem $lineItem): void
unset($this->items[$key]);
}

if($this->compound){
if ($this->compound) {
$entryType = Transaction::getCompoundEntrytype($lineItem->credited);
if(array_key_exists($lineItem->account_id, $this->compoundEntries[$entryType])){
if (array_key_exists($lineItem->account_id, $this->compoundEntries[$entryType])) {
unset($this->compoundEntries[$entryType][$lineItem->account_id]);
}
}
Expand Down Expand Up @@ -698,10 +703,12 @@ public function save(array $options = []): bool
if ($period->status == ReportingPeriod::ADJUSTING && $this->transaction_type != Transaction::JN) {
throw new AdjustingReportingPeriod();
}

if (in_array($this->account->account_type, config('ifrs.single_currency')) &&
$this->account->currency_id != $this->currency_id &&
$this->currency_id != $entity->currency_id) {

if (
in_array($this->account->account_type, config('ifrs.single_currency')) &&
$this->account->currency_id != $this->currency_id &&
$this->currency_id != $entity->currency_id
) {
throw new InvalidCurrency("Transaction", $this->account);
}

Expand All @@ -724,7 +731,7 @@ public function save(array $options = []): bool
if ($this->isDirty('transaction_type') && $this->transaction_type != $this->getOriginal('transaction_type') && !is_null($this->id)) {
throw new InvalidTransactionType();
}

$save = parent::save();
$this->saveLineItems();

Expand Down Expand Up @@ -752,10 +759,10 @@ public static function transactionNo(string $type, Carbon $transaction_date = nu
$periodStart = ReportingPeriod::periodStart($transaction_date, $entity);

$nextId = Transaction::withTrashed()
->where("transaction_type", $type)
->where("transaction_date", ">=", $periodStart)
->where("entity_id", '=', $entity->id)
->count() + 1;
->where("transaction_type", $type)
->where("transaction_date", ">=", $periodStart)
->where("entity_id", '=', $entity->id)
->count() + 1;

return $type . str_pad((string)$periodCount, 2, "0", STR_PAD_LEFT)
. "/" .
Expand Down Expand Up @@ -809,7 +816,7 @@ public function getHasIntegrityAttribute(): bool
// verify transaction ledger hashes
return $this->ledgers->every(
function ($ledger, $key) {
return hash(config('ifrs')['hashing_algorithm'],$ledger->hashed()) == $ledger->hash;
return hash(config('ifrs')['hashing_algorithm'], $ledger->hashed()) == $ledger->hash;
}
);
}
Expand Down
53 changes: 48 additions & 5 deletions tests/Unit/TransactionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
use IFRS\Exceptions\UnpostedAssignment;
use IFRS\Exceptions\InvalidTransactionDate;
use IFRS\Exceptions\InvalidTransactionType;
use IFRS\Models\Category;

class TransactionTest extends TestCase
{
Expand Down Expand Up @@ -123,7 +124,7 @@ public function testTransactionEntityScope()

$newEntity->currency()->associate(factory(Currency::class)->create());
$newEntity->save();

$currency = factory(Currency::class)->create();

$entity = new Entity();
Expand Down Expand Up @@ -230,7 +231,7 @@ public function testTransactionRecycling()
$transaction->delete();
}

/**
/**
* Test Transaction Model recylcling
*
* @return void
Expand Down Expand Up @@ -428,7 +429,7 @@ public function testVat()
$transaction->addLineItem($lineItem2);
$transaction->post();

$this->assertEquals($transaction->vat, ['total' => 7.0,'E' => 2.0, 'L' => 5.0]);
$this->assertEquals($transaction->vat, ['total' => 7.0, 'E' => 2.0, 'L' => 5.0]);
}

/**
Expand Down Expand Up @@ -1082,9 +1083,9 @@ public function testInvalidTransactionDate()
{
$this->expectException(InvalidTransactionDate::class);
$this->expectExceptionMessage('Transaction date cannot be at the beginning of the first day of the Reporting Period. Use a Balance object instead');

Transaction::create([
'transaction_date' => Carbon::parse(date('Y').'-01-01'),
'transaction_date' => Carbon::parse(date('Y') . '-01-01'),
]);
}

Expand Down Expand Up @@ -1133,4 +1134,46 @@ public function testInvalidTransactionType()
'transaction_type' => Transaction::IN
]);
}

/**
* Test Transaction Attachments.
*
* @return void
*/
public function testTransactionAttachments()
{
$account = factory(Account::class)->create([
'account_type' => Account::RECEIVABLE,
'category_id' => null
]);

$category = new Category([
'name' => $this->faker->word,
'category_type' => Account::BANK,
]);
$category->save();

$transaction = new JournalEntry([
"account_id" => $account->id,
"transaction_date" => Carbon::now(),
"narration" => $this->faker->word,
"attachment_id" => $category->id,
"attachment_type" => Category::class
]);

$line = new LineItem([
'vat_id' => factory(Vat::class)->create(["rate" => 0])->id,
'account_id' => factory(Account::class)->create([
'category_id' => null
])->id,
'amount' => 125,
]);

$transaction->addLineItem($line);
$transaction->save();
$transaction->refresh();

$this->assertEquals($transaction->attachment->id, $category->id);
$this->assertEquals($transaction->attachment->name, $category->name);
}
}

0 comments on commit 448e66e

Please sign in to comment.