chore: code cleanup.

This commit is contained in:
James Cole
2023-05-29 13:56:55 +02:00
parent 7f7644c92f
commit 1b52147a05
295 changed files with 12418 additions and 12324 deletions

View File

@@ -42,8 +42,8 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Storage;
/**
@@ -54,6 +54,16 @@ class AccountRepository implements AccountRepositoryInterface
{
private User $user;
/**
* @param array $types
*
* @return int
*/
public function count(array $types): int
{
return $this->user->accounts()->accountTypeIn($types)->count();
}
/**
* Moved here from account CRUD.
*
@@ -107,6 +117,16 @@ class AccountRepository implements AccountRepositoryInterface
return $result;
}
/**
* @param int $accountId
*
* @return Account|null
*/
public function find(int $accountId): ?Account
{
return $this->user->accounts()->find($accountId);
}
/**
* @inheritDoc
*/
@@ -180,6 +200,28 @@ class AccountRepository implements AccountRepositoryInterface
return $account;
}
/**
* @param Account $account
*
* @return TransactionCurrency|null
*/
public function getAccountCurrency(Account $account): ?TransactionCurrency
{
$type = $account->accountType->type;
$list = config('firefly.valid_currency_account_types');
// return null if not in this list.
if (!in_array($type, $list, true)) {
return null;
}
$currencyId = (int)$this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) {
return TransactionCurrency::find($currencyId);
}
return null;
}
/**
* Return account type or null if not found.
*
@@ -211,6 +253,38 @@ class AccountRepository implements AccountRepositoryInterface
return $query->get(['accounts.*']);
}
/**
* @param array $types
* @param array|null $sort
*
* @return Collection
*/
public function getAccountsByType(array $types, ?array $sort = []): Collection
{
$res = array_intersect([AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT], $types);
$query = $this->user->accounts();
if (0 !== count($types)) {
$query->accountTypeIn($types);
}
// add sort parameters. At this point they're filtered to allowed fields to sort by:
if (0 !== count($sort)) {
foreach ($sort as $param) {
$query->orderBy($param[0], $param[1]);
}
}
if (0 === count($sort)) {
if (0 !== count($res)) {
$query->orderBy('accounts.order', 'ASC');
}
$query->orderBy('accounts.active', 'DESC');
$query->orderBy('accounts.name', 'ASC');
}
return $query->get(['accounts.*']);
}
/**
* @param array $types
*
@@ -275,16 +349,6 @@ class AccountRepository implements AccountRepositoryInterface
return $factory->findOrCreate('Cash account', $type->type);
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @inheritDoc
*/
@@ -335,6 +399,31 @@ class AccountRepository implements AccountRepositoryInterface
return $account->locations()->first();
}
/**
* Return meta value for account. Null if not found.
*
* @param Account $account
* @param string $field
*
* @return null|string
*/
public function getMetaValue(Account $account, string $field): ?string
{
$result = $account->accountMeta->filter(
function (AccountMeta $meta) use ($field) {
return strtolower($meta->name) === strtolower($field);
}
);
if (0 === $result->count()) {
return null;
}
if (1 === $result->count()) {
return (string)$result->first()->data;
}
return null;
}
/**
* Get note text or null.
*
@@ -353,6 +442,19 @@ class AccountRepository implements AccountRepositoryInterface
return $note->text;
}
/**
* @param Account $account
*
* @return TransactionJournal|null
*/
public function getOpeningBalance(Account $account): ?TransactionJournal
{
return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->transactionTypes([TransactionType::OPENING_BALANCE])
->first(['transaction_journals.*']);
}
/**
* Returns the amount of the opening balance for this account.
*
@@ -409,19 +511,6 @@ class AccountRepository implements AccountRepositoryInterface
return $journal?->transactionGroup;
}
/**
* @param Account $account
*
* @return TransactionJournal|null
*/
public function getOpeningBalance(Account $account): ?TransactionJournal
{
return TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
->where('transactions.account_id', $account->id)
->transactionTypes([TransactionType::OPENING_BALANCE])
->first(['transaction_journals.*']);
}
/**
* @param Account $account
*
@@ -475,73 +564,6 @@ class AccountRepository implements AccountRepositoryInterface
return $factory->create($data);
}
/**
* @param Account $account
*
* @return TransactionCurrency|null
*/
public function getAccountCurrency(Account $account): ?TransactionCurrency
{
$type = $account->accountType->type;
$list = config('firefly.valid_currency_account_types');
// return null if not in this list.
if (!in_array($type, $list, true)) {
return null;
}
$currencyId = (int)$this->getMetaValue($account, 'currency_id');
if ($currencyId > 0) {
return TransactionCurrency::find($currencyId);
}
return null;
}
/**
* Return meta value for account. Null if not found.
*
* @param Account $account
* @param string $field
*
* @return null|string
*/
public function getMetaValue(Account $account, string $field): ?string
{
$result = $account->accountMeta->filter(
function (AccountMeta $meta) use ($field) {
return strtolower($meta->name) === strtolower($field);
}
);
if (0 === $result->count()) {
return null;
}
if (1 === $result->count()) {
return (string)$result->first()->data;
}
return null;
}
/**
* @param array $types
*
* @return int
*/
public function count(array $types): int
{
return $this->user->accounts()->accountTypeIn($types)->count();
}
/**
* @param int $accountId
*
* @return Account|null
*/
public function find(int $accountId): ?Account
{
return $this->user->accounts()->find($accountId);
}
/**
* @inheritDoc
*/
@@ -595,52 +617,6 @@ class AccountRepository implements AccountRepositoryInterface
return $order;
}
/**
* @param array $types
* @param array|null $sort
*
* @return Collection
*/
public function getAccountsByType(array $types, ?array $sort = []): Collection
{
$res = array_intersect([AccountType::ASSET, AccountType::MORTGAGE, AccountType::LOAN, AccountType::DEBT], $types);
$query = $this->user->accounts();
if (0 !== count($types)) {
$query->accountTypeIn($types);
}
// add sort parameters. At this point they're filtered to allowed fields to sort by:
if (0 !== count($sort)) {
foreach ($sort as $param) {
$query->orderBy($param[0], $param[1]);
}
}
if (0 === count($sort)) {
if (0 !== count($res)) {
$query->orderBy('accounts.order', 'ASC');
}
$query->orderBy('accounts.active', 'DESC');
$query->orderBy('accounts.name', 'ASC');
}
return $query->get(['accounts.*']);
}
/**
* Returns the date of the very first transaction in this account.
*
* @param Account $account
*
* @return Carbon|null
*/
public function oldestJournalDate(Account $account): ?Carbon
{
$journal = $this->oldestJournal($account);
return $journal?->date;
}
/**
* Returns the date of the very first transaction in this account.
*
@@ -664,6 +640,20 @@ class AccountRepository implements AccountRepositoryInterface
return null;
}
/**
* Returns the date of the very first transaction in this account.
*
* @param Account $account
*
* @return Carbon|null
*/
public function oldestJournalDate(Account $account): ?Carbon
{
$journal = $this->oldestJournal($account);
return $journal?->date;
}
/**
* @inheritDoc
*/
@@ -764,6 +754,16 @@ class AccountRepository implements AccountRepositoryInterface
return $dbQuery->take($limit)->get(['accounts.*']);
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*

View File

@@ -32,8 +32,8 @@ use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class AccountTasker.
@@ -154,6 +154,50 @@ class AccountTasker implements AccountTaskerInterface
return $report;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
* @throws FireflyException
* @throws JsonException
*/
public function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): array
{
// get all incomes for the given accounts in the given period!
// also transfers!
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setDestinationAccounts($accounts)->setRange($start, $end);
$collector->excludeSourceAccounts($accounts);
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])->withAccountInformation();
$report = $this->groupIncomeBySource($collector->getExtractedJournals());
// sort the result
// Obtain a list of columns
$sum = [];
foreach ($report['accounts'] as $accountId => $row) {
$sum[$accountId] = (float)$row['sum']; // intentional float
}
array_multisort($sum, SORT_DESC, $report['accounts']);
return $report;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $array
*
@@ -217,40 +261,6 @@ class AccountTasker implements AccountTaskerInterface
return $report;
}
/**
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return array
* @throws FireflyException
* @throws JsonException
*/
public function getIncomeReport(Carbon $start, Carbon $end, Collection $accounts): array
{
// get all incomes for the given accounts in the given period!
// also transfers!
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setDestinationAccounts($accounts)->setRange($start, $end);
$collector->excludeSourceAccounts($accounts);
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])->withAccountInformation();
$report = $this->groupIncomeBySource($collector->getExtractedJournals());
// sort the result
// Obtain a list of columns
$sum = [];
foreach ($report['accounts'] as $accountId => $row) {
$sum[$accountId] = (float)$row['sum']; // intentional float
}
array_multisort($sum, SORT_DESC, $report['accounts']);
return $report;
}
/**
* @param array $array
*
@@ -312,14 +322,4 @@ class AccountTasker implements AccountTaskerInterface
return $report;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
}

View File

@@ -57,80 +57,6 @@ class OperationsRepository implements OperationsRepositoryInterface
return $this->sortByCurrency($journals, 'negative');
}
/**
* Collect transactions with some parameters
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* @param string $type
*
* @return array
*/
private function getTransactions(Carbon $start, Carbon $end, Collection $accounts, string $type): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([$type]);
$collector->setBothAccounts($accounts);
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation()->withTagInformation();
return $collector->getExtractedJournals();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $journals
* @param string $direction
*
* @return array
*/
private function sortByCurrency(array $journals, string $direction): array
{
$array = [];
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$journalId = (int)$journal['transaction_journal_id'];
$array[$currencyId] = $array[$currencyId] ?? [
'currency_id' => $journal['currency_id'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'transaction_journals' => [],
];
$array[$currencyId]['transaction_journals'][$journalId] = [
'amount' => app('steam')->$direction((string)$journal['amount']),
'date' => $journal['date'],
'transaction_journal_id' => $journalId,
'budget_name' => $journal['budget_name'],
'category_name' => $journal['category_name'],
'source_account_id' => $journal['source_account_id'],
'source_account_name' => $journal['source_account_name'],
'source_account_iban' => $journal['source_account_iban'],
'destination_account_id' => $journal['destination_account_id'],
'destination_account_name' => $journal['destination_account_name'],
'destination_account_iban' => $journal['destination_account_iban'],
'tags' => $journal['tags'],
'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'],
];
}
return $array;
}
/**
* This method returns a list of all the deposit transaction journals (as arrays) set in that period
* which have the specified accounts. It's grouped per currency, with as few details in the array
@@ -149,6 +75,16 @@ class OperationsRepository implements OperationsRepositoryInterface
return $this->sortByCurrency($journals, 'positive');
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @inheritDoc
*/
@@ -164,6 +100,112 @@ class OperationsRepository implements OperationsRepositoryInterface
return $this->groupByCurrency($journals, 'negative');
}
/**
* @inheritDoc
*/
public function sumExpensesByDestination(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $expense = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::WITHDRAWAL, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'destination', 'negative');
}
/**
* @inheritDoc
*/
public function sumExpensesBySource(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $expense = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::WITHDRAWAL, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'source', 'negative');
}
/**
* @inheritDoc
*/
public function sumIncome(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $revenue = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::DEPOSIT, $start, $end, $accounts, $revenue, $currency);
return $this->groupByCurrency($journals, 'positive');
}
/**
* @inheritDoc
*/
public function sumIncomeByDestination(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $revenue = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::DEPOSIT, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'destination', 'positive');
}
/**
* @inheritDoc
*/
public function sumIncomeBySource(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $revenue = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::DEPOSIT, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'source', 'positive');
}
/**
* @inheritDoc
*/
public function sumTransfers(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array
{
$journals = $this->getTransactionsForSum(TransactionType::TRANSFER, $start, $end, $accounts, null, $currency);
return $this->groupByEither($journals);
}
/**
* Collect transactions with some parameters
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
* @param string $type
*
* @return array
*/
private function getTransactions(Carbon $start, Carbon $end, Collection $accounts, string $type): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user)->setRange($start, $end)->setTypes([$type]);
$collector->setBothAccounts($accounts);
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation()->withTagInformation();
return $collector->getExtractedJournals();
}
/**
* @param Carbon $start
* @param Carbon $end
@@ -288,21 +330,6 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* @inheritDoc
*/
public function sumExpensesByDestination(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $expense = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::WITHDRAWAL, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'destination', 'negative');
}
/**
* @param array $journals
* @param string $direction
@@ -350,76 +377,6 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* @inheritDoc
*/
public function sumExpensesBySource(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $expense = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::WITHDRAWAL, $start, $end, $accounts, $expense, $currency);
return $this->groupByDirection($journals, 'source', 'negative');
}
/**
* @inheritDoc
*/
public function sumIncome(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $revenue = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::DEPOSIT, $start, $end, $accounts, $revenue, $currency);
return $this->groupByCurrency($journals, 'positive');
}
/**
* @inheritDoc
*/
public function sumIncomeByDestination(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $revenue = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::DEPOSIT, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'destination', 'positive');
}
/**
* @inheritDoc
*/
public function sumIncomeBySource(
Carbon $start,
Carbon $end,
?Collection $accounts = null,
?Collection $revenue = null,
?TransactionCurrency $currency = null
): array {
$journals = $this->getTransactionsForSum(TransactionType::DEPOSIT, $start, $end, $accounts, $revenue, $currency);
return $this->groupByDirection($journals, 'source', 'positive');
}
/**
* @inheritDoc
*/
public function sumTransfers(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array
{
$journals = $this->getTransactionsForSum(TransactionType::TRANSFER, $start, $end, $accounts, null, $currency);
return $this->groupByEither($journals);
}
/**
* @param array $journals
*
@@ -540,4 +497,47 @@ class OperationsRepository implements OperationsRepositoryInterface
return $return;
}
/**
* @param array $journals
* @param string $direction
*
* @return array
*/
private function sortByCurrency(array $journals, string $direction): array
{
$array = [];
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
$journalId = (int)$journal['transaction_journal_id'];
$array[$currencyId] = $array[$currencyId] ?? [
'currency_id' => $journal['currency_id'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'transaction_journals' => [],
];
$array[$currencyId]['transaction_journals'][$journalId] = [
'amount' => app('steam')->$direction((string)$journal['amount']),
'date' => $journal['date'],
'transaction_journal_id' => $journalId,
'budget_name' => $journal['budget_name'],
'category_name' => $journal['category_name'],
'source_account_id' => $journal['source_account_id'],
'source_account_name' => $journal['source_account_name'],
'source_account_iban' => $journal['source_account_iban'],
'destination_account_id' => $journal['destination_account_id'],
'destination_account_name' => $journal['destination_account_name'],
'destination_account_iban' => $journal['destination_account_iban'],
'tags' => $journal['tags'],
'description' => $journal['description'],
'transaction_group_id' => $journal['transaction_group_id'],
];
}
return $array;
}
}

