2018-03-01 09:04:56 +08:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Repositories;
|
|
|
|
|
|
|
|
use App\Models\Journal;
|
|
|
|
use App\Models\JournalTransaction;
|
|
|
|
use App\Support\Money;
|
|
|
|
use Carbon\Carbon;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
use Prettus\Repository\Contracts\CacheableInterface;
|
|
|
|
use Prettus\Repository\Traits\CacheableRepository;
|
|
|
|
use Prettus\Validator\Exceptions\ValidatorException;
|
|
|
|
|
2018-03-01 11:52:36 +08:00
|
|
|
/**
|
|
|
|
* Class JournalRepository
|
|
|
|
* @package App\Repositories
|
|
|
|
*/
|
2018-03-01 09:04:56 +08:00
|
|
|
class JournalRepository extends BaseRepository implements CacheableInterface
|
|
|
|
{
|
|
|
|
use CacheableRepository;
|
|
|
|
|
2018-03-02 06:20:13 +08:00
|
|
|
/**
|
|
|
|
* @return string
|
|
|
|
*/
|
2018-03-01 09:04:56 +08:00
|
|
|
public function model()
|
|
|
|
{
|
|
|
|
return JournalTransaction::class;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Post a new transaction to a journal, and also adjust the balance
|
|
|
|
* on the transaction itself. A cron will run to reconcile the journal
|
|
|
|
* balance nightly, since they're not atomic operations
|
|
|
|
*
|
|
|
|
* @param Journal $journal
|
|
|
|
* @param Money|null $credit Amount to credit
|
|
|
|
* @param Money|null $debit Amount to debit
|
|
|
|
* @param Model|null $reference The object this is a reference to
|
|
|
|
* @param string|null $memo Memo for this transaction
|
|
|
|
* @param string|null $post_date Date of the posting
|
|
|
|
* @param string|null $transaction_group
|
|
|
|
* @return mixed
|
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
* @throws ValidatorException
|
|
|
|
*/
|
|
|
|
public function post(
|
2018-03-01 11:52:36 +08:00
|
|
|
Journal &$journal,
|
2018-03-01 09:04:56 +08:00
|
|
|
Money $credit = null,
|
|
|
|
Money $debit = null,
|
|
|
|
$reference = null,
|
|
|
|
$memo = null,
|
|
|
|
$post_date = null,
|
|
|
|
$transaction_group = null
|
|
|
|
) {
|
|
|
|
|
|
|
|
$attrs = [
|
|
|
|
'journal_id' => $journal->id,
|
|
|
|
'credit' => $credit ? $credit->getAmount():null,
|
|
|
|
'debit' => $debit ? $debit->getAmount():null,
|
2018-03-01 11:52:36 +08:00
|
|
|
'currency' => config('phpvms.currency'),
|
2018-03-01 09:04:56 +08:00
|
|
|
'memo' => $memo,
|
|
|
|
'post_date' => $post_date ?: Carbon::now(),
|
|
|
|
];
|
|
|
|
|
|
|
|
if($reference !== null) {
|
|
|
|
$attrs['ref_class'] = \get_class($reference);
|
|
|
|
$attrs['ref_class_id'] = $reference->id;
|
|
|
|
}
|
2018-03-02 06:20:13 +08:00
|
|
|
|
|
|
|
if($transaction_group) {
|
|
|
|
$transaction_group = str_replace(' ', '_', $transaction_group);
|
|
|
|
$attrs['transaction_group'] = $transaction_group;
|
|
|
|
}
|
2018-03-01 09:04:56 +08:00
|
|
|
|
|
|
|
try {
|
|
|
|
$transaction = $this->create($attrs);
|
|
|
|
} catch (ValidatorException $e) {
|
|
|
|
throw $e;
|
|
|
|
}
|
|
|
|
|
|
|
|
# Adjust the balance on the journal
|
|
|
|
if($credit) {
|
2018-03-01 11:52:36 +08:00
|
|
|
$journal->balance->add($credit);
|
2018-03-01 09:04:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if($debit) {
|
2018-03-01 11:52:36 +08:00
|
|
|
$journal->balance->subtract($debit);
|
2018-03-01 09:04:56 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
$journal->save();
|
2018-03-01 11:52:36 +08:00
|
|
|
$journal->refresh();
|
2018-03-01 09:04:56 +08:00
|
|
|
|
|
|
|
return $transaction;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Journal $journal
|
|
|
|
* @param Carbon|null $date
|
|
|
|
* @return Money
|
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
*/
|
2018-03-01 11:52:36 +08:00
|
|
|
public function getBalance(Journal $journal=null, Carbon $date=null)
|
2018-03-01 09:04:56 +08:00
|
|
|
{
|
|
|
|
if(!$date) {
|
|
|
|
$date = Carbon::now();
|
|
|
|
}
|
|
|
|
|
2018-03-01 11:52:36 +08:00
|
|
|
$credit = $this->getCreditBalanceBetween($date, $journal);
|
|
|
|
$debit = $this->getDebitBalanceBetween($date, $journal);
|
2018-03-01 09:04:56 +08:00
|
|
|
|
|
|
|
return $credit->subtract($debit);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the credit only balance of the journal based on a given date.
|
|
|
|
* @param Journal $journal
|
|
|
|
* @param Carbon $date
|
|
|
|
* @return Money
|
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
*/
|
2018-03-01 11:52:36 +08:00
|
|
|
public function getCreditBalanceBetween(
|
|
|
|
Carbon $date,
|
|
|
|
Journal $journal=null,
|
|
|
|
Carbon $start_date=null
|
|
|
|
): Money {
|
|
|
|
|
|
|
|
$where = [
|
2018-03-01 09:04:56 +08:00
|
|
|
['post_date', '<=', $date]
|
2018-03-01 11:52:36 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
if($journal) {
|
|
|
|
$where['journal_id'] = $journal->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($start_date) {
|
|
|
|
$where[] = ['post_date', '>=', $start_date];
|
|
|
|
}
|
|
|
|
|
|
|
|
$balance = $this
|
|
|
|
->findWhere($where, ['id', 'credit'])
|
|
|
|
->sum('credit') ?: 0;
|
2018-03-01 09:04:56 +08:00
|
|
|
|
|
|
|
return new Money($balance);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Journal $journal
|
|
|
|
* @param Carbon $date
|
|
|
|
* @return Money
|
|
|
|
* @throws \UnexpectedValueException
|
|
|
|
* @throws \InvalidArgumentException
|
|
|
|
*/
|
2018-03-01 11:52:36 +08:00
|
|
|
public function getDebitBalanceBetween(
|
|
|
|
Carbon $date,
|
|
|
|
Journal $journal=null,
|
|
|
|
Carbon $start_date=null
|
|
|
|
): Money {
|
|
|
|
|
|
|
|
$where = [
|
2018-03-01 09:04:56 +08:00
|
|
|
['post_date', '<=', $date]
|
2018-03-01 11:52:36 +08:00
|
|
|
];
|
|
|
|
|
|
|
|
if ($journal) {
|
|
|
|
$where['journal_id'] = $journal->id;
|
|
|
|
}
|
|
|
|
|
|
|
|
if($start_date) {
|
|
|
|
$where[] = ['post_date', '>=', $start_date];
|
|
|
|
}
|
|
|
|
|
|
|
|
$balance = $this
|
|
|
|
->findWhere($where, ['id', 'debit'])
|
|
|
|
->sum('debit') ?: 0;
|
2018-03-01 09:04:56 +08:00
|
|
|
|
|
|
|
return new Money($balance);
|
|
|
|
}
|
2018-03-01 11:52:36 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
|
|
|
];
|
|
|
|
}
|
2018-03-01 09:04:56 +08:00
|
|
|
}
|