Skip to content

Commit

Permalink
Tests, etc: refactor in light of addition of Journal model (#19)
Browse files Browse the repository at this point in the history
Now that we have a `Journal` model (which "owns" `Account` models) we
should update our testing helpers to account for the journal instances
more explicitly. This PR does just that.

Also we add the notion of a 'current period' to `Journal` and remove the
notion of a globally configured "accounting period": a `Journal` now
controls what is the current accounting period in any given context for
objects which descend from it (accounts, line items, etc.). Later work
can further modify existing scopes to require that journal object to use
as a fallback when a more specific period is not needed (and to ensure
all e.g. ledger line items are always scoped to a specific journal).

Related to #16. Closes #19.

-----

Automated Test Results:

OK (191 tests, 319 assertions)
  • Loading branch information
bayprogrammer committed Sep 1, 2023
1 parent 7754505 commit 849823d
Show file tree
Hide file tree
Showing 22 changed files with 669 additions and 775 deletions.
9 changes: 0 additions & 9 deletions config/beankeep.php

This file was deleted.

11 changes: 8 additions & 3 deletions database/factories/Support/AccountLookup.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use ArrayAccess;
use Illuminate\Support\Str;
use STS\Beankeep\Models\Account;
use STS\Beankeep\Models\Journal;

final class AccountLookup implements ArrayAccess
{
Expand All @@ -17,13 +18,17 @@ public function __construct()
$this->refresh();
}

public function refresh(): void
public function refresh(?Journal $journal = null): void
{
$this->accounts = self::lookupTable();
$this->accounts = self::lookupTable($journal);
}

public static function lookupTable(): array
public static function lookupTable(?Journal $journal = null): array
{
if (!$journal) {
$journal = Journal::find(1);
}

return Account::all()
->mapWithKeys(fn (Account $account) =>
[Str::kebab($account->name) => $account])
Expand Down
50 changes: 50 additions & 0 deletions doc/todo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
factories / seeders - create more than one journal

journal helper instance method for getting line items
all line items within journal's current period by default
optionally constrained to specific period
optionally constrained to specific account

update account scopes - require journal

denormalize line-item model (journal_id & date)
update factories, seeders, & tests
simplify existing scopes' implementations

denormalize source-document model (journal_id)
update factories, seeders, & tests

denormalize transaction model (journal_id)
update factories, seeders, & tests

update line item scopes - require journal

-----

line item & account: current journal global scope (opt-in)

report helpers
trial balance
other reports / custom report definitions?

default accounts (used automatically for new journals)

helpers/support for multi-db (journals grouped into sets, one db per set)?

documentation, doc rendering (phpdocs?)

code coverage

-----

prepare for & release 1.0

-----

headless livewire components?

filament package?

tease out "core" from laravel-specific bits?
look at money pattern & libs?
cli demo app?
4 changes: 0 additions & 4 deletions src/BeankeepServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ class BeankeepServiceProvider extends ServiceProvider
{
public function boot(): void
{
$this->publishes([
__DIR__ . '/../config/beankeep.php' => config_path('beankeep.php'),
]);

$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
}
}
36 changes: 0 additions & 36 deletions src/Enums/JournalPeriod.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,40 +76,4 @@ public static function fromString(string $value): static
'dec', 'december' => static::Dec,
};
}

public static function get(?CarbonPeriod $period): CarbonPeriod
{
if (is_null($period)) {
return static::defaultPeriod();
}

return $period;
}

public static function defaultPeriod(): CarbonPeriod
{
if (config('beankeep.default-period')) {
return static::defaultPeriodFromConfig();
}

return static::defaultPeriodThisYear();
}

private static function defaultPeriodFromConfig(): CarbonPeriod {
$startMonthStr = config('beankeep.default-period');

$journalPeriod = JournalPeriod::fromString(
config('beankeep.default-period'),
);

return $journalPeriod->toCarbonPeriod();
}

private static function defaultPeriodThisYear(): CarbonPeriod
{
$startOfYear = CarbonImmutable::now()->startOfYear();
$endOfYear = CarbonImmutable::now()->endOfYear();

return $startOfYear->daysUntil($endOfYear);
}
}
6 changes: 5 additions & 1 deletion src/Models/Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ public function lineItems(): HasMany

public function ledger(?CarbonPeriod $period = null): Ledger
{
$period ??= $this->journal->currentPeriod();

return new Ledger(
account: $this,
startingBalance: $this->openingBalance($period),
Expand All @@ -55,6 +57,8 @@ public function ledger(?CarbonPeriod $period = null): Ledger

public function balance(?CarbonPeriod $period = null): int
{
$period ??= $this->journal->currentPeriod();

$debitSum = $this->lineItems()->ledgerEntries($period)->sum('debit');
$creditSum = $this->lineItems()->ledgerEntries($period)->sum('credit');

Expand All @@ -68,7 +72,7 @@ public function balance(?CarbonPeriod $period = null): int

public function openingBalance(?CarbonPeriod $period = null): int
{
$period = JournalPeriod::get($period);
$period ??= $this->journal->currentPeriod();

$debitSum = $this->lineItems()
->ledgerEntries(priorTo: $period)
Expand Down
6 changes: 6 additions & 0 deletions src/Models/Journal.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace STS\Beankeep\Models;

use Carbon\CarbonPeriod;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasMany;
use STS\Beankeep\Database\Factories\JournalFactory;
Expand All @@ -28,6 +29,11 @@ protected static function newFactory()
return JournalFactory::new();
}

public function currentPeriod(): CarbonPeriod
{
return $this->period->toCarbonPeriod();
}

public function accounts(): HasMany
{
return $this->hasMany(Account::class);
Expand Down
16 changes: 5 additions & 11 deletions src/Models/LineItem.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ public function scopeLedgerEntries(
?CarbonPeriod $period = null,
null|string|Carbon|CarbonImmutable|CarbonPeriod $priorTo = null,
): void {
if ($period && $priorTo) {
throw new ValueError('You cannot specify both a period and '
if (!($period xor $priorTo)) {
throw new ValueError('You must specify a period or a'
. 'priorTo argument.');
}

Expand All @@ -96,10 +96,8 @@ public function scopeLedgerEntries(

public function scopeLedgerEntriesForPeriod(
Builder $query,
?CarbonPeriod $period = null,
CarbonPeriod $period,
): void {
$period = JournalPeriod::get($period);

$query->whereHas('transaction', fn (Builder $query) => $query
->whereBetween('date', $period)
->where('posted', true));
Expand All @@ -116,12 +114,8 @@ public function scopeLedgerEntriesPriorTo(
->where('posted', true));
}

public function scopePeriod(
Builder $query,
?CarbonPeriod $period = null,
): void {
$period = JournalPeriod::get($period);

public function scopePeriod(Builder $query, CarbonPeriod $period): void
{
$query->whereHas('transaction', fn (Builder $query) => $query
->whereBetween('date', $period));
}
Expand Down
Loading

0 comments on commit 849823d

Please sign in to comment.