View File

@@ -40,11 +40,11 @@ class AccountRepository implements AccountRepositoryInterface
{
// search by group, not by user
$dbQuery = $this->userGroup->accounts()
->where('active', true)
->orderBy('accounts.order', 'ASC')
->orderBy('accounts.account_type_id', 'ASC')
->orderBy('accounts.name', 'ASC')
->with(['accountType']);
->where('active', true)
->orderBy('accounts.order', 'ASC')
->orderBy('accounts.account_type_id', 'ASC')
->orderBy('accounts.name', 'ASC')
->with(['accountType']);
if ('' !== $query) {
// split query on spaces just in case:
$parts = explode(' ', $query);

View File

@@ -34,9 +34,9 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use League\Flysystem\UnableToDeleteFile;
use Illuminate\Support\Facades\Log;
use LogicException;
/**
@@ -70,6 +70,27 @@ class AttachmentRepository implements AttachmentRepositoryInterface
return true;
}
/**
* @param Attachment $attachment
*
* @return bool
*/
public function exists(Attachment $attachment): bool
{
/** @var Storage $disk */
$disk = Storage::disk('upload');
return $disk->exists($attachment->fileName());
}
/**
* @return Collection
*/
public function get(): Collection
{
return $this->user->attachments()->get();
}
/**
* @param Attachment $attachment
*
@@ -95,27 +116,6 @@ class AttachmentRepository implements AttachmentRepositoryInterface
return $unencryptedContent;
}
/**
* @param Attachment $attachment
*
* @return bool
*/
public function exists(Attachment $attachment): bool
{
/** @var Storage $disk */
$disk = Storage::disk('upload');
return $disk->exists($attachment->fileName());
}
/**
* @return Collection
*/
public function get(): Collection
{
return $this->user->attachments()->get();
}
/**
* Get attachment note text or empty string.
*
@@ -133,6 +133,16 @@ class AttachmentRepository implements AttachmentRepositoryInterface
return null;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
@@ -152,16 +162,6 @@ class AttachmentRepository implements AttachmentRepositoryInterface
return $result;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param Attachment $attachment
* @param array $data

View File

@@ -43,8 +43,8 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Storage;
/**
@@ -108,107 +108,6 @@ class BillRepository implements BillRepositoryInterface
return $bills;
}
/**
* @return Collection
*/
public function getActiveBills(): Collection
{
return $this->user->bills()
->where('active', true)
->orderBy('bills.name', 'ASC')
->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount'),]);
}
/**
* Between start and end, tells you on which date(s) the bill is expected to hit.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection
{
$set = new Collection();
$currentStart = clone $start;
//Log::debug(sprintf('Now at bill "%s" (%s)', $bill->name, $bill->repeat_freq));
//Log::debug(sprintf('First currentstart is %s', $currentStart->format('Y-m-d')));
while ($currentStart <= $end) {
//Log::debug(sprintf('Currentstart is now %s.', $currentStart->format('Y-m-d')));
$nextExpectedMatch = $this->nextDateMatch($bill, $currentStart);
//Log::debug(sprintf('Next Date match after %s is %s', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
if ($nextExpectedMatch > $end) {// If nextExpectedMatch is after end, we continue
break;
}
$set->push(clone $nextExpectedMatch);
//Log::debug(sprintf('Now %d dates in set.', $set->count()));
$nextExpectedMatch->addDay();
//Log::debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
$currentStart = clone $nextExpectedMatch;
}
return $set;
}
/**
* Given a bill and a date, this method will tell you at which moment this bill expects its next
* transaction. Whether or not it is there already, is not relevant.
*
* @param Bill $bill
* @param Carbon $date
*
* @return Carbon
*/
public function nextDateMatch(Bill $bill, Carbon $date): Carbon
{
$cache = new CacheProperties();
$cache->addProperty($bill->id);
$cache->addProperty('nextDateMatch');
$cache->addProperty($date);
if ($cache->has()) {
return $cache->get();
}
// find the most recent date for this bill NOT in the future. Cache this date:
$start = clone $bill->date;
while ($start < $date) {
$start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
}
$cache->store($start);
return $start;
}
/**
* @param array $data
*
* @return Bill
* @throws FireflyException
* @throws JsonException
*/
public function store(array $data): Bill
{
/** @var BillFactory $factory */
$factory = app(BillFactory::class);
$factory->setUser($this->user);
return $factory->create($data);
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* Correct order of piggies in case of issues.
*/
@@ -249,6 +148,18 @@ class BillRepository implements BillRepositoryInterface
$this->user->bills()->delete();
}
/**
* Find a bill by ID.
*
* @param int $billId
*
* @return Bill|null
*/
public function find(int $billId): ?Bill
{
return $this->user->bills()->find($billId);
}
/**
* Find bill by parameters.
*
@@ -280,18 +191,6 @@ class BillRepository implements BillRepositoryInterface
return null;
}
/**
* Find a bill by ID.
*
* @param int $billId
*
* @return Bill|null
*/
public function find(int $billId): ?Bill
{
return $this->user->bills()->find($billId);
}
/**
* Find a bill by name.
*
@@ -304,6 +203,17 @@ class BillRepository implements BillRepositoryInterface
return $this->user->bills()->where('name', $name)->first(['bills.*']);
}
/**
* @return Collection
*/
public function getActiveBills(): Collection
{
return $this->user->bills()
->where('active', true)
->orderBy('bills.name', 'ASC')
->get(['bills.*', DB::raw('((bills.amount_min + bills.amount_max) / 2) AS expectedAmount'),]);
}
/**
* Get all attachments.
*
@@ -623,13 +533,48 @@ class BillRepository implements BillRepositoryInterface
return $bill->transactionJournals()
->before($end)->after($start)->get(
[
'transaction_journals.id',
'transaction_journals.date',
'transaction_journals.transaction_group_id',
]
'transaction_journals.id',
'transaction_journals.date',
'transaction_journals.transaction_group_id',
]
);
}
/**
* Between start and end, tells you on which date(s) the bill is expected to hit.
*
* @param Bill $bill
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
*/
public function getPayDatesInRange(Bill $bill, Carbon $start, Carbon $end): Collection
{
$set = new Collection();
$currentStart = clone $start;
//Log::debug(sprintf('Now at bill "%s" (%s)', $bill->name, $bill->repeat_freq));
//Log::debug(sprintf('First currentstart is %s', $currentStart->format('Y-m-d')));
while ($currentStart <= $end) {
//Log::debug(sprintf('Currentstart is now %s.', $currentStart->format('Y-m-d')));
$nextExpectedMatch = $this->nextDateMatch($bill, $currentStart);
//Log::debug(sprintf('Next Date match after %s is %s', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
if ($nextExpectedMatch > $end) {// If nextExpectedMatch is after end, we continue
break;
}
$set->push(clone $nextExpectedMatch);
//Log::debug(sprintf('Now %d dates in set.', $set->count()));
$nextExpectedMatch->addDay();
//Log::debug(sprintf('Currentstart (%s) has become %s.', $currentStart->format('Y-m-d'), $nextExpectedMatch->format('Y-m-d')));
$currentStart = clone $nextExpectedMatch;
}
return $set;
}
/**
* Return all rules for one bill
*
@@ -747,6 +692,35 @@ class BillRepository implements BillRepositoryInterface
}
}
/**
* Given a bill and a date, this method will tell you at which moment this bill expects its next
* transaction. Whether or not it is there already, is not relevant.
*
* @param Bill $bill
* @param Carbon $date
*
* @return Carbon
*/
public function nextDateMatch(Bill $bill, Carbon $date): Carbon
{
$cache = new CacheProperties();
$cache->addProperty($bill->id);
$cache->addProperty('nextDateMatch');
$cache->addProperty($date);
if ($cache->has()) {
return $cache->get();
}
// find the most recent date for this bill NOT in the future. Cache this date:
$start = clone $bill->date;
while ($start < $date) {
$start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
}
$cache->store($start);
return $start;
}
/**
* Given the date in $date, this method will return a moment in the future where the bill is expected to be paid.
*
@@ -839,6 +813,32 @@ class BillRepository implements BillRepositoryInterface
$bill->save();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
* @return Bill
* @throws FireflyException
* @throws JsonException
*/
public function store(array $data): Bill
{
/** @var BillFactory $factory */
$factory = app(BillFactory::class);
$factory->setUser($this->user);
return $factory->create($data);
}
/**
* @inheritDoc
*/

View File

@@ -55,14 +55,6 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
$availableBudget->delete();
}
/**
* @inheritDoc
*/
public function findById(int $id): ?AvailableBudget
{
return $this->user->availableBudgets->find($id);
}
/**
* Find existing AB.
*
@@ -81,6 +73,37 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
->first();
}
/**
* @inheritDoc
*/
public function findById(int $id): ?AvailableBudget
{
return $this->user->availableBudgets->find($id);
}
/**
* Return a list of all available budgets (in all currencies) (for the selected period).
*
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return Collection
*/
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
{
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
if (null !== $start && null !== $end) {
$query->where(
static function (Builder $q1) use ($start, $end) {
$q1->where('start_date', '=', $start->format('Y-m-d'));
$q1->where('end_date', '=', $end->format('Y-m-d'));
}
);
}
return $query->get(['available_budgets.*']);
}
/**
* @param TransactionCurrency $currency
* @param Carbon $start
@@ -122,29 +145,6 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface
return $return;
}
/**
* Return a list of all available budgets (in all currencies) (for the selected period).
*
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return Collection
*/
public function get(?Carbon $start = null, ?Carbon $end = null): Collection
{
$query = $this->user->availableBudgets()->with(['transactionCurrency']);
if (null !== $start && null !== $end) {
$query->where(
static function (Builder $q1) use ($start, $end) {
$q1->where('start_date', '=', $start->format('Y-m-d'));
$q1->where('end_date', '=', $end->format('Y-m-d'));
}
);
}
return $query->get(['available_budgets.*']);
}
/**
* Returns all available budget objects.
*

View File

@@ -33,8 +33,8 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
*
@@ -128,19 +128,19 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
}
/**
* @param Budget $budget
* @param TransactionCurrency $currency
* @param Carbon|null $start
* @param Carbon|null $end
* @param Carbon $start
* @param Carbon $end
*
* @return Collection
* @return BudgetLimit|null
*/
public function getAllBudgetLimitsByCurrency(TransactionCurrency $currency, Carbon $start = null, Carbon $end = null): Collection
public function find(Budget $budget, TransactionCurrency $currency, Carbon $start, Carbon $end): ?BudgetLimit
{
return $this->getAllBudgetLimits($start, $end)->filter(
static function (BudgetLimit $budgetLimit) use ($currency) {
return $budgetLimit->transaction_currency_id === $currency->id;
}
);
return $budget->budgetlimits()
->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->first();
}
/**
@@ -211,6 +211,22 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
)->get(['budget_limits.*']);
}
/**
* @param TransactionCurrency $currency
* @param Carbon|null $start
* @param Carbon|null $end
*
* @return Collection
*/
public function getAllBudgetLimitsByCurrency(TransactionCurrency $currency, Carbon $start = null, Carbon $end = null): Collection
{
return $this->getAllBudgetLimits($start, $end)->filter(
static function (BudgetLimit $budgetLimit) use ($currency) {
return $budgetLimit->transaction_currency_id === $currency->id;
}
);
}
/**
* @param Budget $budget
* @param Carbon|null $start
@@ -330,22 +346,6 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
return $limit;
}
/**
* @param Budget $budget
* @param TransactionCurrency $currency
* @param Carbon $start
* @param Carbon $end
*
* @return BudgetLimit|null
*/
public function find(Budget $budget, TransactionCurrency $currency, Carbon $start, Carbon $end): ?BudgetLimit
{
return $budget->budgetlimits()
->where('transaction_currency_id', $currency->id)
->where('start_date', $start->format('Y-m-d'))
->where('end_date', $end->format('Y-m-d'))->first();
}
/**
* @param BudgetLimit $budgetLimit
* @param array $data

View File

@@ -44,8 +44,8 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Storage;
/**
@@ -144,65 +144,6 @@ class BudgetRepository implements BudgetRepositoryInterface
return $return;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @return Collection
*/
public function getActiveBudgets(): Collection
{
return $this->user->budgets()->where('active', true)
->orderBy('order', 'ASC')
->orderBy('name', 'ASC')
->get();
}
/**
* How many days of this budget limit are between start and end?
*
* @param BudgetLimit $limit
* @param Carbon $start
* @param Carbon $end
* @return int
*/
private function daysInOverlap(BudgetLimit $limit, Carbon $start, Carbon $end): int
{
// start1 = $start
// start2 = $limit->start_date
// start1 = $end
// start2 = $limit->end_date
// limit is larger than start and end (inclusive)
// |-----------|
// |----------------|
if ($start->gte($limit->start_date) && $end->lte($limit->end_date)) {
return $start->diffInDays($end) + 1; // add one day
}
// limit starts earlier and limit ends first:
// |-----------|
// |-------|
if ($limit->start_date->lte($start) && $limit->end_date->lte($end)) {
// return days in the range $start-$limit_end
return $start->diffInDays($limit->end_date) + 1; // add one day, the day itself
}
// limit starts later and limit ends earlier
// |-----------|
// |-------|
if ($limit->start_date->gte($start) && $limit->end_date->gte($end)) {
// return days in the range $limit_start - $end
return $limit->start_date->diffInDays($end) + 1; // add one day, the day itself
}
return 0;
}
/**
* @inheritDoc
*/
@@ -280,190 +221,6 @@ class BudgetRepository implements BudgetRepositoryInterface
return true;
}
/**
* @param Budget $budget
* @param array $data
*
* @return Budget
* @throws FireflyException
* @throws JsonException
*/
public function update(Budget $budget, array $data): Budget
{
Log::debug('Now in update()');
$oldName = $budget->name;
if (array_key_exists('name', $data)) {
$budget->name = $data['name'];
$this->updateRuleActions($oldName, $budget->name);
$this->updateRuleTriggers($oldName, $budget->name);
}
if (array_key_exists('active', $data)) {
$budget->active = $data['active'];
}
if (array_key_exists('notes', $data)) {
$this->setNoteText($budget, (string)$data['notes']);
}
$budget->save();
// update or create auto-budget:
$autoBudget = $this->getAutoBudget($budget);
// first things first: delete when no longer required:
$autoBudgetType = array_key_exists('auto_budget_type', $data) ? $data['auto_budget_type'] : null;
if (0 === $autoBudgetType && null !== $autoBudget) {
// delete!
$autoBudget->delete();
return $budget;
}
if (0 === $autoBudgetType && null === $autoBudget) {
return $budget;
}
if (null === $autoBudgetType && null === $autoBudget) {
return $budget;
}
$this->updateAutoBudget($budget, $data);
return $budget;
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleActions(string $oldName, string $newName): void
{
$types = ['set_budget',];
$actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_actions.action_type', $types)
->where('rule_actions.action_value', $oldName)
->get(['rule_actions.*']);
Log::debug(sprintf('Found %d actions to update.', $actions->count()));
/** @var RuleAction $action */
foreach ($actions as $action) {
$action->action_value = $newName;
$action->save();
Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value));
}
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleTriggers(string $oldName, string $newName): void
{
$types = ['budget_is',];
$triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_triggers.trigger_type', $types)
->where('rule_triggers.trigger_value', $oldName)
->get(['rule_triggers.*']);
Log::debug(sprintf('Found %d triggers to update.', $triggers->count()));
/** @var RuleTrigger $trigger */
foreach ($triggers as $trigger) {
$trigger->trigger_value = $newName;
$trigger->save();
Log::debug(sprintf('Updated trigger %d: %s', $trigger->id, $trigger->trigger_value));
}
}
/**
* @param Budget $budget
* @param string $text
* @return void
*/
private function setNoteText(Budget $budget, string $text): void
{
$dbNote = $budget->notes()->first();
if ('' !== $text) {
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($budget);
}
$dbNote->text = trim($text);
$dbNote->save();
return;
}
if (null !== $dbNote) {
$dbNote->delete();
}
}
/**
* @inheritDoc
*/
public function getAutoBudget(Budget $budget): ?AutoBudget
{
return $budget->autoBudgets()->first();
}
/**
* @param Budget $budget
* @param array $data
* @throws FireflyException
* @throws JsonException
*/
private function updateAutoBudget(Budget $budget, array $data): void
{
// update or create auto-budget:
$autoBudget = $this->getAutoBudget($budget);
// grab default currency:
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
if (null === $autoBudget) {
// at this point it's a blind assumption auto_budget_type is 1 or 2.
$autoBudget = new AutoBudget();
$autoBudget->auto_budget_type = $data['auto_budget_type'];
$autoBudget->budget_id = $budget->id;
$autoBudget->transaction_currency_id = $currency->id;
}
// set or update the currency.
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
$repos = app(CurrencyRepositoryInterface::class);
$currencyId = (int)($data['currency_id'] ?? 0);
$currencyCode = (string)($data['currency_code'] ?? '');
$currency = $repos->find($currencyId);
if (null === $currency) {
$currency = $repos->findByCodeNull($currencyCode);
}
if (null !== $currency) {
$autoBudget->transaction_currency_id = $currency->id;
}
}
// change values if submitted or presented:
if (array_key_exists('auto_budget_type', $data)) {
$autoBudget->auto_budget_type = $data['auto_budget_type'];
}
if (array_key_exists('auto_budget_amount', $data)) {
$autoBudget->amount = $data['auto_budget_amount'];
}
if (array_key_exists('auto_budget_period', $data)) {
$autoBudget->period = $data['auto_budget_period'];
}
$autoBudget->save();
}
/**
* Find a budget or return NULL
*
* @param int|null $budgetId |null
*
* @return Budget|null
*/
public function find(int $budgetId = null): ?Budget
{
return $this->user->budgets()->find($budgetId);
}
/**
* @param Budget $budget
*
@@ -494,15 +251,6 @@ class BudgetRepository implements BudgetRepositoryInterface
}
}
/**
* @return Collection
*/
public function getBudgets(): Collection
{
return $this->user->budgets()->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->get();
}
/**
* @inheritDoc
*/
@@ -514,6 +262,18 @@ class BudgetRepository implements BudgetRepositoryInterface
}
}
/**
* Find a budget or return NULL
*
* @param int|null $budgetId |null
*
* @return Budget|null
*/
public function find(int $budgetId = null): ?Budget
{
return $this->user->budgets()->find($budgetId);
}
/**
* @param int|null $budgetId
* @param string|null $budgetName
@@ -572,6 +332,17 @@ class BudgetRepository implements BudgetRepositoryInterface
return null;
}
/**
* @return Collection
*/
public function getActiveBudgets(): Collection
{
return $this->user->budgets()->where('active', true)
->orderBy('order', 'ASC')
->orderBy('name', 'ASC')
->get();
}
/**
* @inheritDoc
*/
@@ -593,6 +364,23 @@ class BudgetRepository implements BudgetRepositoryInterface
);
}
/**
* @inheritDoc
*/
public function getAutoBudget(Budget $budget): ?AutoBudget
{
return $budget->autoBudgets()->first();
}
/**
* @return Collection
*/
public function getBudgets(): Collection
{
return $this->user->budgets()->orderBy('order', 'ASC')
->orderBy('name', 'ASC')->get();
}
/**
* Get all budgets with these ID's.
*
@@ -615,6 +403,11 @@ class BudgetRepository implements BudgetRepositoryInterface
->orderBy('name', 'ASC')->where('active', 0)->get();
}
public function getMaxOrder(): int
{
return (int)$this->user->budgets()->max('order');
}
/**
* @inheritDoc
*/
@@ -656,6 +449,16 @@ class BudgetRepository implements BudgetRepositoryInterface
$budget->save();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @inheritDoc
*/
@@ -829,7 +632,7 @@ class BudgetRepository implements BudgetRepositoryInterface
if ('rollover' === $type) {
$type = AutoBudget::AUTO_BUDGET_ROLLOVER;
}
if('adjusted' === $type) {
if ('adjusted' === $type) {
$type = AutoBudget::AUTO_BUDGET_ADJUSTED;
}
@@ -873,8 +676,205 @@ class BudgetRepository implements BudgetRepositoryInterface
return $newBudget;
}
public function getMaxOrder(): int
/**
* @param Budget $budget
* @param array $data
*
* @return Budget
* @throws FireflyException
* @throws JsonException
*/
public function update(Budget $budget, array $data): Budget
{
return (int)$this->user->budgets()->max('order');
Log::debug('Now in update()');
$oldName = $budget->name;
if (array_key_exists('name', $data)) {
$budget->name = $data['name'];
$this->updateRuleActions($oldName, $budget->name);
$this->updateRuleTriggers($oldName, $budget->name);
}
if (array_key_exists('active', $data)) {
$budget->active = $data['active'];
}
if (array_key_exists('notes', $data)) {
$this->setNoteText($budget, (string)$data['notes']);
}
$budget->save();
// update or create auto-budget:
$autoBudget = $this->getAutoBudget($budget);
// first things first: delete when no longer required:
$autoBudgetType = array_key_exists('auto_budget_type', $data) ? $data['auto_budget_type'] : null;
if (0 === $autoBudgetType && null !== $autoBudget) {
// delete!
$autoBudget->delete();
return $budget;
}
if (0 === $autoBudgetType && null === $autoBudget) {
return $budget;
}
if (null === $autoBudgetType && null === $autoBudget) {
return $budget;
}
$this->updateAutoBudget($budget, $data);
return $budget;
}
/**
* How many days of this budget limit are between start and end?
*
* @param BudgetLimit $limit
* @param Carbon $start
* @param Carbon $end
* @return int
*/
private function daysInOverlap(BudgetLimit $limit, Carbon $start, Carbon $end): int
{
// start1 = $start
// start2 = $limit->start_date
// start1 = $end
// start2 = $limit->end_date
// limit is larger than start and end (inclusive)
// |-----------|
// |----------------|
if ($start->gte($limit->start_date) && $end->lte($limit->end_date)) {
return $start->diffInDays($end) + 1; // add one day
}
// limit starts earlier and limit ends first:
// |-----------|
// |-------|
if ($limit->start_date->lte($start) && $limit->end_date->lte($end)) {
// return days in the range $start-$limit_end
return $start->diffInDays($limit->end_date) + 1; // add one day, the day itself
}
// limit starts later and limit ends earlier
// |-----------|
// |-------|
if ($limit->start_date->gte($start) && $limit->end_date->gte($end)) {
// return days in the range $limit_start - $end
return $limit->start_date->diffInDays($end) + 1; // add one day, the day itself
}
return 0;
}
/**
* @param Budget $budget
* @param string $text
* @return void
*/
private function setNoteText(Budget $budget, string $text): void
{
$dbNote = $budget->notes()->first();
if ('' !== $text) {
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($budget);
}
$dbNote->text = trim($text);
$dbNote->save();
return;
}
if (null !== $dbNote) {
$dbNote->delete();
}
}
/**
* @param Budget $budget
* @param array $data
* @throws FireflyException
* @throws JsonException
*/
private function updateAutoBudget(Budget $budget, array $data): void
{
// update or create auto-budget:
$autoBudget = $this->getAutoBudget($budget);
// grab default currency:
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
if (null === $autoBudget) {
// at this point it's a blind assumption auto_budget_type is 1 or 2.
$autoBudget = new AutoBudget();
$autoBudget->auto_budget_type = $data['auto_budget_type'];
$autoBudget->budget_id = $budget->id;
$autoBudget->transaction_currency_id = $currency->id;
}
// set or update the currency.
if (array_key_exists('currency_id', $data) || array_key_exists('currency_code', $data)) {
$repos = app(CurrencyRepositoryInterface::class);
$currencyId = (int)($data['currency_id'] ?? 0);
$currencyCode = (string)($data['currency_code'] ?? '');
$currency = $repos->find($currencyId);
if (null === $currency) {
$currency = $repos->findByCodeNull($currencyCode);
}
if (null !== $currency) {
$autoBudget->transaction_currency_id = $currency->id;
}
}
// change values if submitted or presented:
if (array_key_exists('auto_budget_type', $data)) {
$autoBudget->auto_budget_type = $data['auto_budget_type'];
}
if (array_key_exists('auto_budget_amount', $data)) {
$autoBudget->amount = $data['auto_budget_amount'];
}
if (array_key_exists('auto_budget_period', $data)) {
$autoBudget->period = $data['auto_budget_period'];
}
$autoBudget->save();
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleActions(string $oldName, string $newName): void
{
$types = ['set_budget',];
$actions = RuleAction::leftJoin('rules', 'rules.id', '=', 'rule_actions.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_actions.action_type', $types)
->where('rule_actions.action_value', $oldName)
->get(['rule_actions.*']);
Log::debug(sprintf('Found %d actions to update.', $actions->count()));
/** @var RuleAction $action */
foreach ($actions as $action) {
$action->action_value = $newName;
$action->save();
Log::debug(sprintf('Updated action %d: %s', $action->id, $action->action_value));
}
}
/**
* @param string $oldName
* @param string $newName
*/
private function updateRuleTriggers(string $oldName, string $newName): void
{
$types = ['budget_is',];
$triggers = RuleTrigger::leftJoin('rules', 'rules.id', '=', 'rule_triggers.rule_id')
->where('rules.user_id', $this->user->id)
->whereIn('rule_triggers.trigger_type', $types)
->where('rule_triggers.trigger_value', $oldName)
->get(['rule_triggers.*']);
Log::debug(sprintf('Found %d triggers to update.', $triggers->count()));
/** @var RuleTrigger $trigger */
foreach ($triggers as $trigger) {
$trigger->trigger_value = $newName;
$trigger->save();
Log::debug(sprintf('Updated trigger %d: %s', $trigger->id, $trigger->trigger_value));
}
}
}

