Fixes and tests for the journal and journaled transactions #130

This commit is contained in:
Nabeel Shahzad
2018-02-28 21:52:36 -06:00
parent 1794549a20
commit 498e795e4b
9 changed files with 213 additions and 33 deletions

View File

@@ -0,0 +1,9 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\Journal::class, function (Faker $faker) {
return [
'currency' => 'USD',
];
});

View File

@@ -0,0 +1,17 @@
<?php
use Faker\Generator as Faker;
$factory->define(App\Models\JournalTransactions::class, function (Faker $faker) {
return [
'transaction_group' => \Ramsey\Uuid\Uuid::uuid4()->toString(),
'journal_id' => function () {
return factory(App\Models\Journal::class)->create()->id;
},
'credit' => $faker->numberBetween(100, 10000),
'debit' => $faker->numberBetween(100, 10000),
'currency' => 'USD',
'memo' => $faker->sentence(6),
'post_date' => \Carbon\Carbon::now(),
];
});

View File

@@ -17,8 +17,8 @@ class CreateJournalTransactionsTable extends Migration
$table->char('id', 36)->unique();
$table->char('transaction_group', 36)->nullable();
$table->integer('journal_id');
$table->unsignedBigInteger('debit')->nullable();
$table->unsignedBigInteger('credit')->nullable();
$table->unsignedBigInteger('debit')->nullable();
$table->char('currency', 5);
$table->text('memo')->nullable();
$table->char('ref_class', 32)->nullable();

View File

@@ -17,9 +17,9 @@ class CreateJournalsTable extends Migration
$table->increments('id');
$table->unsignedInteger('ledger_id')->nullable();
$table->bigInteger('balance')->default(0);
$table->char('currency', 5);
$table->char('morphed_type', 32);
$table->integer('morphed_id');
$table->string('currency', 5);
$table->string('morphed_type', 32)->nullable();
$table->unsignedInteger('morphed_id')->nullable();
$table->timestamps();
});
}

View File

@@ -24,8 +24,8 @@ class JournalTransaction extends BaseModel
public $fillable = [
'transaction_group',
'journal_id',
'debit',
'credit',
'debit',
'currency',
'memo',
'tags',
@@ -35,8 +35,8 @@ class JournalTransaction extends BaseModel
];
protected $casts = [
'debit' => 'integer',
'credits' => 'integer',
'debit' => 'integer',
'post_date' => 'datetime',
'tags' => 'array',
];

View File

