mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-02-25 18:45:27 -06:00
Reformat various code.
This commit is contained in:
parent
29bed2547c
commit
d1a09ff33b
@ -25,7 +25,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\RequestedReportOnJournals;
|
||||
use FireflyIII\Events\WarnUserAboutBill;
|
||||
use FireflyIII\Models\Bill;
|
||||
use Illuminate\Bus\Queueable;
|
||||
|
@ -34,8 +34,8 @@ class BillWarningMail extends Mailable
|
||||
use Queueable, SerializesModels;
|
||||
|
||||
public Bill $bill;
|
||||
public string $field;
|
||||
public int $diff;
|
||||
public string $field;
|
||||
|
||||
/**
|
||||
* ConfirmEmailChangeMail constructor.
|
||||
|
@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Mail;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
@ -60,7 +61,7 @@ class NewIPAddressWarningMail extends Mailable
|
||||
$this->host = '';
|
||||
try {
|
||||
$hostName = gethostbyaddr($this->ipAddress);
|
||||
} catch(\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$hostName = $this->ipAddress;
|
||||
}
|
||||
if ($hostName !== $this->ipAddress) {
|
||||
|
@ -49,34 +49,34 @@ use Illuminate\Support\Carbon;
|
||||
*/
|
||||
class AccountType extends Model
|
||||
{
|
||||
/** @var string */
|
||||
public const DEFAULT = 'Default account';
|
||||
/** @var string */
|
||||
public const CASH = 'Cash account';
|
||||
/** @var string */
|
||||
public const ASSET = 'Asset account';
|
||||
/** @var string */
|
||||
public const EXPENSE = 'Expense account';
|
||||
/** @var string */
|
||||
public const REVENUE = 'Revenue account';
|
||||
/** @var string */
|
||||
public const INITIAL_BALANCE = 'Initial balance account';
|
||||
/** @var string */
|
||||
public const BENEFICIARY = 'Beneficiary account';
|
||||
/** @var string */
|
||||
public const IMPORT = 'Import account';
|
||||
/** @var string */
|
||||
public const RECONCILIATION = 'Reconciliation account';
|
||||
/** @var string */
|
||||
public const LOAN = 'Loan';
|
||||
/** @var string */
|
||||
public const DEBT = 'Debt';
|
||||
/** @var string */
|
||||
public const MORTGAGE = 'Mortgage';
|
||||
public const CASH = 'Cash account';
|
||||
/** @var string */
|
||||
public const CREDITCARD = 'Credit card';
|
||||
/** @var string */
|
||||
public const DEBT = 'Debt';
|
||||
/** @var string */
|
||||
public const DEFAULT = 'Default account';
|
||||
/** @var string */
|
||||
public const EXPENSE = 'Expense account';
|
||||
/** @var string */
|
||||
public const IMPORT = 'Import account';
|
||||
/** @var string */
|
||||
public const INITIAL_BALANCE = 'Initial balance account';
|
||||
/** @var string */
|
||||
public const LIABILITY_CREDIT = 'Liability credit account';
|
||||
/** @var string */
|
||||
public const LOAN = 'Loan';
|
||||
/** @var string */
|
||||
public const MORTGAGE = 'Mortgage';
|
||||
/** @var string */
|
||||
public const RECONCILIATION = 'Reconciliation account';
|
||||
/** @var string */
|
||||
public const REVENUE = 'Revenue account';
|
||||
/**
|
||||
* The attributes that should be casted to native types.
|
||||
*
|
||||
|
@ -77,7 +77,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property string $email
|
||||
* @property int|null $user_group_id
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|Budget whereUserGroupId($value)
|
||||
* @property-read Collection|\FireflyIII\Models\Note[] $notes
|
||||
* @property-read Collection|Note[] $notes
|
||||
* @property-read int|null $notes_count
|
||||
*/
|
||||
class Budget extends Model
|
||||
|
@ -58,20 +58,20 @@ class TransactionType extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
/** @var string */
|
||||
public const WITHDRAWAL = 'Withdrawal';
|
||||
/** @var string */
|
||||
public const DEPOSIT = 'Deposit';
|
||||
/** @var string */
|
||||
public const TRANSFER = 'Transfer';
|
||||
public const INVALID = 'Invalid';
|
||||
/** @var string */
|
||||
public const LIABILITY_CREDIT = 'Liability credit';
|
||||
/** @var string */
|
||||
public const OPENING_BALANCE = 'Opening balance';
|
||||
/** @var string */
|
||||
public const RECONCILIATION = 'Reconciliation';
|
||||
/** @var string */
|
||||
public const INVALID = 'Invalid';
|
||||
public const TRANSFER = 'Transfer';
|
||||
/** @var string */
|
||||
public const LIABILITY_CREDIT = 'Liability credit';
|
||||
public const WITHDRAWAL = 'Withdrawal';
|
||||
/** @var string[] */
|
||||
protected $casts
|
||||
= [
|
||||
|
@ -53,14 +53,14 @@ use Illuminate\Support\Carbon;
|
||||
*/
|
||||
class UserRole extends Model
|
||||
{
|
||||
public const READ_ONLY = 'ro';
|
||||
public const CHANGE_TRANSACTIONS = 'change_tx';
|
||||
public const CHANGE_RULES = 'change_rules';
|
||||
public const CHANGE_PIGGY_BANKS = 'change_piggies';
|
||||
public const CHANGE_REPETITIONS = 'change_reps';
|
||||
public const VIEW_REPORTS = 'view_reports';
|
||||
public const CHANGE_RULES = 'change_rules';
|
||||
public const CHANGE_TRANSACTIONS = 'change_tx';
|
||||
public const FULL = 'full';
|
||||
public const OWNER = 'owner';
|
||||
public const READ_ONLY = 'ro';
|
||||
public const VIEW_REPORTS = 'view_reports';
|
||||
protected $fillable = ['title'];
|
||||
|
||||
/**
|
||||
|
@ -80,17 +80,17 @@ class Webhook extends Model
|
||||
|
||||
// dont forget to update the config in firefly.php
|
||||
// triggers
|
||||
public const TRIGGER_STORE_TRANSACTION = 100;
|
||||
public const TRIGGER_UPDATE_TRANSACTION = 110;
|
||||
public const TRIGGER_DESTROY_TRANSACTION = 120;
|
||||
|
||||
// actions
|
||||
public const RESPONSE_TRANSACTIONS = 200;
|
||||
public const DELIVERY_JSON = 300;
|
||||
public const RESPONSE_ACCOUNTS = 210;
|
||||
public const RESPONSE_NONE = 220;
|
||||
|
||||
// actions
|
||||
public const RESPONSE_TRANSACTIONS = 200;
|
||||
public const TRIGGER_DESTROY_TRANSACTION = 120;
|
||||
public const TRIGGER_STORE_TRANSACTION = 100;
|
||||
|
||||
// delivery
|
||||
public const DELIVERY_JSON = 300;
|
||||
public const TRIGGER_UPDATE_TRANSACTION = 110;
|
||||
protected $casts
|
||||
= [
|
||||
'active' => 'boolean',
|
||||
|
@ -48,7 +48,6 @@ use Laravel\Passport\Client;
|
||||
use Laravel\Passport\Events\AccessTokenCreated;
|
||||
use Log;
|
||||
use Mail;
|
||||
use Request;
|
||||
use Session;
|
||||
|
||||
/**
|
||||
|
@ -198,21 +198,6 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
public function getAccountCurrency(Account $account): ?TransactionCurrency
|
||||
{
|
||||
$currencyId = (int)$this->getMetaValue($account, 'currency_id');
|
||||
if ($currencyId > 0) {
|
||||
return TransactionCurrency::find($currencyId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return account type or null if not found.
|
||||
*
|
||||
@ -244,38 +229,6 @@ 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 (!empty($types)) {
|
||||
$query->accountTypeIn($types);
|
||||
}
|
||||
|
||||
// add sort parameters. At this point they're filtered to allowed fields to sort by:
|
||||
if (!empty($sort)) {
|
||||
foreach ($sort as $param) {
|
||||
$query->orderBy($param[0], $param[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($sort)) {
|
||||
if (!empty($res)) {
|
||||
$query->orderBy('accounts.order', 'ASC');
|
||||
}
|
||||
$query->orderBy('accounts.active', 'DESC');
|
||||
$query->orderBy('accounts.name', 'ASC');
|
||||
}
|
||||
|
||||
return $query->get(['accounts.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $types
|
||||
*
|
||||
@ -384,31 +337,6 @@ 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.
|
||||
*
|
||||
@ -427,20 +355,6 @@ 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.
|
||||
*
|
||||
@ -498,6 +412,20 @@ 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
|
||||
*
|
||||
@ -550,6 +478,46 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return $factory->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
public function getAccountCurrency(Account $account): ?TransactionCurrency
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -603,6 +571,52 @@ 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 (!empty($types)) {
|
||||
$query->accountTypeIn($types);
|
||||
}
|
||||
|
||||
// add sort parameters. At this point they're filtered to allowed fields to sort by:
|
||||
if (!empty($sort)) {
|
||||
foreach ($sort as $param) {
|
||||
$query->orderBy($param[0], $param[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($sort)) {
|
||||
if (!empty($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.
|
||||
*
|
||||
@ -626,20 +640,6 @@ 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
|
||||
*/
|
||||
|
@ -146,46 +146,6 @@ class AccountTasker implements AccountTaskerInterface
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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'];
|
||||
}
|
||||
|
||||
array_multisort($sum, SORT_DESC, $report['accounts']);
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
*
|
||||
@ -247,6 +207,38 @@ class AccountTasker implements AccountTaskerInterface
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
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'];
|
||||
}
|
||||
|
||||
array_multisort($sum, SORT_DESC, $report['accounts']);
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
*
|
||||
@ -306,4 +298,12 @@ class AccountTasker implements AccountTaskerInterface
|
||||
|
||||
return $report;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
}
|
||||
|
@ -56,109 +56,6 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
return $this->sortByCurrency($journals, 'negative');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* as possible. Amounts are always positive.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection|null $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array
|
||||
{
|
||||
$journals = $this->getTransactions($start, $end, $accounts, TransactionType::DEPOSIT);
|
||||
|
||||
return $this->sortByCurrency($journals, 'positive');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function sumExpenses(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->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
|
||||
*
|
||||
@ -223,6 +120,45 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
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
|
||||
* as possible. Amounts are always positive.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection|null $accounts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null): array
|
||||
{
|
||||
$journals = $this->getTransactions($start, $end, $accounts, TransactionType::DEPOSIT);
|
||||
|
||||
return $this->sortByCurrency($journals, 'positive');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function sumExpenses(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->groupByCurrency($journals, 'negative');
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
@ -236,7 +172,8 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
private function getTransactionsForSum(
|
||||
string $type, Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $opposing = null, ?TransactionCurrency $currency = null
|
||||
|
||||
): array {
|
||||
): array
|
||||
{
|
||||
$start->startOfDay();
|
||||
$end->endOfDay();
|
||||
|
||||
@ -343,6 +280,18 @@ 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
|
||||
@ -390,6 +339,63 @@ 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
|
||||
*
|
||||
|
@ -33,7 +33,6 @@ use FireflyIII\User;
|
||||
use Illuminate\Contracts\Encryption\DecryptException;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class AttachmentRepository.
|
||||
|
@ -55,6 +55,36 @@ class BillRepository implements BillRepositoryInterface
|
||||
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function billEndsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->bills();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s', $query));
|
||||
}
|
||||
$search->orderBy('name', 'ASC')
|
||||
->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function billStartsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->bills();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%s%%', $query));
|
||||
}
|
||||
$search->orderBy('name', 'ASC')
|
||||
->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct order of piggies in case of issues.
|
||||
*/
|
||||
@ -95,18 +125,6 @@ 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.
|
||||
*
|
||||
@ -138,6 +156,18 @@ 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.
|
||||
*
|
||||
@ -150,17 +180,6 @@ 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.
|
||||
*
|
||||
@ -258,6 +277,17 @@ class BillRepository implements BillRepositoryInterface
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 the total amount of money paid for the users active bills in the date range given,
|
||||
* grouped per currency.
|
||||
@ -320,6 +350,71 @@ class BillRepository implements BillRepositoryInterface
|
||||
return $sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @throws JsonException
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the total amount of money due for the users active bills in the date range given.
|
||||
*
|
||||
@ -464,41 +559,6 @@ class BillRepository implements BillRepositoryInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
@ -616,36 +676,6 @@ 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
|
||||
* @throws JsonException
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -782,35 +812,4 @@ class BillRepository implements BillRepositoryInterface
|
||||
|
||||
return $service->update($bill, $data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function billEndsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->bills();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s', $query));
|
||||
}
|
||||
$search->orderBy('name', 'ASC')
|
||||
->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function billStartsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->bills();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%s%%', $query));
|
||||
}
|
||||
$search->orderBy('name', 'ASC')
|
||||
->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
}
|
||||
|
@ -35,11 +35,6 @@ use Illuminate\Support\Collection;
|
||||
interface BillRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Add correct order to bills.
|
||||
*/
|
||||
public function correctOrder(): void;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
@ -56,6 +51,11 @@ interface BillRepositoryInterface
|
||||
*/
|
||||
public function billStartsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* Add correct order to bills.
|
||||
*/
|
||||
public function correctOrder(): void;
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
*
|
||||
|
@ -147,6 +147,22 @@ class BudgetLimitRepository implements BudgetLimitRepositoryInterface
|
||||
->where('end_date', $end->format('Y-m-d'))->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 Carbon|null $start
|
||||
* @param Carbon|null $end
|
||||
@ -215,22 +231,6 @@ 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
|
||||
|
@ -50,6 +50,36 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
{
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function budgetEndsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->budgets();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s', $query));
|
||||
}
|
||||
$search->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function budgetStartsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->budgets();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%s%%', $query));
|
||||
}
|
||||
$search->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
@ -76,6 +106,17 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getActiveBudgets(): Collection
|
||||
{
|
||||
return $this->user->budgets()->where('active', true)
|
||||
->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
@ -106,6 +147,15 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getBudgets(): Collection
|
||||
{
|
||||
return $this->user->budgets()->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -117,18 +167,6 @@ 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
|
||||
@ -152,6 +190,18 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find budget by name.
|
||||
*
|
||||
@ -187,17 +237,6 @@ 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
|
||||
*/
|
||||
@ -219,23 +258,6 @@ 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.
|
||||
*
|
||||
@ -258,9 +280,17 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
->orderBy('name', 'ASC')->where('active', 0)->get();
|
||||
}
|
||||
|
||||
public function getMaxOrder(): int
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getNoteText(Budget $budget): ?string
|
||||
{
|
||||
return (int)$this->user->budgets()->max('order');
|
||||
$note = $budget->notes()->first();
|
||||
if (null === $note) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $note->text;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -387,6 +417,38 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
return $newBudget;
|
||||
}
|
||||
|
||||
public function getMaxOrder(): int
|
||||
{
|
||||
return (int) $this->user->budgets()->max('order');
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) { // @phpstan-ignore-line
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
@ -476,6 +538,14 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getAutoBudget(Budget $budget): ?AutoBudget
|
||||
{
|
||||
return $budget->autoBudgets()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @param array $data
|
||||
@ -524,74 +594,4 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
|
||||
$autoBudget->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getNoteText(Budget $budget): ?string
|
||||
{
|
||||
$note = $budget->notes()->first();
|
||||
if (null === $note) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $note->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) { // @phpstan-ignore-line
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function budgetEndsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->budgets();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s', $query));
|
||||
}
|
||||
$search->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function budgetStartsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->budgets();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%s%%', $query));
|
||||
}
|
||||
$search->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')->where('active', true);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
}
|
||||
|
@ -34,17 +34,27 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface BudgetRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function budgetEndsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function budgetStartsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function cleanupBudgets(): bool;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @return string|null
|
||||
*/
|
||||
public function getNoteText(Budget $budget): ?string;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
*
|
||||
@ -140,6 +150,12 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function getMaxOrder(): int;
|
||||
|
||||
/**
|
||||
* @param Budget $budget
|
||||
* @return string|null
|
||||
*/
|
||||
public function getNoteText(Budget $budget): ?string;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
@ -175,20 +191,4 @@ interface BudgetRepositoryInterface
|
||||
*/
|
||||
public function update(Budget $budget, array $data): Budget;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function budgetEndsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function budgetStartsWith(string $query, int $limit): Collection;
|
||||
|
||||
}
|
||||
|
@ -200,6 +200,19 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getBudgets(): Collection
|
||||
{
|
||||
/** @var BudgetRepositoryInterface $repos */
|
||||
$repos = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $repos->getActiveBudgets();
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
@ -208,8 +221,6 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
|
||||
/**
|
||||
* @param Collection $budgets
|
||||
* @param Collection $accounts
|
||||
@ -371,17 +382,6 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getBudgets(): Collection
|
||||
{
|
||||
/** @var BudgetRepositoryInterface $repos */
|
||||
$repos = app(BudgetRepositoryInterface::class);
|
||||
|
||||
return $repos->getActiveBudgets();
|
||||
}
|
||||
|
||||
/**
|
||||
* For now, simply refer to whichever repository holds this function.
|
||||
* See reference nr. 14
|
||||
|
@ -46,6 +46,32 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
{
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function categoryEndsWith(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->categories();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s', $query));
|
||||
}
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function categoryStartsWith(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
|
||||
*
|
||||
@ -79,27 +105,13 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a category or return NULL
|
||||
* Returns a list of all the categories belonging to a user.
|
||||
*
|
||||
* @param int $categoryId
|
||||
*
|
||||
* @return Category|null
|
||||
* @return Collection
|
||||
*/
|
||||
public function find(int $categoryId): ?Category
|
||||
public function getCategories(): Collection
|
||||
{
|
||||
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.*']);
|
||||
return $this->user->categories()->with(['attachments'])->orderBy('name', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -130,6 +142,81 @@ 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 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
|
||||
*
|
||||
@ -158,6 +245,43 @@ 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
|
||||
*/
|
||||
@ -191,16 +315,6 @@ 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
|
||||
*/
|
||||
@ -243,134 +357,6 @@ 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 $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$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
|
||||
@ -422,28 +408,42 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function categoryEndsWith(string $query, int $limit): Collection
|
||||
public function searchCategory(string $query, int $limit): Collection
|
||||
{
|
||||
$search = $this->user->categories();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%%%s', $query));
|
||||
$search->where('name', 'LIKE', sprintf('%%%s%%', $query));
|
||||
}
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @param User $user
|
||||
*/
|
||||
public function categoryStartsWith(string $query, int $limit): Collection
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$search = $this->user->categories();
|
||||
if ('' !== $query) {
|
||||
$search->where('name', 'LIKE', sprintf('%s%%', $query));
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,22 @@ use Illuminate\Support\Collection;
|
||||
interface CategoryRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function categoryEndsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function categoryStartsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
@ -134,22 +150,6 @@ interface CategoryRepositoryInterface
|
||||
*/
|
||||
public function searchCategory(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function categoryEndsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
public function categoryStartsWith(string $query, int $limit): Collection;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
|
@ -116,6 +116,16 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -192,6 +202,138 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function listTransferredIn(Carbon $start, Carbon $end, Collection $accounts, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
||||
->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts);
|
||||
if (null !== $categories && $categories->count() > 0) {
|
||||
$collector->setCategories($categories);
|
||||
}
|
||||
if (null === $categories || (null !== $categories && 0 === $categories->count())) {
|
||||
$collector->setCategories($this->getCategories());
|
||||
}
|
||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$array = [];
|
||||
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int) $journal['currency_id'];
|
||||
$categoryId = (int) $journal['category_id'];
|
||||
$categoryName = (string) $journal['category_name'];
|
||||
|
||||
// catch "no category" entries.
|
||||
if (0 === $categoryId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// info about the currency:
|
||||
$array[$currencyId] = $array[$currencyId] ?? [
|
||||
'categories' => [],
|
||||
'currency_id' => $currencyId,
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
];
|
||||
|
||||
// info about the categories:
|
||||
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
|
||||
'id' => $categoryId,
|
||||
'name' => $categoryName,
|
||||
'transaction_journals' => [],
|
||||
];
|
||||
|
||||
// add journal to array:
|
||||
// only a subset of the fields.
|
||||
$journalId = (int) $journal['transaction_journal_id'];
|
||||
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
|
||||
'amount' => app('steam')->positive($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'category_name' => $journal['category_name'],
|
||||
'source_account_name' => $journal['source_account_name'],
|
||||
'destination_account_id' => $journal['destination_account_id'],
|
||||
'destination_account_name' => $journal['destination_account_name'],
|
||||
'description' => $journal['description'],
|
||||
'transaction_group_id' => $journal['transaction_group_id'],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function listTransferredOut(Carbon $start, Carbon $end, Collection $accounts, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
||||
->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts);
|
||||
if (null !== $categories && $categories->count() > 0) {
|
||||
$collector->setCategories($categories);
|
||||
}
|
||||
if (null === $categories || (null !== $categories && 0 === $categories->count())) {
|
||||
$collector->setCategories($this->getCategories());
|
||||
}
|
||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$array = [];
|
||||
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int) $journal['currency_id'];
|
||||
$categoryId = (int) $journal['category_id'];
|
||||
$categoryName = (string) $journal['category_name'];
|
||||
|
||||
// catch "no category" entries.
|
||||
if (0 === $categoryId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// info about the currency:
|
||||
$array[$currencyId] = $array[$currencyId] ?? [
|
||||
'categories' => [],
|
||||
'currency_id' => $currencyId,
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
];
|
||||
|
||||
// info about the categories:
|
||||
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
|
||||
'id' => $categoryId,
|
||||
'name' => $categoryName,
|
||||
'transaction_journals' => [],
|
||||
];
|
||||
|
||||
// add journal to array:
|
||||
// only a subset of the fields.
|
||||
$journalId = (int) $journal['transaction_journal_id'];
|
||||
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
|
||||
'amount' => app('steam')->negative($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'category_name' => $journal['category_name'],
|
||||
'source_account_name' => $journal['source_account_name'],
|
||||
'destination_account_id' => $journal['destination_account_id'],
|
||||
'destination_account_name' => $journal['destination_account_name'],
|
||||
'description' => $journal['description'],
|
||||
'transaction_group_id' => $journal['transaction_group_id'],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
@ -329,146 +471,4 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function listTransferredIn(Carbon $start, Carbon $end, Collection $accounts, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
||||
->setDestinationAccounts($accounts)->excludeSourceAccounts($accounts);
|
||||
if (null !== $categories && $categories->count() > 0) {
|
||||
$collector->setCategories($categories);
|
||||
}
|
||||
if (null === $categories || (null !== $categories && 0 === $categories->count())) {
|
||||
$collector->setCategories($this->getCategories());
|
||||
}
|
||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$array = [];
|
||||
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$categoryId = (int)$journal['category_id'];
|
||||
$categoryName = (string)$journal['category_name'];
|
||||
|
||||
// catch "no category" entries.
|
||||
if (0 === $categoryId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// info about the currency:
|
||||
$array[$currencyId] = $array[$currencyId] ?? [
|
||||
'categories' => [],
|
||||
'currency_id' => $currencyId,
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
];
|
||||
|
||||
// info about the categories:
|
||||
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
|
||||
'id' => $categoryId,
|
||||
'name' => $categoryName,
|
||||
'transaction_journals' => [],
|
||||
];
|
||||
|
||||
// add journal to array:
|
||||
// only a subset of the fields.
|
||||
$journalId = (int)$journal['transaction_journal_id'];
|
||||
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
|
||||
'amount' => app('steam')->positive($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'category_name' => $journal['category_name'],
|
||||
'source_account_name' => $journal['source_account_name'],
|
||||
'destination_account_id' => $journal['destination_account_id'],
|
||||
'destination_account_name' => $journal['destination_account_name'],
|
||||
'description' => $journal['description'],
|
||||
'transaction_group_id' => $journal['transaction_group_id'],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function listTransferredOut(Carbon $start, Carbon $end, Collection $accounts, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionType::TRANSFER])
|
||||
->setSourceAccounts($accounts)->excludeDestinationAccounts($accounts);
|
||||
if (null !== $categories && $categories->count() > 0) {
|
||||
$collector->setCategories($categories);
|
||||
}
|
||||
if (null === $categories || (null !== $categories && 0 === $categories->count())) {
|
||||
$collector->setCategories($this->getCategories());
|
||||
}
|
||||
$collector->withCategoryInformation()->withAccountInformation()->withBudgetInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$array = [];
|
||||
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$categoryId = (int)$journal['category_id'];
|
||||
$categoryName = (string)$journal['category_name'];
|
||||
|
||||
// catch "no category" entries.
|
||||
if (0 === $categoryId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// info about the currency:
|
||||
$array[$currencyId] = $array[$currencyId] ?? [
|
||||
'categories' => [],
|
||||
'currency_id' => $currencyId,
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
];
|
||||
|
||||
// info about the categories:
|
||||
$array[$currencyId]['categories'][$categoryId] = $array[$currencyId]['categories'][$categoryId] ?? [
|
||||
'id' => $categoryId,
|
||||
'name' => $categoryName,
|
||||
'transaction_journals' => [],
|
||||
];
|
||||
|
||||
// add journal to array:
|
||||
// only a subset of the fields.
|
||||
$journalId = (int)$journal['transaction_journal_id'];
|
||||
$array[$currencyId]['categories'][$categoryId]['transaction_journals'][$journalId] = [
|
||||
'amount' => app('steam')->negative($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'category_name' => $journal['category_name'],
|
||||
'source_account_name' => $journal['source_account_name'],
|
||||
'destination_account_id' => $journal['destination_account_id'],
|
||||
'destination_account_name' => $journal['destination_account_name'],
|
||||
'description' => $journal['description'],
|
||||
'transaction_group_id' => $journal['transaction_group_id'],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,20 @@ interface OperationsRepositoryInterface
|
||||
*/
|
||||
public function listExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* as possible. Amounts are always positive.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection|null $accounts
|
||||
* @param Collection|null $categories
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
/**
|
||||
* This method returns a list of all the transfer transaction journals (as arrays) set in that period
|
||||
* which have the specified category set to them, transferred INTO the listed accounts.
|
||||
@ -77,20 +91,6 @@ interface OperationsRepositoryInterface
|
||||
*/
|
||||
public function listTransferredOut(Carbon $start, Carbon $end, Collection $accounts, ?Collection $categories = null): array;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* as possible. Amounts are always positive.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection|null $accounts
|
||||
* @param Collection|null $categories
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function listIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
|
@ -48,19 +48,6 @@ 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
|
||||
*
|
||||
@ -163,6 +150,27 @@ 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
*
|
||||
@ -192,40 +200,6 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
$currency->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* Enables a currency
|
||||
*/
|
||||
public function enable(TransactionCurrency $currency): void
|
||||
{
|
||||
$currency->enabled = true;
|
||||
$currency->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find by ID, return NULL if not found.
|
||||
*
|
||||
* @param int $currencyId
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
public function find(int $currencyId): ?TransactionCurrency
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find by currency code, return NULL if unfound.
|
||||
* Used in Import Currency!
|
||||
@ -347,19 +321,45 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
* Find by ID, return NULL if not found.
|
||||
*
|
||||
* @param int $currencyId
|
||||
*
|
||||
* @return TransactionCurrency|null
|
||||
*/
|
||||
public function get(): Collection
|
||||
public function find(int $currencyId): ?TransactionCurrency
|
||||
{
|
||||
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionCurrency $currency
|
||||
* Enables a currency
|
||||
*/
|
||||
public function enable(TransactionCurrency $currency): void
|
||||
{
|
||||
$currency->enabled = true;
|
||||
$currency->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getAll(): Collection
|
||||
public function get(): Collection
|
||||
{
|
||||
return TransactionCurrency::orderBy('code', 'ASC')->get();
|
||||
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -80,30 +80,6 @@ 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,24 +97,6 @@ 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
|
||||
*/
|
||||
@ -188,6 +146,16 @@ class LinkTypeRepository implements LinkTypeRepositoryInterface
|
||||
return $query->get(['journal_links.*']);
|
||||
}
|
||||
|
||||
public function getLink(TransactionJournal $one, TransactionJournal $two): ?TransactionJournalLink
|
||||
{
|
||||
$left = TransactionJournalLink::whereDestinationId($one->id)->whereSourceId($two->id)->first();
|
||||
if (null !== $left) {
|
||||
return $left;
|
||||
}
|
||||
|
||||
return TransactionJournalLink::whereDestinationId($two->id)->whereSourceId($one->id)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of existing connections.
|
||||
*
|
||||
@ -282,6 +250,91 @@ 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
if (null !== $dbNote && '' === $text) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) { // @phpstan-ignore-line
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function switchLinkById(int $linkId): bool
|
||||
{
|
||||
/** @var TransactionJournalLink $link */
|
||||
$link = TransactionJournalLink::find($linkId);
|
||||
if (null !== $link && $link->source->user->id === $this->user->id) {
|
||||
$this->switchLink($link);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournalLink $link
|
||||
*
|
||||
@ -350,57 +403,4 @@ 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;
|
||||
}
|
||||
if (null !== $dbNote && '' === $text) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) { // @phpstan-ignore-line
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getLink(TransactionJournal $one, TransactionJournal $two): ?TransactionJournalLink
|
||||
{
|
||||
$left = TransactionJournalLink::whereDestinationId($one->id)->whereSourceId($two->id)->first();
|
||||
if (null !== $left) {
|
||||
return $left;
|
||||
}
|
||||
|
||||
return TransactionJournalLink::whereDestinationId($two->id)->whereSourceId($one->id)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function switchLinkById(int $linkId): bool
|
||||
{
|
||||
/** @var TransactionJournalLink $link */
|
||||
$link = TransactionJournalLink::find($linkId);
|
||||
if (null !== $link && $link->source->user->id === $this->user->id) {
|
||||
$this->switchLink($link);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -52,6 +52,17 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function get(): Collection
|
||||
{
|
||||
return $this->user->objectGroups()
|
||||
->with(['piggyBanks', 'bills'])
|
||||
->orderBy('order', 'ASC')
|
||||
->orderBy('title', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -81,17 +92,6 @@ 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,6 +151,32 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
|
||||
return $dbQuery->take($limit)->get(['object_groups.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$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
|
||||
*/
|
||||
@ -179,30 +205,4 @@ class ObjectGroupRepository implements ObjectGroupRepositoryInterface
|
||||
|
||||
return $objectGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -127,21 +127,6 @@ trait ModifiesPiggyBanks
|
||||
return bccomp($amount, $savedSoFar) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return PiggyBankEvent
|
||||
*/
|
||||
public function createEvent(PiggyBank $piggyBank, string $amount): PiggyBankEvent
|
||||
{
|
||||
if (0 === bccomp('0', $amount)) {
|
||||
return new PiggyBankEvent;
|
||||
}
|
||||
|
||||
return PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
@ -195,6 +180,21 @@ trait ModifiesPiggyBanks
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
*
|
||||
* @return PiggyBankEvent
|
||||
*/
|
||||
public function createEvent(PiggyBank $piggyBank, string $amount): PiggyBankEvent
|
||||
{
|
||||
if (0 === bccomp('0', $amount)) {
|
||||
return new PiggyBankEvent;
|
||||
}
|
||||
|
||||
return PiggyBankEvent::create(['date' => Carbon::now(), 'amount' => $amount, 'piggy_bank_id' => $piggyBank->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -205,23 +205,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++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param string $amount
|
||||
@ -262,34 +245,6 @@ trait ModifiesPiggyBanks
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
*
|
||||
@ -349,6 +304,82 @@ 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();
|
||||
if (null !== $dbNote) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) { // @phpstan-ignore-line
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
@ -416,37 +447,6 @@ 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();
|
||||
if (null !== $dbNote) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) { // @phpstan-ignore-line
|
||||
// @ignoreException
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -54,28 +54,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
$this->user->piggyBanks()->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $piggyBankId
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
*/
|
||||
public function find(int $piggyBankId): ?PiggyBank
|
||||
{
|
||||
return $this->user->piggyBanks()->find($piggyBankId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -107,6 +85,28 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $piggyBankId
|
||||
*
|
||||
* @return PiggyBank|null
|
||||
*/
|
||||
public function find(int $piggyBankId): ?PiggyBank
|
||||
{
|
||||
return $this->user->piggyBanks()->find($piggyBankId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -145,6 +145,16 @@ 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
|
||||
*
|
||||
@ -277,14 +287,6 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
return $note->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getPiggyBanks(): Collection
|
||||
{
|
||||
return $this->user->piggyBanks()->with(['account', 'objectGroups'])->orderBy('order', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Also add amount in name.
|
||||
*
|
||||
@ -307,13 +309,11 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return PiggyBankRepetition|null
|
||||
* @return Collection
|
||||
*/
|
||||
public function getRepetition(PiggyBank $piggyBank): ?PiggyBankRepetition
|
||||
public function getPiggyBanks(): Collection
|
||||
{
|
||||
return $piggyBank->piggyBankRepetitions()->first();
|
||||
return $this->user->piggyBanks()->with(['account', 'objectGroups'])->orderBy('order', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,6 +107,22 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getBillId(RecurrenceTransaction $recTransaction): ?int
|
||||
{
|
||||
$return = null;
|
||||
/** @var RecurrenceTransactionMeta $meta */
|
||||
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
||||
if ('bill_id' === $meta->name) {
|
||||
$return = (int) $meta->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the budget ID from a recurring transaction transaction.
|
||||
*
|
||||
@ -228,45 +244,6 @@ 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
|
||||
*
|
||||
@ -449,6 +426,27 @@ 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.
|
||||
*
|
||||
@ -576,6 +574,45 @@ 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.
|
||||
*
|
||||
@ -592,41 +629,4 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getBillId(RecurrenceTransaction $recTransaction): ?int
|
||||
{
|
||||
$return = null;
|
||||
/** @var RecurrenceTransactionMeta $meta */
|
||||
foreach ($recTransaction->recurrenceTransactionMeta as $meta) {
|
||||
if ('bill_id' === $meta->name) {
|
||||
$return = (int)$meta->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,15 @@ interface RecurringRepositoryInterface
|
||||
*/
|
||||
public function getAll(): Collection;
|
||||
|
||||
/**
|
||||
* Get the category from a recurring transaction transaction.
|
||||
*
|
||||
* @param RecurrenceTransaction $recTransaction
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function getBillId(RecurrenceTransaction $recTransaction): ?int;
|
||||
|
||||
/**
|
||||
* Get the budget ID from a recurring transaction transaction.
|
||||
*
|
||||
@ -82,15 +91,6 @@ interface RecurringRepositoryInterface
|
||||
*/
|
||||
public function getCategoryId(RecurrenceTransaction $recTransaction): ?int;
|
||||
|
||||
/**
|
||||
* Get the category from a recurring transaction transaction.
|
||||
*
|
||||
* @param RecurrenceTransaction $recTransaction
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function getBillId(RecurrenceTransaction $recTransaction): ?int;
|
||||
|
||||
/**
|
||||
* Get the category from a recurring transaction transaction.
|
||||
*
|
||||
|
@ -253,43 +253,6 @@ 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
|
||||
*/
|
||||
@ -305,42 +268,6 @@ 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 $user
|
||||
*/
|
||||
@ -404,23 +331,113 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $moment
|
||||
* @param Rule $rule
|
||||
* @param array $values
|
||||
*
|
||||
* @return RuleAction
|
||||
*/
|
||||
public function storeAction(Rule $rule, array $values): RuleAction
|
||||
private function setRuleTrigger(string $moment, Rule $rule): void
|
||||
{
|
||||
$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();
|
||||
/** @var RuleTrigger|null $trigger */
|
||||
$trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first();
|
||||
if (null !== $trigger) {
|
||||
$trigger->trigger_value = $moment;
|
||||
$trigger->save();
|
||||
|
||||
return $ruleAction;
|
||||
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
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function resetRuleOrder(RuleGroup $ruleGroup): bool
|
||||
{
|
||||
$groupRepository = app(RuleGroupRepositoryInterface::class);
|
||||
$groupRepository->setUser($ruleGroup->user);
|
||||
$groupRepository->resetRuleOrder($ruleGroup);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 bool
|
||||
*/
|
||||
private function storeTriggers(Rule $rule, array $data): bool
|
||||
{
|
||||
$order = 1;
|
||||
foreach ($data['triggers'] as $trigger) {
|
||||
$value = $trigger['value'] ?? '';
|
||||
$stopProcessing = $trigger['stop_processing'] ?? false;
|
||||
$active = $trigger['active'] ?? true;
|
||||
|
||||
$triggerValues = [
|
||||
'action' => $trigger['type'],
|
||||
'value' => $value,
|
||||
'stop_processing' => $stopProcessing,
|
||||
'order' => $order,
|
||||
'active' => $active,
|
||||
];
|
||||
$this->storeTrigger($rule, $triggerValues);
|
||||
++$order;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -443,6 +460,53 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
return $ruleTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function storeActions(Rule $rule, array $data): bool
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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
|
||||
@ -502,81 +566,17 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $moment
|
||||
* @param Rule $rule
|
||||
* @inheritDoc
|
||||
*/
|
||||
private function setRuleTrigger(string $moment, Rule $rule): void
|
||||
public function moveRule(Rule $rule, RuleGroup $ruleGroup, int $order): Rule
|
||||
{
|
||||
/** @var RuleTrigger|null $trigger */
|
||||
$trigger = $rule->ruleTriggers()->where('trigger_type', 'user_action')->first();
|
||||
if (null !== $trigger) {
|
||||
$trigger->trigger_value = $moment;
|
||||
$trigger->save();
|
||||
if ($rule->rule_group_id !== $ruleGroup->id) {
|
||||
$rule->rule_group_id = $ruleGroup->id;
|
||||
}
|
||||
$rule->save();
|
||||
$rule->refresh();
|
||||
$this->setOrder($rule, $order);
|
||||
|
||||
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 bool
|
||||
*/
|
||||
private function storeTriggers(Rule $rule, array $data): bool
|
||||
{
|
||||
$order = 1;
|
||||
foreach ($data['triggers'] as $trigger) {
|
||||
$value = $trigger['value'] ?? '';
|
||||
$stopProcessing = $trigger['stop_processing'] ?? false;
|
||||
$active = $trigger['active'] ?? true;
|
||||
|
||||
$triggerValues = [
|
||||
'action' => $trigger['type'],
|
||||
'value' => $value,
|
||||
'stop_processing' => $stopProcessing,
|
||||
'order' => $order,
|
||||
'active' => $active,
|
||||
];
|
||||
$this->storeTrigger($rule, $triggerValues);
|
||||
++$order;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function storeActions(Rule $rule, array $data): bool
|
||||
{
|
||||
$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;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $rule;
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,108 @@ 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
|
||||
*/
|
||||
@ -112,6 +214,14 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(): Collection
|
||||
{
|
||||
return $this->user->ruleGroups()->orderBy('order', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ruleGroupId
|
||||
*
|
||||
@ -132,14 +242,6 @@ 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
|
||||
*/
|
||||
@ -324,63 +426,6 @@ 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
|
||||
*/
|
||||
@ -396,32 +441,6 @@ 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 $user
|
||||
*/
|
||||
@ -455,6 +474,32 @@ 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
|
||||
@ -483,49 +528,4 @@ 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -114,6 +114,16 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
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
|
||||
@ -229,14 +239,4 @@ class OperationsRepository implements OperationsRepositoryInterface
|
||||
{
|
||||
throw new FireflyException(sprintf('%s is not yet implemented.', __METHOD__));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
private function getTags(): Collection
|
||||
{
|
||||
$repository = app(TagRepositoryInterface::class);
|
||||
|
||||
return $repository->get();
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,14 @@ class TagRepository implements TagRepositoryInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(): Collection
|
||||
{
|
||||
return $this->user->tags()->orderBy('tag', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Tag $tag
|
||||
* @param Carbon $start
|
||||
@ -134,14 +142,6 @@ class TagRepository implements TagRepositoryInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get(): Collection
|
||||
{
|
||||
return $this->user->tags()->orderBy('tag', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@ -162,14 +162,6 @@ class TagRepository implements TagRepositoryInterface
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getLocation(Tag $tag): ?Location
|
||||
{
|
||||
return $tag->locations()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $year
|
||||
*
|
||||
@ -458,4 +450,12 @@ class TagRepository implements TagRepositoryInterface
|
||||
return $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getLocation(Tag $tag): ?Location
|
||||
{
|
||||
return $tag->locations()->first();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -56,6 +56,18 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
{
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function countAttachments(int $journalId): int
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $this->user->transactionJournals()->find($journalId);
|
||||
|
||||
return $journal->attachments()->count();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionGroup $group
|
||||
*/
|
||||
@ -80,6 +92,56 @@ class TransactionGroupRepository implements TransactionGroupRepositoryInterface
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a transaction group by its ID.
|
||||
*
|
||||
@ -182,6 +244,56 @@ 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) {
|
||||
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
|
||||
*/
|
||||
@ -390,116 +502,4 @@ 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) {
|
||||
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
|
||||
*/
|
||||
public function countAttachments(int $journalId): int
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $this->user->transactionJournals()->find($journalId);
|
||||
|
||||
return $journal->attachments()->count();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,13 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface TransactionGroupRepositoryInterface
|
||||
{
|
||||
/**
|
||||
* @param int $journalId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAttachments(int $journalId): int;
|
||||
|
||||
/**
|
||||
* @param TransactionGroup $group
|
||||
*/
|
||||
@ -86,13 +93,6 @@ interface TransactionGroupRepositoryInterface
|
||||
*/
|
||||
public function getLocation(int $journalId): ?Location;
|
||||
|
||||
/**
|
||||
* @param int $journalId
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function countAttachments(int $journalId): int;
|
||||
|
||||
/**
|
||||
* Return object with all found meta field things as Carbon objects.
|
||||
*
|
||||
|
@ -33,18 +33,6 @@ use 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
|
||||
@ -69,6 +57,18 @@ 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
|
||||
|
@ -39,39 +39,6 @@ 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.
|
||||
@ -144,6 +111,14 @@ class UserRepository implements UserRepositoryInterface
|
||||
return $this->all()->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function all(): Collection
|
||||
{
|
||||
return User::orderBy('id', 'DESC')->get(['users.*']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $displayName
|
||||
@ -173,6 +148,22 @@ class UserRepository implements UserRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
*
|
||||
@ -203,16 +194,6 @@ class UserRepository implements UserRepositoryInterface
|
||||
return User::orderBy('id', 'ASC')->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $role
|
||||
*
|
||||
* @return Role|null
|
||||
*/
|
||||
public function getRole(string $role): ?Role
|
||||
{
|
||||
return Role::where('name', $role)->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
@ -284,21 +265,6 @@ class UserRepository implements UserRepositoryInterface
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -334,6 +300,31 @@ 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
|
||||
*/
|
||||
@ -402,18 +393,27 @@ class UserRepository implements UserRepositoryInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Remove any role the user has.
|
||||
*
|
||||
* @param User $user
|
||||
* @param string $role
|
||||
*/
|
||||
public function deleteEmptyGroups(): void
|
||||
public function removeRole(User $user, string $role): 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();
|
||||
}
|
||||
}
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
@ -39,11 +39,6 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function all(): Collection;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function deleteEmptyGroups(): void;
|
||||
|
||||
/**
|
||||
* Gives a user a role.
|
||||
*
|
||||
@ -100,6 +95,11 @@ interface UserRepositoryInterface
|
||||
*/
|
||||
public function createRole(string $name, string $displayName, string $description): Role;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public function deleteEmptyGroups(): void;
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*
|
||||
|
@ -512,6 +512,63 @@ trait AccountServiceTrait
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* See reference nr. 99
|
||||
*
|
||||
* @param TransactionGroup $group
|
||||
*
|
||||
* @return TransactionJournal
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getObJournal(TransactionGroup $group): TransactionJournal
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $group->transactionJournals()->first();
|
||||
if (null === $journal) {
|
||||
throw new FireflyException(sprintf('Group #%d has no OB journal', $group->id));
|
||||
}
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* See reference nr. 98
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getOBTransaction(TransactionJournal $journal, Account $account): Transaction
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->where('account_id', '!=', $account->id)->first();
|
||||
if (null === $transaction) {
|
||||
throw new FireflyException(sprintf('Could not get OB transaction for journal #%d', $journal->id));
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getNotOBTransaction(TransactionJournal $journal, Account $account): Transaction
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->where('account_id', $account->id)->first();
|
||||
if (null === $transaction) {
|
||||
throw new FireflyException(sprintf('Could not get non-OB transaction for journal #%d', $journal->id));
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update or create the opening balance group.
|
||||
* Since opening balance and date can still be empty strings, it may fail.
|
||||
@ -667,61 +724,4 @@ trait AccountServiceTrait
|
||||
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* See reference nr. 99
|
||||
*
|
||||
* @param TransactionGroup $group
|
||||
*
|
||||
* @return TransactionJournal
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getObJournal(TransactionGroup $group): TransactionJournal
|
||||
{
|
||||
/** @var TransactionJournal $journal */
|
||||
$journal = $group->transactionJournals()->first();
|
||||
if (null === $journal) {
|
||||
throw new FireflyException(sprintf('Group #%d has no OB journal', $group->id));
|
||||
}
|
||||
|
||||
return $journal;
|
||||
}
|
||||
|
||||
/**
|
||||
* See reference nr. 98
|
||||
*
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getOBTransaction(TransactionJournal $journal, Account $account): Transaction
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->where('account_id', '!=', $account->id)->first();
|
||||
if (null === $transaction) {
|
||||
throw new FireflyException(sprintf('Could not get OB transaction for journal #%d', $journal->id));
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TransactionJournal $journal
|
||||
* @param Account $account
|
||||
*
|
||||
* @return Transaction
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getNotOBTransaction(TransactionJournal $journal, Account $account): Transaction
|
||||
{
|
||||
/** @var Transaction $transaction */
|
||||
$transaction = $journal->transactions()->where('account_id', $account->id)->first();
|
||||
if (null === $transaction) {
|
||||
throw new FireflyException(sprintf('Could not get non-OB transaction for journal #%d', $journal->id));
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
}
|
||||
|
@ -109,32 +109,6 @@ trait JournalServiceTrait
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account|null $account
|
||||
* @param array $data
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
private function findAccountByName(?Account $account, array $data, array $types): ?Account
|
||||
{
|
||||
// second attempt, find by name.
|
||||
if (null === $account && null !== $data['name']) {
|
||||
// find by preferred type.
|
||||
$source = $this->accountRepository->findByName($data['name'], [$types[0]]);
|
||||
// or any expected type.
|
||||
$source = $source ?? $this->accountRepository->findByName($data['name'], $types);
|
||||
|
||||
if (null !== $source) {
|
||||
Log::debug(sprintf('Found "account_name" object: #%d, %s', $source->id, $source->name));
|
||||
|
||||
$account = $source;
|
||||
}
|
||||
}
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account|null $account
|
||||
* @param array $data
|
||||
@ -190,6 +164,32 @@ trait JournalServiceTrait
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account|null $account
|
||||
* @param array $data
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
private function findAccountByName(?Account $account, array $data, array $types): ?Account
|
||||
{
|
||||
// second attempt, find by name.
|
||||
if (null === $account && null !== $data['name']) {
|
||||
// find by preferred type.
|
||||
$source = $this->accountRepository->findByName($data['name'], [$types[0]]);
|
||||
// or any expected type.
|
||||
$source = $source ?? $this->accountRepository->findByName($data['name'], $types);
|
||||
|
||||
if (null !== $source) {
|
||||
Log::debug(sprintf('Found "account_name" object: #%d, %s', $source->id, $source->name));
|
||||
|
||||
$account = $source;
|
||||
}
|
||||
}
|
||||
|
||||
return $account;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account|null $account
|
||||
* @param array $data
|
||||
|
@ -53,7 +53,7 @@ class EitherConfigKey
|
||||
// triggers and actions:
|
||||
'firefly.rule-actions',
|
||||
'firefly.context-rule-actions',
|
||||
'search.operators'
|
||||
'search.operators',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -180,28 +180,6 @@ trait ConvertsDataTypes
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return date or NULL.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
protected function getCarbonDate(string $field): ?Carbon
|
||||
{
|
||||
$result = null;
|
||||
try {
|
||||
$result = $this->get($field) ? new Carbon($this->get($field)) : null;
|
||||
} catch (InvalidFormatException $e) {
|
||||
// @ignoreException
|
||||
}
|
||||
if (null === $result) {
|
||||
Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $string
|
||||
*
|
||||
@ -269,6 +247,28 @@ trait ConvertsDataTypes
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return date or NULL.
|
||||
*
|
||||
* @param string $field
|
||||
*
|
||||
* @return Carbon|null
|
||||
*/
|
||||
protected function getCarbonDate(string $field): ?Carbon
|
||||
{
|
||||
$result = null;
|
||||
try {
|
||||
$result = $this->get($field) ? new Carbon($this->get($field)) : null;
|
||||
} catch (InvalidFormatException $e) {
|
||||
// @ignoreException
|
||||
}
|
||||
if (null === $result) {
|
||||
Log::debug(sprintf('Exception when parsing date "%s".', $this->get($field)));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse to integer
|
||||
*
|
||||
|
@ -37,14 +37,13 @@ class AccountSearch implements GenericSearchInterface
|
||||
/** @var string */
|
||||
public const SEARCH_ALL = 'all';
|
||||
/** @var string */
|
||||
public const SEARCH_NAME = 'name';
|
||||
/** @var string */
|
||||
public const SEARCH_IBAN = 'iban';
|
||||
/** @var string */
|
||||
public const SEARCH_NUMBER = 'number';
|
||||
/** @var string */
|
||||
public const SEARCH_ID = 'id';
|
||||
|
||||
/** @var string */
|
||||
public const SEARCH_NAME = 'name';
|
||||
/** @var string */
|
||||
public const SEARCH_NUMBER = 'number';
|
||||
private string $field;
|
||||
private string $query;
|
||||
private array $types;
|
||||
|
@ -170,73 +170,6 @@ class OperatorQuerySearch implements SearchInterface
|
||||
$this->collector->setSearchWords($this->words);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function searchTime(): float
|
||||
{
|
||||
return microtime(true) - $this->startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function searchTransactions(): LengthAwarePaginator
|
||||
{
|
||||
if (empty($this->getWords()) && empty($this->getOperators())) {
|
||||
return new LengthAwarePaginator([], 0, 5, 1);
|
||||
}
|
||||
|
||||
return $this->collector->getPaginatedGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*/
|
||||
public function setDate(Carbon $date): void
|
||||
{
|
||||
$this->date = $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
*/
|
||||
public function setLimit(int $limit): void
|
||||
{
|
||||
$this->limit = $limit;
|
||||
$this->collector->setLimit($this->limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function setPage(int $page): void
|
||||
{
|
||||
$this->page = $page;
|
||||
$this->collector->setPage($this->page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->accountRepository->setUser($user);
|
||||
$this->billRepository->setUser($user);
|
||||
$this->categoryRepository->setUser($user);
|
||||
$this->budgetRepository->setUser($user);
|
||||
$this->tagRepository->setUser($user);
|
||||
$this->collector = app(GroupCollectorInterface::class);
|
||||
$this->collector->setUser($user);
|
||||
$this->collector->withAccountInformation()->withCategoryInformation()->withBudgetInformation();
|
||||
|
||||
$this->setLimit((int) app('preferences')->getForUser($user, 'listPageSize', 50)->data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Node $searchNode
|
||||
*
|
||||
@ -1152,14 +1085,6 @@ class OperatorQuerySearch implements SearchInterface
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getWords(): array
|
||||
{
|
||||
return $this->words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $range
|
||||
*
|
||||
@ -1199,46 +1124,6 @@ class OperatorQuerySearch implements SearchInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param array $range
|
||||
* @return void
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function setExactObjectDateParams(string $field,array $range): void
|
||||
{
|
||||
/**
|
||||
* @var string $key
|
||||
* @var Carbon|string $value
|
||||
*/
|
||||
foreach ($range as $key => $value) {
|
||||
switch ($key) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setExactObjectDateParams()', $key));
|
||||
case 'exact':
|
||||
Log::debug(sprintf('Set %s_is_exact value "%s"',$field, $value->format('Y-m-d')));
|
||||
$this->collector->setObjectRange($value, clone $value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on', $field), 'value' => $value->format('Y-m-d'),]);
|
||||
break;
|
||||
case 'year':
|
||||
Log::debug(sprintf('Set %s_is_exact YEAR value "%s"', $field, $value));
|
||||
$this->collector->objectYearIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_year', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'month':
|
||||
Log::debug(sprintf('Set %s_is_exact MONTH value "%s"', $field, $value));
|
||||
$this->collector->objectMonthIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_month', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'day':
|
||||
Log::debug(sprintf('Set %s_is_exact DAY value "%s"', $field, $value));
|
||||
$this->collector->objectDayIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_day', $field), 'value' => $value,]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $range
|
||||
*
|
||||
@ -1277,6 +1162,85 @@ class OperatorQuerySearch implements SearchInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $range
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function setDateAfterParams(array $range)
|
||||
{
|
||||
/**
|
||||
* @var string $key
|
||||
* @var Carbon|string $value
|
||||
*/
|
||||
foreach ($range as $key => $value) {
|
||||
switch ($key) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setDateAfterParams()', $key));
|
||||
case 'exact':
|
||||
$this->collector->setAfter($value);
|
||||
$this->operators->push(['type' => 'date_after', 'value' => $value->format('Y-m-d'),]);
|
||||
break;
|
||||
case 'year':
|
||||
Log::debug(sprintf('Set date_is_after YEAR value "%s"', $value));
|
||||
$this->collector->yearAfter($value);
|
||||
$this->operators->push(['type' => 'date_after_year', 'value' => $value,]);
|
||||
break;
|
||||
case 'month':
|
||||
Log::debug(sprintf('Set date_is_after MONTH value "%s"', $value));
|
||||
$this->collector->monthAfter($value);
|
||||
$this->operators->push(['type' => 'date_after_month', 'value' => $value,]);
|
||||
break;
|
||||
case 'day':
|
||||
Log::debug(sprintf('Set date_is_after DAY value "%s"', $value));
|
||||
$this->collector->dayAfter($value);
|
||||
$this->operators->push(['type' => 'date_after_day', 'value' => $value,]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param array $range
|
||||
* @return void
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function setExactMetaDateParams(string $field, array $range): void
|
||||
{
|
||||
Log::debug('Now in setExactMetaDateParams()');
|
||||
/**
|
||||
* @var string $key
|
||||
* @var Carbon|string $value
|
||||
*/
|
||||
foreach ($range as $key => $value) {
|
||||
switch ($key) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setExactMetaDateParams()', $key));
|
||||
case 'exact':
|
||||
Log::debug(sprintf('Set %s_is_exact value "%s"', $field, $value->format('Y-m-d')));
|
||||
$this->collector->setMetaDateRange($value, $value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on', $field), 'value' => $value->format('Y-m-d'),]);
|
||||
break;
|
||||
case 'year':
|
||||
Log::debug(sprintf('Set %s_is_exact YEAR value "%s"', $field, $value));
|
||||
$this->collector->metaYearIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_year', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'month':
|
||||
Log::debug(sprintf('Set %s_is_exact MONTH value "%s"', $field, $value));
|
||||
$this->collector->metaMonthIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_month', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'day':
|
||||
Log::debug(sprintf('Set %s_is_exact DAY value "%s"', $field, $value));
|
||||
$this->collector->metaDayIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_day', $field), 'value' => $value,]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param array $range
|
||||
@ -1356,11 +1320,12 @@ class OperatorQuerySearch implements SearchInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param array $range
|
||||
*
|
||||
* @return void
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function setDateAfterParams(array $range)
|
||||
private function setExactObjectDateParams(string $field, array $range): void
|
||||
{
|
||||
/**
|
||||
* @var string $key
|
||||
@ -1369,63 +1334,26 @@ class OperatorQuerySearch implements SearchInterface
|
||||
foreach ($range as $key => $value) {
|
||||
switch ($key) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setDateAfterParams()', $key));
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setExactObjectDateParams()', $key));
|
||||
case 'exact':
|
||||
$this->collector->setAfter($value);
|
||||
$this->operators->push(['type' => 'date_after', 'value' => $value->format('Y-m-d'),]);
|
||||
Log::debug(sprintf('Set %s_is_exact value "%s"', $field, $value->format('Y-m-d')));
|
||||
$this->collector->setObjectRange($value, clone $value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on', $field), 'value' => $value->format('Y-m-d'),]);
|
||||
break;
|
||||
case 'year':
|
||||
Log::debug(sprintf('Set date_is_after YEAR value "%s"', $value));
|
||||
$this->collector->yearAfter($value);
|
||||
$this->operators->push(['type' => 'date_after_year', 'value' => $value,]);
|
||||
Log::debug(sprintf('Set %s_is_exact YEAR value "%s"', $field, $value));
|
||||
$this->collector->objectYearIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_year', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'month':
|
||||
Log::debug(sprintf('Set date_is_after MONTH value "%s"', $value));
|
||||
$this->collector->monthAfter($value);
|
||||
$this->operators->push(['type' => 'date_after_month', 'value' => $value,]);
|
||||
Log::debug(sprintf('Set %s_is_exact MONTH value "%s"', $field, $value));
|
||||
$this->collector->objectMonthIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_month', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'day':
|
||||
Log::debug(sprintf('Set date_is_after DAY value "%s"', $value));
|
||||
$this->collector->dayAfter($value);
|
||||
$this->operators->push(['type' => 'date_after_day', 'value' => $value,]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $range
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function setObjectDateAfterParams(string $field, array $range)
|
||||
{
|
||||
/**
|
||||
* @var string $key
|
||||
* @var Carbon|string $value
|
||||
*/
|
||||
foreach ($range as $key => $value) {
|
||||
switch ($key) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setDateAfterParams()', $key));
|
||||
case 'exact':
|
||||
$this->collector->setObjectAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after', $field), 'value' => $value->format('Y-m-d'),]);
|
||||
break;
|
||||
case 'year':
|
||||
Log::debug(sprintf('Set date_is_after YEAR value "%s"', $value));
|
||||
$this->collector->objectYearAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after_year', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'month':
|
||||
Log::debug(sprintf('Set date_is_after MONTH value "%s"', $value));
|
||||
$this->collector->objectMonthAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after_month', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'day':
|
||||
Log::debug(sprintf('Set date_is_after DAY value "%s"', $value));
|
||||
$this->collector->objectDayAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after_day', $field), 'value' => $value,]);
|
||||
Log::debug(sprintf('Set %s_is_exact DAY value "%s"', $field, $value));
|
||||
$this->collector->objectDayIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_day', $field), 'value' => $value,]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1470,14 +1398,12 @@ class OperatorQuerySearch implements SearchInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $field
|
||||
* @param array $range
|
||||
* @return void
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function setExactMetaDateParams(string $field, array $range): void
|
||||
private function setObjectDateAfterParams(string $field, array $range)
|
||||
{
|
||||
Log::debug('Now in setExactMetaDateParams()');
|
||||
/**
|
||||
* @var string $key
|
||||
* @var Carbon|string $value
|
||||
@ -1485,28 +1411,102 @@ class OperatorQuerySearch implements SearchInterface
|
||||
foreach ($range as $key => $value) {
|
||||
switch ($key) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setExactMetaDateParams()', $key));
|
||||
throw new FireflyException(sprintf('Cannot handle key "%s" in setDateAfterParams()', $key));
|
||||
case 'exact':
|
||||
Log::debug(sprintf('Set %s_is_exact value "%s"', $field, $value->format('Y-m-d')));
|
||||
$this->collector->setMetaDateRange($value, $value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on', $field), 'value' => $value->format('Y-m-d'),]);
|
||||
$this->collector->setObjectAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after', $field), 'value' => $value->format('Y-m-d'),]);
|
||||
break;
|
||||
case 'year':
|
||||
Log::debug(sprintf('Set %s_is_exact YEAR value "%s"', $field, $value));
|
||||
$this->collector->metaYearIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_year', $field), 'value' => $value,]);
|
||||
Log::debug(sprintf('Set date_is_after YEAR value "%s"', $value));
|
||||
$this->collector->objectYearAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after_year', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'month':
|
||||
Log::debug(sprintf('Set %s_is_exact MONTH value "%s"', $field, $value));
|
||||
$this->collector->metaMonthIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_month', $field), 'value' => $value,]);
|
||||
Log::debug(sprintf('Set date_is_after MONTH value "%s"', $value));
|
||||
$this->collector->objectMonthAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after_month', $field), 'value' => $value,]);
|
||||
break;
|
||||
case 'day':
|
||||
Log::debug(sprintf('Set %s_is_exact DAY value "%s"', $field, $value));
|
||||
$this->collector->metaDayIs($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_on_day', $field), 'value' => $value,]);
|
||||
Log::debug(sprintf('Set date_is_after DAY value "%s"', $value));
|
||||
$this->collector->objectDayAfter($value, $field);
|
||||
$this->operators->push(['type' => sprintf('%s_after_day', $field), 'value' => $value,]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function searchTime(): float
|
||||
{
|
||||
return microtime(true) - $this->startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function searchTransactions(): LengthAwarePaginator
|
||||
{
|
||||
if (empty($this->getWords()) && empty($this->getOperators())) {
|
||||
return new LengthAwarePaginator([], 0, 5, 1);
|
||||
}
|
||||
|
||||
return $this->collector->getPaginatedGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getWords(): array
|
||||
{
|
||||
return $this->words;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Carbon $date
|
||||
*/
|
||||
public function setDate(Carbon $date): void
|
||||
{
|
||||
$this->date = $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function setPage(int $page): void
|
||||
{
|
||||
$this->page = $page;
|
||||
$this->collector->setPage($this->page);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->accountRepository->setUser($user);
|
||||
$this->billRepository->setUser($user);
|
||||
$this->categoryRepository->setUser($user);
|
||||
$this->budgetRepository->setUser($user);
|
||||
$this->tagRepository->setUser($user);
|
||||
$this->collector = app(GroupCollectorInterface::class);
|
||||
$this->collector->setUser($user);
|
||||
$this->collector->withAccountInformation()->withCategoryInformation()->withBudgetInformation();
|
||||
|
||||
$this->setLimit((int) app('preferences')->getForUser($user, 'listPageSize', 50)->data);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $limit
|
||||
*/
|
||||
public function setLimit(int $limit): void
|
||||
{
|
||||
$this->limit = $limit;
|
||||
$this->collector->setLimit($this->limit);
|
||||
}
|
||||
}
|
||||
|
@ -43,53 +43,6 @@ use Str;
|
||||
class Steam
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns the previous URL but refuses to send you to specific URLs.
|
||||
*
|
||||
* - outside domain
|
||||
* - to JS files, API or JSON routes
|
||||
*
|
||||
* Uses the session's previousUrl() function as inspired by GitHub user @z1r0-
|
||||
*
|
||||
* session()->previousUrl() uses getSafeUrl() so we can safely return it:
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSafePreviousUrl(): string
|
||||
{
|
||||
//Log::debug(sprintf('getSafePreviousUrl: "%s"', session()->previousUrl()));
|
||||
return session()->previousUrl() ?? route('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure URL is safe.
|
||||
*
|
||||
* @param string $unknownUrl
|
||||
* @param string $safeUrl
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSafeUrl(string $unknownUrl, string $safeUrl): string
|
||||
{
|
||||
//Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
|
||||
$returnUrl = $safeUrl;
|
||||
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
|
||||
$safeHost = parse_url($safeUrl, PHP_URL_HOST);
|
||||
|
||||
if (null !== $unknownHost && $unknownHost === $safeHost) {
|
||||
$returnUrl = $unknownUrl;
|
||||
}
|
||||
|
||||
// URL must not lead to weird pages
|
||||
$forbiddenWords = ['jscript', 'json', 'debug', 'serviceworker', 'offline', 'delete', '/login', '/attachments/view'];
|
||||
if (Str::contains($returnUrl, $forbiddenWords)) {
|
||||
$returnUrl = $safeUrl;
|
||||
}
|
||||
|
||||
return $returnUrl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param Carbon $date
|
||||
@ -391,6 +344,65 @@ class Steam
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filterSpaces(string $string): string
|
||||
{
|
||||
$search = [
|
||||
"\u{0001}", // start of heading
|
||||
"\u{0002}", // start of text
|
||||
"\u{0003}", // end of text
|
||||
"\u{0004}", // end of transmission
|
||||
"\u{0005}", // enquiry
|
||||
"\u{0006}", // ACK
|
||||
"\u{0007}", // BEL
|
||||
"\u{0008}", // backspace
|
||||
"\u{000E}", // shift out
|
||||
"\u{000F}", // shift in
|
||||
"\u{0010}", // data link escape
|
||||
"\u{0011}", // DC1
|
||||
"\u{0012}", // DC2
|
||||
"\u{0013}", // DC3
|
||||
"\u{0014}", // DC4
|
||||
"\u{0015}", // NAK
|
||||
"\u{0016}", // SYN
|
||||
"\u{0017}", // ETB
|
||||
"\u{0018}", // CAN
|
||||
"\u{0019}", // EM
|
||||
"\u{001A}", // SUB
|
||||
"\u{001B}", // escape
|
||||
"\u{001C}", // file separator
|
||||
"\u{001D}", // group separator
|
||||
"\u{001E}", // record separator
|
||||
"\u{001F}", // unit separator
|
||||
"\u{007F}", // DEL
|
||||
"\u{00A0}", // non-breaking space
|
||||
"\u{1680}", // ogham space mark
|
||||
"\u{180E}", // mongolian vowel separator
|
||||
"\u{2000}", // en quad
|
||||
"\u{2001}", // em quad
|
||||
"\u{2002}", // en space
|
||||
"\u{2003}", // em space
|
||||
"\u{2004}", // three-per-em space
|
||||
"\u{2005}", // four-per-em space
|
||||
"\u{2006}", // six-per-em space
|
||||
"\u{2007}", // figure space
|
||||
"\u{2008}", // punctuation space
|
||||
"\u{2009}", // thin space
|
||||
"\u{200A}", // hair space
|
||||
"\u{200B}", // zero width space
|
||||
"\u{202F}", // narrow no-break space
|
||||
"\u{3000}", // ideographic space
|
||||
"\u{FEFF}", // zero width no -break space
|
||||
"\x20", // plain old normal space
|
||||
];
|
||||
|
||||
return str_replace($search, '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $accounts
|
||||
*
|
||||
@ -463,6 +475,52 @@ class Steam
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the previous URL but refuses to send you to specific URLs.
|
||||
*
|
||||
* - outside domain
|
||||
* - to JS files, API or JSON routes
|
||||
*
|
||||
* Uses the session's previousUrl() function as inspired by GitHub user @z1r0-
|
||||
*
|
||||
* session()->previousUrl() uses getSafeUrl() so we can safely return it:
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSafePreviousUrl(): string
|
||||
{
|
||||
//Log::debug(sprintf('getSafePreviousUrl: "%s"', session()->previousUrl()));
|
||||
return session()->previousUrl() ?? route('index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure URL is safe.
|
||||
*
|
||||
* @param string $unknownUrl
|
||||
* @param string $safeUrl
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSafeUrl(string $unknownUrl, string $safeUrl): string
|
||||
{
|
||||
//Log::debug(sprintf('getSafeUrl(%s, %s)', $unknownUrl, $safeUrl));
|
||||
$returnUrl = $safeUrl;
|
||||
$unknownHost = parse_url($unknownUrl, PHP_URL_HOST);
|
||||
$safeHost = parse_url($safeUrl, PHP_URL_HOST);
|
||||
|
||||
if (null !== $unknownHost && $unknownHost === $safeHost) {
|
||||
$returnUrl = $unknownUrl;
|
||||
}
|
||||
|
||||
// URL must not lead to weird pages
|
||||
$forbiddenWords = ['jscript', 'json', 'debug', 'serviceworker', 'offline', 'delete', '/login', '/attachments/view'];
|
||||
if (Str::contains($returnUrl, $forbiddenWords)) {
|
||||
$returnUrl = $safeUrl;
|
||||
}
|
||||
|
||||
return $returnUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $amount
|
||||
*
|
||||
@ -573,63 +631,4 @@ class Steam
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filterSpaces(string $string): string
|
||||
{
|
||||
$search = [
|
||||
"\u{0001}", // start of heading
|
||||
"\u{0002}", // start of text
|
||||
"\u{0003}", // end of text
|
||||
"\u{0004}", // end of transmission
|
||||
"\u{0005}", // enquiry
|
||||
"\u{0006}", // ACK
|
||||
"\u{0007}", // BEL
|
||||
"\u{0008}", // backspace
|
||||
"\u{000E}", // shift out
|
||||
"\u{000F}", // shift in
|
||||
"\u{0010}", // data link escape
|
||||
"\u{0011}", // DC1
|
||||
"\u{0012}", // DC2
|
||||
"\u{0013}", // DC3
|
||||
"\u{0014}", // DC4
|
||||
"\u{0015}", // NAK
|
||||
"\u{0016}", // SYN
|
||||
"\u{0017}", // ETB
|
||||
"\u{0018}", // CAN
|
||||
"\u{0019}", // EM
|
||||
"\u{001A}", // SUB
|
||||
"\u{001B}", // escape
|
||||
"\u{001C}", // file separator
|
||||
"\u{001D}", // group separator
|
||||
"\u{001E}", // record separator
|
||||
"\u{001F}", // unit separator
|
||||
"\u{007F}", // DEL
|
||||
"\u{00A0}", // non-breaking space
|
||||
"\u{1680}", // ogham space mark
|
||||
"\u{180E}", // mongolian vowel separator
|
||||
"\u{2000}", // en quad
|
||||
"\u{2001}", // em quad
|
||||
"\u{2002}", // en space
|
||||
"\u{2003}", // em space
|
||||
"\u{2004}", // three-per-em space
|
||||
"\u{2005}", // four-per-em space
|
||||
"\u{2006}", // six-per-em space
|
||||
"\u{2007}", // figure space
|
||||
"\u{2008}", // punctuation space
|
||||
"\u{2009}", // thin space
|
||||
"\u{200A}", // hair space
|
||||
"\u{200B}", // zero width space
|
||||
"\u{202F}", // narrow no-break space
|
||||
"\u{3000}", // ideographic space
|
||||
"\u{FEFF}", // zero width no -break space
|
||||
"\x20", // plain old normal space
|
||||
];
|
||||
|
||||
return str_replace($search, '', $string);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user