View File

@@ -86,6 +86,16 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
return $data;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param Collection $accounts
* @param Carbon $start
@@ -138,16 +148,6 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
return $return;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* TODO this method does not include multi currency. It just counts.
* TODO this probably also applies to the other "sumExpenses" methods.

View File

@@ -210,17 +210,6 @@ class OperationsRepository implements OperationsRepositoryInterface
}
}
/**
* @return Collection
*/
private function getBudgets(): Collection
{
/** @var BudgetRepositoryInterface $repos */
$repos = app(BudgetRepositoryInterface::class);
return $repos->getActiveBudgets();
}
/**
* @param Collection $budgets
* @param Collection $accounts
@@ -403,4 +392,15 @@ class OperationsRepository implements OperationsRepositoryInterface
return $blRepository->getBudgetLimits($budget, $start, $end);
}
/**
* @return Collection
*/
private function getBudgets(): Collection
{
/** @var BudgetRepositoryInterface $repos */
$repos = app(BudgetRepositoryInterface::class);
return $repos->getActiveBudgets();
}
}

View File

@@ -107,13 +107,27 @@ class CategoryRepository implements CategoryRepositoryInterface
}
/**
* Returns a list of all the categories belonging to a user.
* Find a category or return NULL
*
* @return Collection
* @param int $categoryId
*
* @return Category|null
*/
public function getCategories(): Collection
public function find(int $categoryId): ?Category
{
return $this->user->categories()->with(['attachments'])->orderBy('name', 'ASC')->get();
return $this->user->categories()->find($categoryId);
}
/**
* Find a category.
*
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
return $this->user->categories()->where('name', $name)->first(['categories.*']);
}
/**
@@ -144,90 +158,6 @@ class CategoryRepository implements CategoryRepositoryInterface
return $result;
}
/**
* Find a category or return NULL
*
* @param int $categoryId
*
* @return Category|null
*/
public function find(int $categoryId): ?Category
{
return $this->user->categories()->find($categoryId);
}
/**
* Find a category.
*
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
return $this->user->categories()->where('name', $name)->first(['categories.*']);
}
/**
* @param array $data
*
* @return Category
* @throws FireflyException
*/
public function store(array $data): Category
{
/** @var CategoryFactory $factory */
$factory = app(CategoryFactory::class);
$factory->setUser($this->user);
$category = $factory->findOrCreate(null, $data['name']);
if (null === $category) {
throw new FireflyException(sprintf('400003: Could not store new category with name "%s"', $data['name']));
}
if (array_key_exists('notes', $data) && '' === $data['notes']) {
$this->removeNotes($category);
}
if (array_key_exists('notes', $data) && '' !== $data['notes']) {
$this->updateNotes($category, $data['notes']);
}
return $category;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param Category $category
*/
public function removeNotes(Category $category): void
{
$category->notes()->delete();
}
/**
* @inheritDoc
*/
public function updateNotes(Category $category, string $notes): void
{
$dbNote = $category->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($category);
}
$dbNote->text = trim($notes);
$dbNote->save();
}
/**
* @param Category $category
*
@@ -256,43 +186,6 @@ class CategoryRepository implements CategoryRepositoryInterface
return $firstJournalDate;
}
/**
* @param Category $category
*
* @return Carbon|null
*/
private function getFirstJournalDate(Category $category): ?Carbon
{
$query = $category->transactionJournals()->orderBy('date', 'ASC');
$result = $query->first(['transaction_journals.*']);
if (null !== $result) {
return $result->date;
}
return null;
}
/**
* @param Category $category
*
* @return Carbon|null
*/
private function getFirstTransactionDate(Category $category): ?Carbon
{
// check transactions:
$query = $category->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'ASC');
$lastTransaction = $query->first(['transaction_journals.*']);
if (null !== $lastTransaction) {
return new Carbon($lastTransaction->date);
}
return null;
}
/**
* @inheritDoc
*/
@@ -326,6 +219,16 @@ class CategoryRepository implements CategoryRepositoryInterface
return $this->user->categories()->whereIn('id', $categoryIds)->get();
}
/**
* Returns a list of all the categories belonging to a user.
*
* @return Collection
*/
public function getCategories(): Collection
{
return $this->user->categories()->with(['attachments'])->orderBy('name', 'ASC')->get();
}
/**
* @inheritDoc
*/
@@ -368,6 +271,135 @@ class CategoryRepository implements CategoryRepositoryInterface
return $lastJournalDate;
}
/**
* @param Category $category
*/
public function removeNotes(Category $category): void
{
$category->notes()->delete();
}
/**
* @param string $query
* @param int $limit
*
* @return Collection
*/
public function searchCategory(string $query, int $limit): Collection
{
$search = $this->user->categories();
if ('' !== $query) {
$search->where('name', 'LIKE', sprintf('%%%s%%', $query));
}
return $search->take($limit)->get();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
* @return Category
* @throws FireflyException
*/
public function store(array $data): Category
{
/** @var CategoryFactory $factory */
$factory = app(CategoryFactory::class);
$factory->setUser($this->user);
$category = $factory->findOrCreate(null, $data['name']);
if (null === $category) {
throw new FireflyException(sprintf('400003: Could not store new category with name "%s"', $data['name']));
}
if (array_key_exists('notes', $data) && '' === $data['notes']) {
$this->removeNotes($category);
}
if (array_key_exists('notes', $data) && '' !== $data['notes']) {
$this->updateNotes($category, $data['notes']);
}
return $category;
}
/**
* @param Category $category
* @param array $data
*
* @return Category
* @throws Exception
*/
public function update(Category $category, array $data): Category
{
/** @var CategoryUpdateService $service */
$service = app(CategoryUpdateService::class);
$service->setUser($this->user);
return $service->update($category, $data);
}
/**
* @inheritDoc
*/
public function updateNotes(Category $category, string $notes): void
{
$dbNote = $category->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($category);
}
$dbNote->text = trim($notes);
$dbNote->save();
}
/**
* @param Category $category
*
* @return Carbon|null
*/
private function getFirstJournalDate(Category $category): ?Carbon
{
$query = $category->transactionJournals()->orderBy('date', 'ASC');
$result = $query->first(['transaction_journals.*']);
if (null !== $result) {
return $result->date;
}
return null;
}
/**
* @param Category $category
*
* @return Carbon|null
*/
private function getFirstTransactionDate(Category $category): ?Carbon
{
// check transactions:
$query = $category->transactions()
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
->orderBy('transaction_journals.date', 'ASC');
$lastTransaction = $query->first(['transaction_journals.*']);
if (null !== $lastTransaction) {
return new Carbon($lastTransaction->date);
}
return null;
}
/**
* @param Category $category
* @param Collection $accounts
@@ -417,36 +449,4 @@ class CategoryRepository implements CategoryRepositoryInterface
return null;
}
/**
* @param string $query
* @param int $limit
*
* @return Collection
*/
public function searchCategory(string $query, int $limit): Collection
{
$search = $this->user->categories();
if ('' !== $query) {
$search->where('name', 'LIKE', sprintf('%%%s%%', $query));
}
return $search->take($limit)->get();
}
/**
* @param Category $category
* @param array $data
*
* @return Category
* @throws Exception
*/
public function update(Category $category, array $data): Category
{
/** @var CategoryUpdateService $service */
$service = app(CategoryUpdateService::class);
$service->setUser($this->user);
return $service->update($category, $data);
}
}