@@ -11,7 +11,10 @@ use Prettus\Repository\Contracts\CacheableInterface;
use Prettus\Repository\Traits\CacheableRepository;
use Prettus\Validator\Exceptions\ValidatorException;
/**
* Class JournalRepository
* @package App\Repositories
*/
class JournalRepository extends BaseRepository implements CacheableInterface
{
use CacheableRepository;
@@ -39,7 +42,7 @@ class JournalRepository extends BaseRepository implements CacheableInterface
* @throws ValidatorException
*/
public function post(
Journal $journal,
Journal &$journal,
Money $credit = null,
Money $debit = null,
$reference = null,
@@ -52,7 +55,7 @@ class JournalRepository extends BaseRepository implements CacheableInterface
'journal_id' => $journal->id,
'credit' => $credit ? $credit->getAmount():null,
'debit' => $debit ? $debit->getAmount():null,
'currency_code' => config('phpvms.currency'),
'currency' => config('phpvms.currency'),
'memo' => $memo,
'post_date' => $post_date ?: Carbon::now(),
'transaction_group' => $transaction_group,
@@ -70,17 +73,16 @@ class JournalRepository extends BaseRepository implements CacheableInterface
}
# Adjust the balance on the journal
$balance = new Money($journal->balance);
if($credit) {
$balance = $balance->add($credit);
$journal->balance->add($credit);
}
if($debit) {
$balance = $balance->subtract($debit);
$journal->balance->subtract($debit);
}
$journal->balance = $balance->getAmount();
$journal->save();
$journal->refresh();
return $transaction;
}
@@ -92,14 +94,14 @@ class JournalRepository extends BaseRepository implements CacheableInterface
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public function getBalance(Journal $journal, Carbon $date=null)
public function getBalance(Journal $journal=null, Carbon $date=null)
{
if(!$date) {
$date = Carbon::now();
}
$credit = $this->getCreditBalanceOn($journal, $date);
$debit = $this->getDebitBalanceOn($journal, $date);
$credit = $this->getCreditBalanceBetween($date, $journal);
$debit = $this->getDebitBalanceBetween($date, $journal);
return $credit->subtract($debit);
}
@@ -112,12 +114,27 @@ class JournalRepository extends BaseRepository implements CacheableInterface
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public function getCreditBalanceOn(Journal $journal, Carbon $date)
{
$balance = $this->findWhere([
'journal_id' => $journal->id,
public function getCreditBalanceBetween(
Carbon $date,
Journal $journal=null,
Carbon $start_date=null
): Money {
$where = [
['post_date', '<=', $date]
], ['id', 'credit'])->sum('credit') ?: 0;
];
if($journal) {
$where['journal_id'] = $journal->id;
}
if ($start_date) {
$where[] = ['post_date', '>=', $start_date];
}
$balance = $this
->findWhere($where, ['id', 'credit'])
->sum('credit') ?: 0;
return new Money($balance);
}
@@ -129,13 +146,49 @@ class JournalRepository extends BaseRepository implements CacheableInterface
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public function getDebitBalanceOn(Journal $journal, Carbon $date): Money
{
$balance = $this->findWhere([
'journal_id' => $journal->id,
public function getDebitBalanceBetween(
Carbon $date,
Journal $journal=null,
Carbon $start_date=null
): Money {
$where = [
['post_date', '<=', $date]
], ['id', 'debit'])->sum('debit') ?: 0;
];
if ($journal) {
$where['journal_id'] = $journal->id;
}
if($start_date) {
$where[] = ['post_date', '>=', $start_date];
}
$balance = $this
->findWhere($where, ['id', 'debit'])
->sum('debit') ?: 0;
return new Money($balance);
}
/**
* Return all transactions for a given object
* @param $object
* @return array
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public function getAllForObject($object)
{
$transactions = $this->findWhere([
'ref_class' => \get_class($object),
'ref_class_id' => $object->id,
]);
return [
'credits' => new Money($transactions->sum('credit')),
'debits' => new Money($transactions->sum('debit')),
'transactions' => $transactions,
];
}
}

View File

@@ -80,6 +80,6 @@ class FinanceService extends BaseService
$pilot_rate = $this->getPayRateForPirep($pirep) / 60;
$payment = round($pirep->flight_time * $pilot_rate, 2);
return new Money($payment);
return Money::createFromAmount($payment);
}
}

View File

@@ -31,6 +31,20 @@ class Money
return new MoneyBase($amount, static::currency());
}
/**
* Create from a dollar amount
* @param $amount
* @return Money
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public static function createFromAmount($amount)
{
return new Money(
static::convertToSubunit($amount)
);
}
/**
* Convert a whole unit into it's subunit, e,g: dollar to cents
* @param $amount
@@ -65,7 +79,6 @@ class Money
*/
public function __construct($amount)
{
$amount = static::convertToSubunit($amount);
$this->money = static::create($amount);
}
@@ -78,9 +91,17 @@ class Money
return $this->money->getAmount();
}
/**
* Alias of getAmount()
*/
public function toAmount()
{
return $this->getAmount();
}
/**
* Returns the value in whole amounts, e.g: 100.00
* vs returning in all cents
* instead of returning in the smallest denomination
* @return float
*/
public function getValue()
@@ -88,6 +109,14 @@ class Money
return $this->money->getValue();
}
/**
* Alias of getValue()
*/
public function toValue()
{
return $this->getValue();
}
/**
* @return MoneyBase
*/
@@ -116,10 +145,16 @@ class Money
/**
* Add an amount
* @param $amount
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public function add($amount)
{
$this->money = $this->money->add($amount);
if(!($amount instanceof self)) {
$amount = static::createFromAmount($amount);
}
$this->money = $this->money->add($amount->money);
}
/**
@@ -143,11 +178,16 @@ class Money
* Subtract an amount
* @param $amount
* @return Money
* @throws \UnexpectedValueException
* @throws \InvalidArgumentException
*/
public function subtract($amount)
{
$this->money = $this->money->subtract($amount);
if (!($amount instanceof self)) {
$amount = static::createFromAmount($amount);
}
$this->money = $this->money->subtract($amount->money);
return $this;
}
@@ -155,12 +195,17 @@ class Money
* Multiply by an amount
* @param $amount
* @return Money
* @throws \UnexpectedValueException
* @throws \OutOfBoundsException
* @throws \InvalidArgumentException
*/
public function multiply($amount)
{
$this->money = $this->money->multiply($amount);
if (!($amount instanceof self)) {
$amount = static::createFromAmount($amount);
}
$this->money = $this->money->multiply($amount->money);
return $this;
}

View File

@@ -1,9 +1,11 @@
<?php
use App\Repositories\JournalRepository;
use App\Services\FareService;
use App\Services\FinanceService;
use App\Services\FleetService;
use App\Support\Math;
use App\Support\Money;
class FinanceTest extends TestCase
{
@@ -373,7 +375,7 @@ class FinanceTest extends TestCase
]);
$payment = $this->financeSvc->getPilotPilotPay($pirep_acars);
$this->assertEquals($payment->getValue(), 100);
$this->assertEquals(100, $payment->getValue());
$pirep_acars = factory(App\Models\Pirep::class)->create([
'user_id' => $this->user->id,
@@ -385,4 +387,58 @@ class FinanceTest extends TestCase
$payment = $this->financeSvc->getPilotPilotPay($pirep_acars);
$this->assertEquals($payment->getValue(), 150);
}
/**
* @throws \Prettus\Validator\Exceptions\ValidatorException
*/
public function testJournalOperations()
{
$journalRepo = app(JournalRepository::class);
$user = factory(App\Models\User::class)->create();
$journal = factory(App\Models\Journal::class)->create();
$journalRepo->post(
$journal,
Money::createFromAmount(100),
null,
$user
);
$balance = $journalRepo->getBalance($journal);
$this->assertEquals(100, $balance->getValue());
# add another transaction
$journalRepo->post(
$journal,
Money::createFromAmount(25),
null,
$user
);
$balance = $journalRepo->getBalance($journal);
$this->assertEquals(125, $balance->getValue());
# Get the total balance
$this->assertEquals(125, $journal->balance->getValue());
# debit an amount
$journalRepo->post(
$journal,
null,
Money::createFromAmount(25),
$user
);
$this->assertEquals(100, $journal->balance->getValue());
# find all transactions
$transactions = $journalRepo->getAllForObject($user);
$this->assertCount(3, $transactions['transactions']);
$this->assertEquals(125, $transactions['credits']->getValue());
$this->assertEquals(25, $transactions['debits']->getValue());
}
}