View File

@@ -90,16 +90,6 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
return $array;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* This method returns a list of all the deposit transaction journals (as arrays) set in that period
* which have no category set to them. It's grouped per currency, with as few details in the array
@@ -152,6 +142,16 @@ class NoCategoryRepository implements NoCategoryRepositoryInterface
return $array;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* Sum of withdrawal journals in period without a category, grouped per currency. Amounts are always negative.
*

View File

@@ -116,26 +116,6 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* Returns a list of all the categories belonging to a user.
*
* @return Collection
*/
private function getCategories(): Collection
{
return $this->user->categories()->get();
}
/**
* This method returns a list of all the deposit transaction journals (as arrays) set in that period
* which have the specified category set to them. It's grouped per currency, with as few details in the array
@@ -341,6 +321,16 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* Sum of withdrawal journals in period for a set of categories, grouped per currency. Amounts are always negative.
*
@@ -470,4 +460,14 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* Returns a list of all the categories belonging to a user.
*
* @return Collection
*/
private function getCategories(): Collection
{
return $this->user->categories()->get();
}
}

View File

@@ -41,8 +41,8 @@ use FireflyIII\Services\Internal\Update\CurrencyUpdateService;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class CurrencyRepository.
@@ -51,6 +51,19 @@ class CurrencyRepository implements CurrencyRepositoryInterface
{
private User $user;
/**
* @param TransactionCurrency $currency
*
* @return int
*/
public function countJournals(TransactionCurrency $currency): int
{
$count = $currency->transactions()->whereNull('deleted_at')->count() + $currency->transactionJournals()->whereNull('deleted_at')->count();
// also count foreign:
return $count + Transaction::where('foreign_currency_id', $currency->id)->count();
}
/**
* @param TransactionCurrency $currency
*
@@ -152,35 +165,6 @@ class CurrencyRepository implements CurrencyRepositoryInterface
return null;
}
/**
* @param TransactionCurrency $currency
*
* @return int
*/
public function countJournals(TransactionCurrency $currency): int
{
$count = $currency->transactions()->whereNull('deleted_at')->count() + $currency->transactionJournals()->whereNull('deleted_at')->count();
// also count foreign:
return $count + Transaction::where('foreign_currency_id', $currency->id)->count();
}
/**
* @return Collection
*/
public function getAll(): Collection
{
return TransactionCurrency::orderBy('code', 'ASC')->get();
}
/**
* @return Collection
*/
public function get(): Collection
{
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* @param TransactionCurrency $currency
*
@@ -210,6 +194,16 @@ class CurrencyRepository implements CurrencyRepositoryInterface
$currency->save();
}
/**
* @param TransactionCurrency $currency
* Enables a currency
*/
public function enable(TransactionCurrency $currency): void
{
$currency->enabled = true;
$currency->save();
}
/**
* @inheritDoc
*/
@@ -230,13 +224,27 @@ class CurrencyRepository implements CurrencyRepositoryInterface
}
/**
* @param TransactionCurrency $currency
* Enables a currency
* Find by ID, return NULL if not found.
*
* @param int $currencyId
*
* @return TransactionCurrency|null
*/
public function enable(TransactionCurrency $currency): void
public function find(int $currencyId): ?TransactionCurrency
{
$currency->enabled = true;
$currency->save();
return TransactionCurrency::find($currencyId);
}
/**
* Find by currency code, return NULL if unfound.
*
* @param string $currencyCode
*
* @return TransactionCurrency|null
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
{
return TransactionCurrency::where('code', $currencyCode)->first();
}
/**
@@ -362,27 +370,19 @@ class CurrencyRepository implements CurrencyRepositoryInterface
}
/**
* Find by ID, return NULL if not found.
*
* @param int $currencyId
*
* @return TransactionCurrency|null
* @return Collection
*/
public function find(int $currencyId): ?TransactionCurrency
public function get(): Collection
{
return TransactionCurrency::find($currencyId);
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
}
/**
* Find by currency code, return NULL if unfound.
*
* @param string $currencyCode
*
* @return TransactionCurrency|null
* @return Collection
*/
public function findByCode(string $currencyCode): ?TransactionCurrency
public function getAll(): Collection
{
return TransactionCurrency::where('code', $currencyCode)->first();
return TransactionCurrency::orderBy('code', 'ASC')->get();
}
/**

View File

@@ -70,6 +70,18 @@ class JournalRepository implements JournalRepositoryInterface
$service->destroy($journal);
}
/**
* Find a specific journal.
*
* @param int $journalId
*
* @return TransactionJournal|null
*/
public function find(int $journalId): ?TransactionJournal
{
return $this->user->transactionJournals()->find($journalId);
}
/**
* @inheritDoc
*/
@@ -221,18 +233,6 @@ class JournalRepository implements JournalRepositoryInterface
$journal?->transactions()->update(['reconciled' => true]);
}
/**
* Find a specific journal.
*
* @param int $journalId
*
* @return TransactionJournal|null
*/
public function find(int $journalId): ?TransactionJournal
{
return $this->user->transactionJournals()->find($journalId);
}
/**
* Search in journal descriptions.
*

View File

@@ -68,28 +68,6 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
return true;
}
/**
* @param LinkType $linkType
* @param array $data
*
* @return LinkType
*/
public function update(LinkType $linkType, array $data): LinkType
{
if (array_key_exists('name', $data) && '' !== (string)$data['name']) {
$linkType->name = $data['name'];
}
if (array_key_exists('inward', $data) && '' !== (string)$data['inward']) {
$linkType->inward = $data['inward'];
}
if (array_key_exists('outward', $data) && '' !== (string)$data['outward']) {
$linkType->outward = $data['outward'];
}
$linkType->save();
return $linkType;
}
/**
* @param TransactionJournalLink $link
*
@@ -104,6 +82,30 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
return true;
}
/**
* @param int $linkTypeId
*
* @return LinkType|null
*/
public function find(int $linkTypeId): ?LinkType
{
return LinkType::find($linkTypeId);
}
/**
* @param string|null $name
*
* @return LinkType|null
*/
public function findByName(string $name = null): ?LinkType
{
if (null === $name) {
return null;
}
return LinkType::where('name', $name)->first();
}
/**
* Check if link exists between journals.
*
@@ -121,6 +123,30 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
return $count + $opposingCount > 0;
}
/**
* See if such a link already exists (and get it).
*
* @param LinkType $linkType
* @param TransactionJournal $inward
* @param TransactionJournal $outward
*
* @return TransactionJournalLink|null
*/
public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
{
return TransactionJournalLink::where('link_type_id', $linkType->id)
->where('source_id', $inward->id)
->where('destination_id', $outward->id)->first();
}
/**
* @return Collection
*/
public function get(): Collection
{
return LinkType::orderBy('name', 'ASC')->get();
}
/**
* Return array of all journal ID's for this type of link.
*
@@ -137,14 +163,6 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
return array_unique(array_merge($sources, $destinations));
}
/**
* @return Collection
*/
public function get(): Collection
{
return LinkType::orderBy('name', 'ASC')->get();
}
/**
* Returns all the journal links (of a specific type).
*
@@ -275,66 +293,19 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
return $link;
}
/**
* @param int $linkTypeId
*
* @return LinkType|null
*/
public function find(int $linkTypeId): ?LinkType
{
return LinkType::find($linkTypeId);
}
/**
* @param string|null $name
*
* @return LinkType|null
*/
public function findByName(string $name = null): ?LinkType
{
if (null === $name) {
return null;
}
return LinkType::where('name', $name)->first();
}
/**
* See if such a link already exists (and get it).
*
* @param LinkType $linkType
* @param TransactionJournal $inward
* @param TransactionJournal $outward
*
* @return TransactionJournalLink|null
*/
public function findSpecificLink(LinkType $linkType, TransactionJournal $inward, TransactionJournal $outward): ?TransactionJournalLink
{
return TransactionJournalLink::where('link_type_id', $linkType->id)
->where('source_id', $inward->id)
->where('destination_id', $outward->id)->first();
}
/**
* @param TransactionJournalLink $link
* @param string $text
*
* @throws Exception
* @return bool
*/
private function setNoteText(TransactionJournalLink $link, string $text): void
public function switchLink(TransactionJournalLink $link): bool
{
$dbNote = $link->notes()->first();
if ('' !== $text) {
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($link);
}
$dbNote->text = trim($text);
$dbNote->save();
$source = $link->source_id;
$link->source_id = $link->destination_id;
$link->destination_id = $source;
$link->save();
return;
}
$dbNote?->delete();
return true;
}
/**
@@ -352,18 +323,25 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
}
/**
* @param TransactionJournalLink $link
* @param LinkType $linkType
* @param array $data
*
* @return bool
* @return LinkType
*/
public function switchLink(TransactionJournalLink $link): bool
public function update(LinkType $linkType, array $data): LinkType
{
$source = $link->source_id;
$link->source_id = $link->destination_id;
$link->destination_id = $source;
$link->save();
if (array_key_exists('name', $data) && '' !== (string)$data['name']) {
$linkType->name = $data['name'];
}
if (array_key_exists('inward', $data) && '' !== (string)$data['inward']) {
$linkType->inward = $data['inward'];
}
if (array_key_exists('outward', $data) && '' !== (string)$data['outward']) {
$linkType->outward = $data['outward'];
}
$linkType->save();
return true;
return $linkType;
}
/**
@@ -397,4 +375,26 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
return $journalLink;
}
/**
* @param TransactionJournalLink $link
* @param string $text
*
* @throws Exception
*/
private function setNoteText(TransactionJournalLink $link, string $text): void
{
$dbNote = $link->notes()->first();
if ('' !== $text) {
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($link);
}
$dbNote->text = trim($text);
$dbNote->save();
return;
}
$dbNote?->delete();
}
}

View File

@@ -31,6 +31,16 @@ use FireflyIII\Models\ObjectGroup;
*/
trait CreatesObjectGroups
{
/**
* @param string $title
*
* @return null|ObjectGroup
*/
protected function findObjectGroup(string $title): ?ObjectGroup
{
return $this->user->objectGroups()->where('title', $title)->first();
}
/**
* @param int $groupId
*
@@ -80,14 +90,4 @@ trait CreatesObjectGroups
{
return 1 === $this->user->objectGroups()->where('title', $title)->count();
}
/**
* @param string $title
*
* @return null|ObjectGroup
*/
protected function findObjectGroup(string $title): ?ObjectGroup
{
return $this->user->objectGroups()->where('title', $title)->first();
}
}

View File

@@ -53,17 +53,6 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
}
}
/**
* @inheritDoc
*/
public function get(): Collection
{
return $this->user->objectGroups()
->with(['piggyBanks', 'bills'])
->orderBy('order', 'ASC')
->orderBy('title', 'ASC')->get();
}
/**
* @inheritDoc
*/
@@ -93,6 +82,17 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
$objectGroup->delete();
}
/**
* @inheritDoc
*/
public function get(): Collection
{
return $this->user->objectGroups()
->with(['piggyBanks', 'bills'])
->orderBy('order', 'ASC')
->orderBy('title', 'ASC')->get();
}
/**
* @inheritDoc
*/
@@ -151,34 +151,6 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
return $dbQuery->take($limit)->get(['object_groups.*']);
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @inheritDoc
*/
public function update(ObjectGroup $objectGroup, array $data): ObjectGroup
{
if (array_key_exists('title', $data)) {
$objectGroup->title = $data['title'];
}
if (array_key_exists('order', $data)) {
$this->setOrder($objectGroup, (int)$data['order']);
}
$objectGroup->save();
return $objectGroup;
}
/**
* @inheritDoc
*/
@@ -207,4 +179,32 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
return $objectGroup;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @inheritDoc
*/
public function update(ObjectGroup $objectGroup, array $data): ObjectGroup
{
if (array_key_exists('title', $data)) {
$objectGroup->title = $data['title'];
}
if (array_key_exists('order', $data)) {
$this->setOrder($objectGroup, (int)$data['order']);
}
$objectGroup->save();
return $objectGroup;
}
}

View File

@@ -43,34 +43,6 @@ trait ModifiesPiggyBanks
{
use CreatesObjectGroups;
public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount, TransactionJournal $journal): void
{
Log::debug(sprintf('addAmountToRepetition: %s', $amount));
if (-1 === bccomp($amount, '0')) {
Log::debug('Remove amount.');
$this->removeAmount($repetition->piggyBank, bcmul($amount, '-1'), $journal);
}
if (1 === bccomp($amount, '0')) {
Log::debug('Add amount.');
$this->addAmount($repetition->piggyBank, $amount, $journal);
}
}
public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool
{
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
}
$repetition->currentamount = bcsub($repetition->currentamount, $amount);
$repetition->save();
Log::debug('addAmount [a]: Trigger change for negative amount.');
event(new ChangedPiggyBankAmount($piggyBank, bcmul($amount, '-1'), $journal, null));
return true;
}
/**
* @param PiggyBank $piggyBank
* @param string $amount
@@ -93,6 +65,19 @@ trait ModifiesPiggyBanks
return true;
}
public function addAmountToRepetition(PiggyBankRepetition $repetition, string $amount, TransactionJournal $journal): void
{
Log::debug(sprintf('addAmountToRepetition: %s', $amount));
if (-1 === bccomp($amount, '0')) {
Log::debug('Remove amount.');
$this->removeAmount($repetition->piggyBank, bcmul($amount, '-1'), $journal);
}
if (1 === bccomp($amount, '0')) {
Log::debug('Add amount.');
$this->addAmount($repetition->piggyBank, $amount, $journal);
}
}
/**
* @param PiggyBank $piggyBank
* @param string $amount
@@ -155,6 +140,21 @@ trait ModifiesPiggyBanks
return true;
}
public function removeAmount(PiggyBank $piggyBank, string $amount, ?TransactionJournal $journal = null): bool
{
$repetition = $this->getRepetition($piggyBank);
if (null === $repetition) {
return false;
}
$repetition->currentamount = bcsub($repetition->currentamount, $amount);
$repetition->save();
Log::debug('addAmount [a]: Trigger change for negative amount.');
event(new ChangedPiggyBankAmount($piggyBank, bcmul($amount, '-1'), $journal, null));
return true;
}
/**
* @inheritDoc
*/
@@ -165,6 +165,23 @@ trait ModifiesPiggyBanks
return $piggyBank;
}
/**
* Correct order of piggies in case of issues.
*/
public function resetOrder(): void
{
$set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']);
$current = 1;
foreach ($set as $piggyBank) {
if ((int)$piggyBank->order !== $current) {
Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current));
$piggyBank->order = $current;
$piggyBank->save();
}
$current++;
}
}
/**
* @param PiggyBank $piggyBank
* @param string $amount
@@ -210,6 +227,34 @@ trait ModifiesPiggyBanks
return $piggyBank;
}
/**
* @inheritDoc
*/
public function setOrder(PiggyBank $piggyBank, int $newOrder): bool
{
$oldOrder = (int)$piggyBank->order;
Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
if ($newOrder > $oldOrder) {
$this->user->piggyBanks()->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->decrement('piggy_banks.order');
$piggyBank->order = $newOrder;
Log::debug(sprintf('Order of piggy #%d ("%s") is now %d', $piggyBank->id, $piggyBank->name, $newOrder));
$piggyBank->save();
return true;
}
$this->user->piggyBanks()->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->increment('piggy_banks.order');
$piggyBank->order = $newOrder;
Log::debug(sprintf('Order of piggy #%d ("%s") is now %d', $piggyBank->id, $piggyBank->name, $newOrder));
$piggyBank->save();
return true;
}
/**
* @param array $data
*
@@ -274,76 +319,6 @@ trait ModifiesPiggyBanks
return $piggyBank;
}
/**
* Correct order of piggies in case of issues.
*/
public function resetOrder(): void
{
$set = $this->user->piggyBanks()->orderBy('piggy_banks.order', 'ASC')->get(['piggy_banks.*']);
$current = 1;
foreach ($set as $piggyBank) {
if ((int)$piggyBank->order !== $current) {
Log::debug(sprintf('Piggy bank #%d ("%s") was at place %d but should be on %d', $piggyBank->id, $piggyBank->name, $piggyBank->order, $current));
$piggyBank->order = $current;
$piggyBank->save();
}
$current++;
}
}
/**
* @inheritDoc
*/
public function setOrder(PiggyBank $piggyBank, int $newOrder): bool
{
$oldOrder = (int)$piggyBank->order;
Log::debug(sprintf('Will move piggy bank #%d ("%s") from %d to %d', $piggyBank->id, $piggyBank->name, $oldOrder, $newOrder));
if ($newOrder > $oldOrder) {
$this->user->piggyBanks()->where('piggy_banks.order', '<=', $newOrder)->where('piggy_banks.order', '>', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->decrement('piggy_banks.order');
$piggyBank->order = $newOrder;
Log::debug(sprintf('Order of piggy #%d ("%s") is now %d', $piggyBank->id, $piggyBank->name, $newOrder));
$piggyBank->save();
return true;
}
$this->user->piggyBanks()->where('piggy_banks.order', '>=', $newOrder)->where('piggy_banks.order', '<', $oldOrder)
->where('piggy_banks.id', '!=', $piggyBank->id)
->increment('piggy_banks.order');
$piggyBank->order = $newOrder;
Log::debug(sprintf('Order of piggy #%d ("%s") is now %d', $piggyBank->id, $piggyBank->name, $newOrder));
$piggyBank->save();
return true;
}
/**
* @param PiggyBank $piggyBank
* @param string $note
*
* @return bool
*/
private function updateNote(PiggyBank $piggyBank, string $note): bool
{
if ('' === $note) {
$dbNote = $piggyBank->notes()->first();
$dbNote?->delete();
return true;
}
$dbNote = $piggyBank->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($piggyBank);
}
$dbNote->text = trim($note);
$dbNote->save();
return true;
}
/**
* @param PiggyBank $piggyBank
* @param array $data
@@ -413,6 +388,31 @@ trait ModifiesPiggyBanks
return $piggyBank;
}
/**
* @param PiggyBank $piggyBank
* @param string $note
*
* @return bool
*/
private function updateNote(PiggyBank $piggyBank, string $note): bool
{
if ('' === $note) {
$dbNote = $piggyBank->notes()->first();
$dbNote?->delete();
return true;
}
$dbNote = $piggyBank->notes()->first();
if (null === $dbNote) {
$dbNote = new Note();
$dbNote->noteable()->associate($piggyBank);
}
$dbNote->text = trim($note);
$dbNote->save();
return true;
}
/**
* @param PiggyBank $piggyBank
* @param array $data

View File

@@ -36,8 +36,8 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Storage;
/**
@@ -58,6 +58,29 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
$this->user->piggyBanks()->delete();
}
/**
* @param int $piggyBankId
*
* @return PiggyBank|null
*/
public function find(int $piggyBankId): ?PiggyBank
{
// phpstan doesn't get the Model.
return $this->user->piggyBanks()->find($piggyBankId); // @phpstan-ignore-line
}
/**
* Find by name or return NULL.
*
* @param string $name
*
* @return PiggyBank|null
*/
public function findByName(string $name): ?PiggyBank
{
return $this->user->piggyBanks()->where('piggy_banks.name', $name)->first(['piggy_banks.*']);
}
/**
* @param int|null $piggyBankId
* @param string|null $piggyBankName
@@ -89,29 +112,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return null;
}
/**
* @param int $piggyBankId
*
* @return PiggyBank|null
*/
public function find(int $piggyBankId): ?PiggyBank
{
// phpstan doesn't get the Model.
return $this->user->piggyBanks()->find($piggyBankId); // @phpstan-ignore-line
}
/**
* Find by name or return NULL.
*
* @param string $name
*
* @return PiggyBank|null
*/
public function findByName(string $name): ?PiggyBank
{
return $this->user->piggyBanks()->where('piggy_banks.name', $name)->first(['piggy_banks.*']);
}
/**
* @inheritDoc
*/
@@ -150,16 +150,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return (string)$rep->currentamount;
}
/**
* @param PiggyBank $piggyBank
*
* @return PiggyBankRepetition|null
*/
public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition
{
return $piggyBank->piggyBankRepetitions()->first();
}
/**
* @param PiggyBank $piggyBank
*
@@ -274,16 +264,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return (string)$amount;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @return int
*/
@@ -310,6 +290,22 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $note->text;
}
/**
* @return Collection
*/
public function getPiggyBanks(): Collection
{
return $this->user // @phpstan-ignore-line (phpstan does not recognize objectGroups)
->piggyBanks()
->with(
[
'account',
'objectGroups',
]
)
->orderBy('order', 'ASC')->get();
}
/**
* Also add amount in name.
*
@@ -331,19 +327,13 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
}
/**
* @return Collection
* @param PiggyBank $piggyBank
*
* @return PiggyBankRepetition|null
*/
public function getPiggyBanks(): Collection
public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition
{
return $this->user // @phpstan-ignore-line (phpstan does not recognize objectGroups)
->piggyBanks()
->with(
[
'account',
'objectGroups',
]
)
->orderBy('order', 'ASC')->get();
return $piggyBank->piggyBankRepetitions()->first();
}
/**
@@ -422,4 +412,14 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
return $search->take($limit)->get();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
}

View File

@@ -47,8 +47,8 @@ use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class RecurringRepository
@@ -92,21 +92,6 @@ class RecurringRepository implements RecurringRepositoryInterface
return false;
}
/**
* Returns all of the user's recurring transactions.
*
* @return Collection
*/
public function get(): Collection
{
return $this->user->recurrences()
->with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
->orderBy('active', 'DESC')
->orderBy('transaction_type_id', 'ASC')
->orderBy('title', 'ASC')
->get();
}
/**
* Destroy a recurring transaction.
*
@@ -127,6 +112,21 @@ class RecurringRepository implements RecurringRepositoryInterface
$this->user->recurrences()->delete();
}
/**
* Returns all of the user's recurring transactions.
*
* @return Collection
*/
public function get(): Collection
{
return $this->user->recurrences()
->with(['TransactionCurrency', 'TransactionType', 'RecurrenceRepetitions', 'RecurrenceTransactions'])
->orderBy('active', 'DESC')
->orderBy('transaction_type_id', 'ASC')
->orderBy('title', 'ASC')
->get();
}
/**
* Get ALL recurring transactions.
*
@@ -276,6 +276,45 @@ class RecurringRepository implements RecurringRepositoryInterface
return '';
}
/**
* Generate events in the date range.
*
* @param RecurrenceRepetition $repetition
* @param Carbon $start
* @param Carbon $end
*
* @return array
*
*/
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array
{
$occurrences = [];
$mutator = clone $start;
$mutator->startOfDay();
$skipMod = $repetition->repetition_skip + 1;
Log::debug(sprintf('Calculating occurrences for rep type "%s"', $repetition->repetition_type));
Log::debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d')));
if ('daily' === $repetition->repetition_type) {
$occurrences = $this->getDailyInRange($mutator, $end, $skipMod);
}
if ('weekly' === $repetition->repetition_type) {
$occurrences = $this->getWeeklyInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
if ('monthly' === $repetition->repetition_type) {
$occurrences = $this->getMonthlyInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
if ('ndom' === $repetition->repetition_type) {
$occurrences = $this->getNdomInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
if ('yearly' === $repetition->repetition_type) {
$occurrences = $this->getYearlyInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
// filter out all the weekend days:
return $this->filterWeekends($repetition, $occurrences);
}
/**
* @param RecurrenceTransaction $transaction
*
@@ -345,16 +384,6 @@ class RecurringRepository implements RecurringRepositoryInterface
return $collector->getPaginatedGroups();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param Recurrence $recurrence
*
@@ -465,27 +494,6 @@ class RecurringRepository implements RecurringRepositoryInterface
return $this->filterMaxDate($repeatUntil, $occurrences);
}
/**
* @param Carbon|null $max
* @param array $occurrences
*
* @return array
*/
private function filterMaxDate(?Carbon $max, array $occurrences): array
{
if (null === $max) {
return $occurrences;
}
$filtered = [];
foreach ($occurrences as $date) {
if ($date->lte($max)) {
$filtered[] = $date;
}
}
return $filtered;
}
/**
* Parse the repetition in a string that is user readable.
*
@@ -562,6 +570,16 @@ class RecurringRepository implements RecurringRepositoryInterface
return $search->take($limit)->get(['id', 'title', 'description']);
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
@@ -605,45 +623,6 @@ class RecurringRepository implements RecurringRepositoryInterface
return 0;
}
/**
* Generate events in the date range.
*
* @param RecurrenceRepetition $repetition
* @param Carbon $start
* @param Carbon $end
*
* @return array
*
*/
public function getOccurrencesInRange(RecurrenceRepetition $repetition, Carbon $start, Carbon $end): array
{
$occurrences = [];
$mutator = clone $start;
$mutator->startOfDay();
$skipMod = $repetition->repetition_skip + 1;
Log::debug(sprintf('Calculating occurrences for rep type "%s"', $repetition->repetition_type));
Log::debug(sprintf('Mutator is now: %s', $mutator->format('Y-m-d')));
if ('daily' === $repetition->repetition_type) {
$occurrences = $this->getDailyInRange($mutator, $end, $skipMod);
}
if ('weekly' === $repetition->repetition_type) {
$occurrences = $this->getWeeklyInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
if ('monthly' === $repetition->repetition_type) {
$occurrences = $this->getMonthlyInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
if ('ndom' === $repetition->repetition_type) {
$occurrences = $this->getNdomInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
if ('yearly' === $repetition->repetition_type) {
$occurrences = $this->getYearlyInRange($mutator, $end, $skipMod, $repetition->repetition_moment);
}
// filter out all the weekend days:
return $this->filterWeekends($repetition, $occurrences);
}
/**
* Update a recurring transaction.
*
@@ -660,4 +639,25 @@ class RecurringRepository implements RecurringRepositoryInterface
return $service->update($recurrence, $data);
}
/**
* @param Carbon|null $max
* @param array $occurrences
*
* @return array
*/
private function filterMaxDate(?Carbon $max, array $occurrences): array
{
if (null === $max) {
return $occurrences;
}
$filtered = [];
foreach ($occurrences as $date) {
if ($date->lte($max)) {
$filtered[] = $date;
}
}
return $filtered;
}
}

View File

@@ -45,6 +45,14 @@ class RuleRepository implements RuleRepositoryInterface
/** @var User */
private $user;
/**
* @return int
*/
public function count(): int
{
return $this->user->rules()->count();
}
/**
* @param Rule $rule
*
@@ -92,6 +100,16 @@ class RuleRepository implements RuleRepositoryInterface
return $newRule;
}
/**
* @param int $ruleId
*
* @return Rule|null
*/
public function find(int $ruleId): ?Rule
{
return $this->user->rules()->find($ruleId);
}
/**
* Get all the users rules.
*
@@ -139,14 +157,6 @@ class RuleRepository implements RuleRepositoryInterface
return $rule->ruleTriggers()->where('trigger_type', 'user_action')->first()->trigger_value;
}
/**
* @return int
*/
public function count(): int
{
return $this->user->rules()->count();
}
/**
* @param Rule $rule
*
@@ -244,6 +254,43 @@ class RuleRepository implements RuleRepositoryInterface
return $filtered;
}
/**
* @inheritDoc
*/
public function maxOrder(RuleGroup $ruleGroup): int
{
return (int)$ruleGroup->rules()->max('order');
}
/**
* @inheritDoc
*/
public function moveRule(Rule $rule, RuleGroup $ruleGroup, int $order): Rule
{
if ($rule->rule_group_id !== $ruleGroup->id) {
$rule->rule_group_id = $ruleGroup->id;
}
$rule->save();
$rule->refresh();
$this->setOrder($rule, $order);
return $rule;
}
/**
* @param RuleGroup $ruleGroup
*
* @return bool
*/
public function resetRuleOrder(RuleGroup $ruleGroup): bool
{
$groupRepository = app(RuleGroupRepositoryInterface::class);
$groupRepository->setUser($ruleGroup->user);
$groupRepository->resetRuleOrder($ruleGroup);
return true;
}
/**
* @inheritDoc
*/
@@ -259,6 +306,52 @@ class RuleRepository implements RuleRepositoryInterface
return $search->take($limit)->get(['id', 'title', 'description']);
}
/**
* @inheritDoc
*/
public function setOrder(Rule $rule, int $newOrder): void
{
$oldOrder = (int)$rule->order;
$groupId = (int)$rule->rule_group_id;
$maxOrder = $this->maxOrder($rule->ruleGroup);
$newOrder = $newOrder > $maxOrder ? $maxOrder + 1 : $newOrder;
Log::debug(sprintf('New order will be %d', $newOrder));
if ($newOrder > $oldOrder) {
$this->user->rules()
->where('rules.rule_group_id', $groupId)
->where('rules.order', '<=', $newOrder)
->where('rules.order', '>', $oldOrder)
->where('rules.id', '!=', $rule->id)
->decrement('rules.order');
$rule->order = $newOrder;
Log::debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
$rule->save();
return;
}
$this->user->rules()
->where('rules.rule_group_id', $groupId)
->where('rules.order', '>=', $newOrder)
->where('rules.order', '<', $oldOrder)
->where('rules.id', '!=', $rule->id)
->increment('rules.order');
$rule->order = $newOrder;
Log::debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
$rule->save();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
@@ -314,135 +407,23 @@ class RuleRepository implements RuleRepositoryInterface
}
/**
* @param int $ruleId
*
* @return Rule|null
*/
public function find(int $ruleId): ?Rule
{
return $this->user->rules()->find($ruleId);
}
/**
* @param string $moment
* @param Rule $rule
*/
private function setRuleTrigger(string $moment, Rule $rule): void
{
/** @var RuleTrigger|null $trigger */
$trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first();
if (null !== $trigger) {
$trigger->trigger_value = $moment;
$trigger->save();
return;
}
$trigger = new RuleTrigger();
$trigger->order = 0;
$trigger->trigger_type = 'user_action';
$trigger->trigger_value = $moment;
$trigger->rule_id = $rule->id;
$trigger->active = true;
$trigger->stop_processing = false;
$trigger->save();
}
/**
* @param RuleGroup $ruleGroup
* @param array $values
*
* @return bool
* @return RuleAction
*/
public function resetRuleOrder(RuleGroup $ruleGroup): bool
public function storeAction(Rule $rule, array $values): RuleAction
{
$groupRepository = app(RuleGroupRepositoryInterface::class);
$groupRepository->setUser($ruleGroup->user);
$groupRepository->resetRuleOrder($ruleGroup);
$ruleAction = new RuleAction();
$ruleAction->rule()->associate($rule);
$ruleAction->order = $values['order'];
$ruleAction->active = $values['active'];
$ruleAction->stop_processing = $values['stop_processing'];
$ruleAction->action_type = $values['action'];
$ruleAction->action_value = $values['value'] ?? '';
$ruleAction->save();
return true;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @inheritDoc
*/
public function setOrder(Rule $rule, int $newOrder): void
{
$oldOrder = (int)$rule->order;
$groupId = (int)$rule->rule_group_id;
$maxOrder = $this->maxOrder($rule->ruleGroup);
$newOrder = $newOrder > $maxOrder ? $maxOrder + 1 : $newOrder;
Log::debug(sprintf('New order will be %d', $newOrder));
if ($newOrder > $oldOrder) {
$this->user->rules()
->where('rules.rule_group_id', $groupId)
->where('rules.order', '<=', $newOrder)
->where('rules.order', '>', $oldOrder)
->where('rules.id', '!=', $rule->id)
->decrement('rules.order');
$rule->order = $newOrder;
Log::debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
$rule->save();
return;
}
$this->user->rules()
->where('rules.rule_group_id', $groupId)
->where('rules.order', '>=', $newOrder)
->where('rules.order', '<', $oldOrder)
->where('rules.id', '!=', $rule->id)
->increment('rules.order');
$rule->order = $newOrder;
Log::debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
$rule->save();
}
/**
* @inheritDoc
*/
public function maxOrder(RuleGroup $ruleGroup): int
{
return (int)$ruleGroup->rules()->max('order');
}
/**
* @param Rule $rule
* @param array $data
*
* @return void
*/
private function storeTriggers(Rule $rule, array $data): void
{
$order = 1;
foreach ($data['triggers'] as $trigger) {
$value = $trigger['value'] ?? '';
$stopProcessing = $trigger['stop_processing'] ?? false;
$active = $trigger['active'] ?? true;
$type = $trigger['type'];
if (true === ($trigger['prohibited'] ?? false) && !str_starts_with($type, '-')) {
$type = sprintf('-%s', $type);
}
$triggerValues = [
'action' => $type,
'value' => $value,
'stop_processing' => $stopProcessing,
'order' => $order,
'active' => $active,
];
$this->storeTrigger($rule, $triggerValues);
++$order;
}
return $ruleAction;
}
/**
@@ -465,51 +446,6 @@ class RuleRepository implements RuleRepositoryInterface
return $ruleTrigger;
}
/**
* @param Rule $rule
* @param array $data
*
* @return void
*/
private function storeActions(Rule $rule, array $data): void
{
$order = 1;
foreach ($data['actions'] as $action) {
$value = $action['value'] ?? '';
$stopProcessing = $action['stop_processing'] ?? false;
$active = $action['active'] ?? true;
$actionValues = [
'action' => $action['type'],
'value' => $value,
'stop_processing' => $stopProcessing,
'order' => $order,
'active' => $active,
];
$this->storeAction($rule, $actionValues);
++$order;
}
}
/**
* @param Rule $rule
* @param array $values
*
* @return RuleAction
*/
public function storeAction(Rule $rule, array $values): RuleAction
{
$ruleAction = new RuleAction();
$ruleAction->rule()->associate($rule);
$ruleAction->order = $values['order'];
$ruleAction->active = $values['active'];
$ruleAction->stop_processing = $values['stop_processing'];
$ruleAction->action_type = $values['action'];
$ruleAction->action_value = $values['value'] ?? '';
$ruleAction->save();
return $ruleAction;
}
/**
* @param Rule $rule
* @param array $data
@@ -569,17 +505,81 @@ class RuleRepository implements RuleRepositoryInterface
}
/**
* @inheritDoc
* @param string $moment
* @param Rule $rule
*/
public function moveRule(Rule $rule, RuleGroup $ruleGroup, int $order): Rule
private function setRuleTrigger(string $moment, Rule $rule): void
{
if ($rule->rule_group_id !== $ruleGroup->id) {
$rule->rule_group_id = $ruleGroup->id;
}
$rule->save();
$rule->refresh();
$this->setOrder($rule, $order);
/** @var RuleTrigger|null $trigger */
$trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first();
if (null !== $trigger) {
$trigger->trigger_value = $moment;
$trigger->save();
return $rule;
return;
}
$trigger = new RuleTrigger();
$trigger->order = 0;
$trigger->trigger_type = 'user_action';
$trigger->trigger_value = $moment;
$trigger->rule_id = $rule->id;
$trigger->active = true;
$trigger->stop_processing = false;
$trigger->save();
}
/**
* @param Rule $rule
* @param array $data
*
* @return void
*/
private function storeActions(Rule $rule, array $data): void
{
$order = 1;
foreach ($data['actions'] as $action) {
$value = $action['value'] ?? '';
$stopProcessing = $action['stop_processing'] ?? false;
$active = $action['active'] ?? true;
$actionValues = [
'action' => $action['type'],
'value' => $value,
'stop_processing' => $stopProcessing,
'order' => $order,
'active' => $active,
];
$this->storeAction($rule, $actionValues);
++$order;
}
}
/**
* @param Rule $rule
* @param array $data
*
* @return void
*/
private function storeTriggers(Rule $rule, array $data): void
{
$order = 1;
foreach ($data['triggers'] as $trigger) {
$value = $trigger['value'] ?? '';
$stopProcessing = $trigger['stop_processing'] ?? false;
$active = $trigger['active'] ?? true;
$type = $trigger['type'];
if (true === ($trigger['prohibited'] ?? false) && !str_starts_with($type, '-')) {
$type = sprintf('-%s', $type);
}
$triggerValues = [
'action' => $type,
'value' => $value,
'stop_processing' => $stopProcessing,
'order' => $order,
'active' => $active,
];
$this->storeTrigger($rule, $triggerValues);
++$order;
}
}
}

View File

@@ -63,14 +63,6 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
}
}
/**
* @return Collection
*/
public function get(): Collection
{
return $this->user->ruleGroups()->orderBy('order', 'ASC')->get();
}
/**
* @return int
*/
@@ -109,108 +101,6 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
return true;
}
/**
* @return bool
*/
public function resetOrder(): bool
{
$set = $this->user
->ruleGroups()
->whereNull('deleted_at')
->orderBy('order', 'ASC')
->orderBy('title', 'DESC')
->get();
$count = 1;
/** @var RuleGroup $entry */
foreach ($set as $entry) {
if ($entry->order !== $count) {
$entry->order = $count;
$entry->save();
}
// also update rules in group.
$this->resetRuleOrder($entry);
++$count;
}
return true;
}
/**
* @param RuleGroup $ruleGroup
*
* @return bool
*/
public function resetRuleOrder(RuleGroup $ruleGroup): bool
{
$set = $ruleGroup->rules()
->orderBy('order', 'ASC')
->orderBy('title', 'DESC')
->orderBy('updated_at', 'DESC')
->get(['rules.*']);
$count = 1;
/** @var Rule $entry */
foreach ($set as $entry) {
if ((int)$entry->order !== $count) {
Log::debug(sprintf('Rule #%d was on spot %d but must be on spot %d', $entry->id, $entry->order, $count));
$entry->order = $count;
$entry->save();
}
$this->resetRuleActionOrder($entry);
$this->resetRuleTriggerOrder($entry);
++$count;
}
return true;
}
/**
* @param Rule $rule
*/
private function resetRuleActionOrder(Rule $rule): void
{
$actions = $rule->ruleActions()
->orderBy('order', 'ASC')
->orderBy('active', 'DESC')
->orderBy('action_type', 'ASC')
->get();
$index = 1;
/** @var RuleAction $action */
foreach ($actions as $action) {
if ((int)$action->order !== $index) {
$action->order = $index;
$action->save();
Log::debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index));
}
$index++;
}
}
/**
* @param Rule $rule
*/
private function resetRuleTriggerOrder(Rule $rule): void
{
$triggers = $rule->ruleTriggers()
->orderBy('order', 'ASC')
->orderBy('active', 'DESC')
->orderBy('trigger_type', 'ASC')
->get();
$index = 1;
/** @var RuleTrigger $trigger */
foreach ($triggers as $trigger) {
$order = (int)$trigger->order;
if ($order !== $index) {
$trigger->order = $index;
$trigger->save();
Log::debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index));
}
$index++;
}
}
/**
* @inheritDoc
*/
@@ -244,6 +134,14 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
return $this->user->ruleGroups()->where('title', $title)->first();
}
/**
* @return Collection
*/
public function get(): Collection
{
return $this->user->ruleGroups()->orderBy('order', 'ASC')->get();
}
/**
* @return Collection
*/
@@ -428,6 +326,63 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
return (int)$this->user->ruleGroups()->where('active', true)->max('order');
}
/**
* @return bool
*/
public function resetOrder(): bool
{
$set = $this->user
->ruleGroups()
->whereNull('deleted_at')
->orderBy('order', 'ASC')
->orderBy('title', 'DESC')
->get();
$count = 1;
/** @var RuleGroup $entry */
foreach ($set as $entry) {
if ($entry->order !== $count) {
$entry->order = $count;
$entry->save();
}
// also update rules in group.
$this->resetRuleOrder($entry);
++$count;
}
return true;
}
/**
* @param RuleGroup $ruleGroup
*
* @return bool
*/
public function resetRuleOrder(RuleGroup $ruleGroup): bool
{
$set = $ruleGroup->rules()
->orderBy('order', 'ASC')
->orderBy('title', 'DESC')
->orderBy('updated_at', 'DESC')
->get(['rules.*']);
$count = 1;
/** @var Rule $entry */
foreach ($set as $entry) {
if ((int)$entry->order !== $count) {
Log::debug(sprintf('Rule #%d was on spot %d but must be on spot %d', $entry->id, $entry->order, $count));
$entry->order = $count;
$entry->save();
}
$this->resetRuleActionOrder($entry);
$this->resetRuleTriggerOrder($entry);
++$count;
}
return true;
}
/**
* @inheritDoc
*/
@@ -443,6 +398,32 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
return $search->take($limit)->get(['id', 'title', 'description']);
}
/**
* @inheritDoc
*/
public function setOrder(RuleGroup $ruleGroup, int $newOrder): void
{
$oldOrder = (int)$ruleGroup->order;
if ($newOrder > $oldOrder) {
$this->user->ruleGroups()->where('rule_groups.order', '<=', $newOrder)->where('rule_groups.order', '>', $oldOrder)
->where('rule_groups.id', '!=', $ruleGroup->id)
->decrement('order');
$ruleGroup->order = $newOrder;
Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save();
return;
}
$this->user->ruleGroups()->where('rule_groups.order', '>=', $newOrder)->where('rule_groups.order', '<', $oldOrder)
->where('rule_groups.id', '!=', $ruleGroup->id)
->increment('order');
$ruleGroup->order = $newOrder;
Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save();
}
/**
* @param User|Authenticatable|null $user
*/
@@ -478,32 +459,6 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
return $newRuleGroup;
}
/**
* @inheritDoc
*/
public function setOrder(RuleGroup $ruleGroup, int $newOrder): void
{
$oldOrder = (int)$ruleGroup->order;
if ($newOrder > $oldOrder) {
$this->user->ruleGroups()->where('rule_groups.order', '<=', $newOrder)->where('rule_groups.order', '>', $oldOrder)
->where('rule_groups.id', '!=', $ruleGroup->id)
->decrement('order');
$ruleGroup->order = $newOrder;
Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save();
return;
}
$this->user->ruleGroups()->where('rule_groups.order', '>=', $newOrder)->where('rule_groups.order', '<', $oldOrder)
->where('rule_groups.id', '!=', $ruleGroup->id)
->increment('order');
$ruleGroup->order = $newOrder;
Log::debug(sprintf('Order of group #%d ("%s") is now %d', $ruleGroup->id, $ruleGroup->title, $newOrder));
$ruleGroup->save();
}
/**
* @param RuleGroup $ruleGroup
* @param array $data
@@ -532,4 +487,49 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
return $ruleGroup;
}
/**
* @param Rule $rule
*/
private function resetRuleActionOrder(Rule $rule): void
{
$actions = $rule->ruleActions()
->orderBy('order', 'ASC')
->orderBy('active', 'DESC')
->orderBy('action_type', 'ASC')
->get();
$index = 1;
/** @var RuleAction $action */
foreach ($actions as $action) {
if ((int)$action->order !== $index) {
$action->order = $index;
$action->save();
Log::debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index));
}
$index++;
}
}
/**
* @param Rule $rule
*/
private function resetRuleTriggerOrder(Rule $rule): void
{
$triggers = $rule->ruleTriggers()
->orderBy('order', 'ASC')
->orderBy('active', 'DESC')
->orderBy('trigger_type', 'ASC')
->get();
$index = 1;
/** @var RuleTrigger $trigger */
foreach ($triggers as $trigger) {
$order = (int)$trigger->order;
if ($order !== $index) {
$trigger->order = $index;
$trigger->save();
Log::debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index));
}
$index++;
}
}
}

View File

@@ -119,28 +119,6 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @return Collection
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getTags(): Collection
{
$repository = app(TagRepositoryInterface::class);
return $repository->get();
}
/**
* This method returns a list of all the deposit transaction journals (as arrays) set in that period
* which have the specified tag(s) set to them. It's grouped per currency, with as few details in the array
@@ -219,6 +197,16 @@ class OperationsRepository implements OperationsRepositoryInterface
return $array;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* Sum of withdrawal journals in period for a set of tags, grouped per currency. Amounts are always negative.
*
@@ -250,4 +238,16 @@ class OperationsRepository implements OperationsRepositoryInterface
{
throw new FireflyException(sprintf('%s is not yet implemented.', __METHOD__));
}
/**
* @return Collection
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getTags(): Collection
{
$repository = app(TagRepositoryInterface::class);
return $repository->get();
}
}

View File

@@ -83,14 +83,6 @@ class TagRepository implements TagRepositoryInterface
}
}
/**
* @return Collection
*/
public function get(): Collection
{
return $this->user->tags()->orderBy('tag', 'ASC')->get();
}
/**
* @param Tag $tag
* @param Carbon $start
@@ -109,16 +101,6 @@ class TagRepository implements TagRepositoryInterface
return $collector->getExtractedJournals();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param int $tagId
*
@@ -151,6 +133,14 @@ class TagRepository implements TagRepositoryInterface
return $tag->transactionJournals()->orderBy('date', 'ASC')->first()?->date;
}
/**
* @return Collection
*/
public function get(): Collection
{
return $this->user->tags()->orderBy('tag', 'ASC')->get();
}
/**
* @inheritDoc
*/
@@ -171,6 +161,15 @@ class TagRepository implements TagRepositoryInterface
);
}
/**
* @inheritDoc
*/
public function getLocation(Tag $tag): ?Location
{
/** @var Location|null */
return $tag->locations()->first();
}
/**
* @param int|null $year
*
@@ -291,6 +290,16 @@ class TagRepository implements TagRepositoryInterface
return $tags->take($limit)->get('tags.*');
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
@@ -446,13 +455,4 @@ class TagRepository implements TagRepositoryInterface
return $tag;
}
/**
* @inheritDoc
*/
public function getLocation(Tag $tag): ?Location
{
/** @var Location|null */
return $tag->locations()->first();
}
}

View File

@@ -48,8 +48,8 @@ use FireflyIII\User;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class TransactionGroupRepository
@@ -69,18 +69,6 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $journal->attachments()->count();
}
/**
* Find a transaction group by its ID.
*
* @param int $groupId
*
* @return TransactionGroup|null
*/
public function find(int $groupId): ?TransactionGroup
{
return $this->user->transactionGroups()->find($groupId);
}
/**
* @param TransactionGroup $group
*/
@@ -107,53 +95,15 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
}
/**
* @param TransactionJournal $journal
* Find a transaction group by its ID.
*
* @return array
*/
private function expandJournal(TransactionJournal $journal): array
{
$array = $journal->toArray();
$array['transactions'] = [];
$array['meta'] = $journal->transactionJournalMeta->toArray();
$array['tags'] = $journal->tags->toArray();
$array['categories'] = $journal->categories->toArray();
$array['budgets'] = $journal->budgets->toArray();
$array['notes'] = $journal->notes->toArray();
$array['locations'] = [];
$array['attachments'] = $journal->attachments->toArray();
$array['links'] = [];
$array['piggy_bank_events'] = $journal->piggyBankEvents->toArray();
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$array['transactions'][] = $this->expandTransaction($transaction);
}
return $array;
}
/**
* @param Transaction $transaction
* @param int $groupId
*
* @return array
* @return TransactionGroup|null
*/
private function expandTransaction(Transaction $transaction): array
public function find(int $groupId): ?TransactionGroup
{
$array = $transaction->toArray();
$array['account'] = $transaction->account->toArray();
$array['budgets'] = [];
$array['categories'] = [];
foreach ($transaction->categories as $category) {
$array['categories'][] = $category->toArray();
}
foreach ($transaction->budgets as $budget) {
$array['budgets'][] = $budget->toArray();
}
return $array;
return $this->user->transactionGroups()->find($groupId);
}
/**
@@ -189,36 +139,6 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $result;
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* Get the note text for a journal (by ID).
*
* @param int $journalId
*
* @return string|null
*/
public function getNoteText(int $journalId): ?string
{
/** @var Note|null $note */
$note = Note::where('noteable_id', $journalId)
->where('noteable_type', TransactionJournal::class)
->first();
if (null === $note) {
return null;
}
return $note->text;
}
/**
* Return all journal links for all journals in the group.
*
@@ -277,58 +197,6 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $return;
}
/**
* @param TransactionJournal $journal
*
* @return string
*/
private function getFormattedAmount(TransactionJournal $journal): string
{
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
$currency = $transaction->transactionCurrency;
$type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->amount);
$return = '';
if (TransactionType::WITHDRAWAL === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
}
if (TransactionType::WITHDRAWAL !== $type) {
$return = app('amount')->formatAnything($currency, $amount);
}
return $return;
}
/**
* @param TransactionJournal $journal
*
* @return string
*/
private function getFormattedForeignAmount(TransactionJournal $journal): string
{
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
if (null === $transaction->foreign_amount || '' === $transaction->foreign_amount) {
return '';
}
if (0 === bccomp('0', $transaction->foreign_amount)) {
return '';
}
$currency = $transaction->foreignCurrency;
$type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->foreign_amount);
$return = '';
if (TransactionType::WITHDRAWAL === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
}
if (TransactionType::WITHDRAWAL !== $type) {
$return = app('amount')->formatAnything($currency, $amount);
}
return $return;
}
/**
* @inheritDoc
*/
@@ -389,6 +257,26 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return new NullArrayObject($return);
}
/**
* Get the note text for a journal (by ID).
*
* @param int $journalId
*
* @return string|null
*/
public function getNoteText(int $journalId): ?string
{
/** @var Note|null $note */
$note = Note::where('noteable_id', $journalId)
->where('noteable_type', TransactionJournal::class)
->first();
if (null === $note) {
return null;
}
return $note->text;
}
/**
* Return all piggy bank events for all journals in the group.
*
@@ -464,6 +352,16 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $result->pluck('tag')->toArray();
}
/**
* @param User|Authenticatable|null $user
*/
public function setUser(User|Authenticatable|null $user): void
{
if (null !== $user) {
$this->user = $user;
}
}
/**
* @param array $data
*
@@ -506,4 +404,106 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
return $service->update($transactionGroup, $data);
}
/**
* @param TransactionJournal $journal
*
* @return array
*/
private function expandJournal(TransactionJournal $journal): array
{
$array = $journal->toArray();
$array['transactions'] = [];
$array['meta'] = $journal->transactionJournalMeta->toArray();
$array['tags'] = $journal->tags->toArray();
$array['categories'] = $journal->categories->toArray();
$array['budgets'] = $journal->budgets->toArray();
$array['notes'] = $journal->notes->toArray();
$array['locations'] = [];
$array['attachments'] = $journal->attachments->toArray();
$array['links'] = [];
$array['piggy_bank_events'] = $journal->piggyBankEvents->toArray();
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$array['transactions'][] = $this->expandTransaction($transaction);
}
return $array;
}
/**
* @param Transaction $transaction
*
* @return array
*/
private function expandTransaction(Transaction $transaction): array
{
$array = $transaction->toArray();
$array['account'] = $transaction->account->toArray();
$array['budgets'] = [];
$array['categories'] = [];
foreach ($transaction->categories as $category) {
$array['categories'][] = $category->toArray();
}
foreach ($transaction->budgets as $budget) {
$array['budgets'][] = $budget->toArray();
}
return $array;
}
/**
* @param TransactionJournal $journal
*
* @return string
*/
private function getFormattedAmount(TransactionJournal $journal): string
{
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
$currency = $transaction->transactionCurrency;
$type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->amount);
$return = '';
if (TransactionType::WITHDRAWAL === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
}
if (TransactionType::WITHDRAWAL !== $type) {
$return = app('amount')->formatAnything($currency, $amount);
}
return $return;
}
/**
* @param TransactionJournal $journal
*
* @return string
*/
private function getFormattedForeignAmount(TransactionJournal $journal): string
{
/** @var Transaction $transaction */
$transaction = $journal->transactions->first();
if (null === $transaction->foreign_amount || '' === $transaction->foreign_amount) {
return '';
}
if (0 === bccomp('0', $transaction->foreign_amount)) {
return '';
}
$currency = $transaction->foreignCurrency;
$type = $journal->transactionType->type;
$amount = app('steam')->positive($transaction->foreign_amount);
$return = '';
if (TransactionType::WITHDRAWAL === $type) {
$return = app('amount')->formatAnything($currency, app('steam')->negative($amount));
}
if (TransactionType::WITHDRAWAL !== $type) {
$return = app('amount')->formatAnything($currency, $amount);
}
return $return;
}
}

View File

@@ -32,6 +32,18 @@ use Illuminate\Support\Facades\Log;
*/
class TransactionTypeRepository implements TransactionTypeRepositoryInterface
{
/**
* @param string $type
*
* @return TransactionType|null
*/
public function findByType(string $type): ?TransactionType
{
$search = ucfirst($type);
return TransactionType::whereType($search)->first();
}
/**
* @param TransactionType|null $type
* @param string|null $typeString
@@ -56,18 +68,6 @@ class TransactionTypeRepository implements TransactionTypeRepositoryInterface
return $search;
}
/**
* @param string $type
*
* @return TransactionType|null
*/
public function findByType(string $type): ?TransactionType
{
$search = ucfirst($type);
return TransactionType::whereType($search)->first();
}
/**
* @param string $query
* @param int $limit

View File

@@ -43,6 +43,39 @@ use Str;
*/
class UserRepository implements UserRepositoryInterface
{
/**
* @return Collection
*/
public function all(): Collection
{
return User::orderBy('id', 'DESC')->get(['users.*']);
}
/**
* @param User $user
* @param string $role
*
* @return bool
*/
public function attachRole(User $user, string $role): bool
{
$roleObject = Role::where('name', $role)->first();
if (null === $roleObject) {
Log::error(sprintf('Could not find role "%s" in attachRole()', $role));
return false;
}
try {
$user->roles()->attach($roleObject);
} catch (QueryException $e) {
// don't care
Log::error(sprintf('Query exception when giving user a role: %s', $e->getMessage()));
}
return true;
}
/**
* This updates the users email address and records some things so it can be confirmed or undone later.
* The user is blocked until the change is confirmed.
@@ -107,6 +140,14 @@ class UserRepository implements UserRepositoryInterface
return true;
}
/**
* @return int
*/
public function count(): int
{
return $this->all()->count();
}
/**
* @param string $name
* @param string $displayName
@@ -119,6 +160,22 @@ class UserRepository implements UserRepositoryInterface
return Role::create(['name' => $name, 'display_name' => $displayName, 'description' => $description]);
}
/**
* @inheritDoc
*/
public function deleteEmptyGroups(): void
{
$groups = UserGroup::get();
/** @var UserGroup $group */
foreach ($groups as $group) {
$count = $group->groupMemberships()->count();
if (0 === $count) {
Log::info(sprintf('Deleted empty group #%d ("%s")', $group->id, $group->title));
$group->delete();
}
}
}
/**
* @inheritDoc
*/
@@ -146,35 +203,13 @@ class UserRepository implements UserRepositoryInterface
}
/**
* @inheritDoc
* @param int $userId
*
* @return User|null
*/
public function deleteEmptyGroups(): void
public function find(int $userId): ?User
{
$groups = UserGroup::get();
/** @var UserGroup $group */
foreach ($groups as $group) {
$count = $group->groupMemberships()->count();
if (0 === $count) {
Log::info(sprintf('Deleted empty group #%d ("%s")', $group->id, $group->title));
$group->delete();
}
}
}
/**
* @return int
*/
public function count(): int
{
return $this->all()->count();
}
/**
* @return Collection
*/
public function all(): Collection
{
return User::orderBy('id', 'DESC')->get(['users.*']);
return User::find($userId);
}
/**
@@ -205,6 +240,16 @@ class UserRepository implements UserRepositoryInterface
return InvitedUser::with('user')->get();
}
/**
* @param string $role
*
* @return Role|null
*/
public function getRole(string $role): ?Role
{
return Role::where('name', $role)->first();
}
/**
* @param User $user
*
@@ -242,16 +287,6 @@ class UserRepository implements UserRepositoryInterface
return $roles;
}
/**
* @param int $userId
*
* @return User|null
*/
public function find(int $userId): ?User
{
return User::find($userId);
}
/**
* Return basic user information.
*
@@ -340,6 +375,21 @@ class UserRepository implements UserRepositoryInterface
}
}
/**
* Remove any role the user has.
*
* @param User $user
* @param string $role
*/
public function removeRole(User $user, string $role): void
{
$roleObj = $this->getRole($role);
if (null === $roleObj) {
return;
}
$user->roles()->detach($roleObj->id);
}
/**
* Set MFA code.
*
@@ -375,31 +425,6 @@ class UserRepository implements UserRepositoryInterface
return $user;
}
/**
* @param User $user
* @param string $role
*
* @return bool
*/
public function attachRole(User $user, string $role): bool
{
$roleObject = Role::where('name', $role)->first();
if (null === $roleObject) {
Log::error(sprintf('Could not find role "%s" in attachRole()', $role));
return false;
}
try {
$user->roles()->attach($roleObject);
} catch (QueryException $e) {
// don't care
Log::error(sprintf('Query exception when giving user a role: %s', $e->getMessage()));
}
return true;
}
/**
* @param User $user
*/
@@ -466,31 +491,6 @@ class UserRepository implements UserRepositoryInterface
return true;
}
/**
* Remove any role the user has.
*
* @param User $user
* @param string $role
*/
public function removeRole(User $user, string $role): void
{
$roleObj = $this->getRole($role);
if (null === $roleObj) {
return;
}
$user->roles()->detach($roleObj->id);
}
/**
* @param string $role
*
* @return Role|null
*/
public function getRole(string $role): ?Role
{
return Role::where('name', $role)->first();
}
/**
* @inheritDoc
*/