mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-19 19:01:58 +00:00
Refactor code to traits.
This commit is contained in:
@@ -476,154 +476,4 @@ class BudgetController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the amount of money budgeted in a period.
|
|
||||||
*
|
|
||||||
* @param Budget $budget
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getBudgetedInPeriod(Budget $budget, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
$key = app('navigation')->preferredCarbonFormat($start, $end);
|
|
||||||
$range = app('navigation')->preferredRangeFormat($start, $end);
|
|
||||||
$current = clone $start;
|
|
||||||
$budgeted = [];
|
|
||||||
while ($current < $end) {
|
|
||||||
/** @var Carbon $currentStart */
|
|
||||||
$currentStart = app('navigation')->startOfPeriod($current, $range);
|
|
||||||
/** @var Carbon $currentEnd */
|
|
||||||
$currentEnd = app('navigation')->endOfPeriod($current, $range);
|
|
||||||
$budgetLimits = $this->repository->getBudgetLimits($budget, $currentStart, $currentEnd);
|
|
||||||
$index = $currentStart->format($key);
|
|
||||||
$budgeted[$index] = $budgetLimits->sum('amount');
|
|
||||||
$currentEnd->addDay();
|
|
||||||
$current = clone $currentEnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $budgeted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the expenses for a budget in a date range.
|
|
||||||
*
|
|
||||||
* @param Collection $limits
|
|
||||||
* @param Budget $budget
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*/
|
|
||||||
protected function getExpensesForBudget(Collection $limits, Budget $budget, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
$return = [];
|
|
||||||
if (0 === $limits->count()) {
|
|
||||||
$spent = $this->repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
|
||||||
if (0 !== bccomp($spent, '0')) {
|
|
||||||
$return[$budget->name]['spent'] = bcmul($spent, '-1');
|
|
||||||
$return[$budget->name]['left'] = 0;
|
|
||||||
$return[$budget->name]['overspent'] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$rows = $this->spentInPeriodMulti($budget, $limits);
|
|
||||||
foreach ($rows as $name => $row) {
|
|
||||||
if (0 !== bccomp($row['spent'], '0') || 0 !== bccomp($row['left'], '0')) {
|
|
||||||
$return[$name] = $row;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unset($rows);
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Returns an array with the following values:
|
|
||||||
* 0 =>
|
|
||||||
* 'name' => name of budget + repetition
|
|
||||||
* 'left' => left in budget repetition (always zero)
|
|
||||||
* 'overspent' => spent more than budget repetition? (always zero)
|
|
||||||
* 'spent' => actually spent in period for budget
|
|
||||||
* 1 => (etc)
|
|
||||||
*
|
|
||||||
* @param Budget $budget
|
|
||||||
* @param Collection $limits
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected function spentInPeriodMulti(Budget $budget, Collection $limits): array // get data + augment with info
|
|
||||||
{
|
|
||||||
$return = [];
|
|
||||||
$format = (string)trans('config.month_and_day');
|
|
||||||
$name = $budget->name;
|
|
||||||
/** @var BudgetLimit $budgetLimit */
|
|
||||||
foreach ($limits as $budgetLimit) {
|
|
||||||
$expenses = $this->repository->spentInPeriod(new Collection([$budget]), new Collection, $budgetLimit->start_date, $budgetLimit->end_date);
|
|
||||||
$expenses = app('steam')->positive($expenses);
|
|
||||||
|
|
||||||
if ($limits->count() > 1) {
|
|
||||||
$name = $budget->name . ' ' . trans(
|
|
||||||
'firefly.between_dates',
|
|
||||||
[
|
|
||||||
'start' => $budgetLimit->start_date->formatLocalized($format),
|
|
||||||
'end' => $budgetLimit->end_date->formatLocalized($format),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
$amount = $budgetLimit->amount;
|
|
||||||
$leftInLimit = bcsub($amount, $expenses);
|
|
||||||
$hasOverspent = bccomp($leftInLimit, '0') === -1;
|
|
||||||
$left = $hasOverspent ? '0' : bcsub($amount, $expenses);
|
|
||||||
$spent = $hasOverspent ? $amount : $expenses;
|
|
||||||
$overspent = $hasOverspent ? app('steam')->positive($leftInLimit) : '0';
|
|
||||||
|
|
||||||
$return[$name] = [
|
|
||||||
'left' => $left,
|
|
||||||
'overspent' => $overspent,
|
|
||||||
'spent' => $spent,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array with the following values:
|
|
||||||
* 'name' => "no budget" in local language
|
|
||||||
* 'repetition_left' => left in budget repetition (always zero)
|
|
||||||
* 'repetition_overspent' => spent more than budget repetition? (always zero)
|
|
||||||
* 'spent' => actually spent in period for budget.
|
|
||||||
*
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
protected function spentInPeriodWithout(Carbon $start, Carbon $end): string // get data + augment with info
|
|
||||||
{
|
|
||||||
// collector
|
|
||||||
/** @var TransactionCollectorInterface $collector */
|
|
||||||
$collector = app(TransactionCollectorInterface::class);
|
|
||||||
$types = [TransactionType::WITHDRAWAL];
|
|
||||||
$collector->setAllAssetAccounts()->setTypes($types)->setRange($start, $end)->withoutBudget();
|
|
||||||
$transactions = $collector->getTransactions();
|
|
||||||
$sum = '0';
|
|
||||||
/** @var Transaction $entry */
|
|
||||||
foreach ($transactions as $entry) {
|
|
||||||
$sum = bcadd($entry->transaction_amount, $sum);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
|||||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use FireflyIII\Support\Http\Controllers\AugumentData;
|
use FireflyIII\Support\Http\Controllers\AugumentData;
|
||||||
|
use FireflyIII\Support\Http\Controllers\ChartGeneration;
|
||||||
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
use FireflyIII\Support\Http\Controllers\DateCalculation;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -43,7 +44,7 @@ use Log;
|
|||||||
*/
|
*/
|
||||||
class CategoryController extends Controller
|
class CategoryController extends Controller
|
||||||
{
|
{
|
||||||
use DateCalculation, AugumentData;
|
use DateCalculation, AugumentData, ChartGeneration;
|
||||||
/** @var GeneratorInterface Chart generation methods. */
|
/** @var GeneratorInterface Chart generation methods. */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
@@ -393,91 +394,4 @@ class CategoryController extends Controller
|
|||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Chart for a specific period (start and end).
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @param Category $category
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
*/
|
|
||||||
protected function makePeriodChart(Category $category, Carbon $start, Carbon $end): array // chart helper method.
|
|
||||||
{
|
|
||||||
$cache = new CacheProperties;
|
|
||||||
$cache->addProperty($start);
|
|
||||||
$cache->addProperty($end);
|
|
||||||
$cache->addProperty($category->id);
|
|
||||||
$cache->addProperty('chart.category.period-chart');
|
|
||||||
|
|
||||||
|
|
||||||
if ($cache->has()) {
|
|
||||||
//return $cache->get(); // @codeCoverageIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var AccountRepositoryInterface $accountRepository */
|
|
||||||
$accountRepository = app(AccountRepositoryInterface::class);
|
|
||||||
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
|
||||||
$repository = app(CategoryRepositoryInterface::class);
|
|
||||||
|
|
||||||
// chart data
|
|
||||||
$chartData = [
|
|
||||||
[
|
|
||||||
'label' => (string)trans('firefly.spent'),
|
|
||||||
'entries' => [],
|
|
||||||
'type' => 'bar',
|
|
||||||
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => (string)trans('firefly.earned'),
|
|
||||||
'entries' => [],
|
|
||||||
'type' => 'bar',
|
|
||||||
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'label' => (string)trans('firefly.sum'),
|
|
||||||
'entries' => [],
|
|
||||||
'type' => 'line',
|
|
||||||
'fill' => false,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
$step = $this->calculateStep($start, $end);
|
|
||||||
|
|
||||||
|
|
||||||
while ($start <= $end) {
|
|
||||||
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $start);
|
|
||||||
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $start);
|
|
||||||
$sum = bcadd($spent, $earned);
|
|
||||||
$label = trim(app('navigation')->periodShow($start, $step));
|
|
||||||
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12);
|
|
||||||
$chartData[1]['entries'][$label] = round($earned, 12);
|
|
||||||
$chartData[2]['entries'][$label] = round($sum, 12);
|
|
||||||
|
|
||||||
switch ($step) {
|
|
||||||
default:
|
|
||||||
case '1D':
|
|
||||||
$start->addDay();
|
|
||||||
break;
|
|
||||||
case '1W':
|
|
||||||
$start->addDays(7);
|
|
||||||
break;
|
|
||||||
case '1M':
|
|
||||||
$start->addMonth();
|
|
||||||
break;
|
|
||||||
case '1Y':
|
|
||||||
$start->addYear();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = $this->generator->multiSet($chartData);
|
|
||||||
$cache->store($data);
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -28,9 +28,9 @@ use FireflyIII\Helpers\Report\NetWorthInterface;
|
|||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use FireflyIII\Support\Http\Controllers\BasicDataSupport;
|
use FireflyIII\Support\Http\Controllers\BasicDataSupport;
|
||||||
|
use FireflyIII\Support\Http\Controllers\ChartGeneration;
|
||||||
use Illuminate\Http\JsonResponse;
|
use Illuminate\Http\JsonResponse;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Log;
|
use Log;
|
||||||
@@ -40,7 +40,7 @@ use Log;
|
|||||||
*/
|
*/
|
||||||
class ReportController extends Controller
|
class ReportController extends Controller
|
||||||
{
|
{
|
||||||
use BasicDataSupport;
|
use BasicDataSupport, ChartGeneration;
|
||||||
/** @var GeneratorInterface Chart generation methods. */
|
/** @var GeneratorInterface Chart generation methods. */
|
||||||
protected $generator;
|
protected $generator;
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ class ReportController extends Controller
|
|||||||
// filter accounts on having the preference for being included.
|
// filter accounts on having the preference for being included.
|
||||||
/** @var AccountRepositoryInterface $accountRepository */
|
/** @var AccountRepositoryInterface $accountRepository */
|
||||||
$accountRepository = app(AccountRepositoryInterface::class);
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
$filtered = $accounts->filter(
|
$filtered = $accounts->filter(
|
||||||
function (Account $account) use ($accountRepository) {
|
function (Account $account) use ($accountRepository) {
|
||||||
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
|
$includeNetWorth = $accountRepository->getMetaValue($account, 'include_net_worth');
|
||||||
$result = null === $includeNetWorth ? true : '1' === $includeNetWorth;
|
$result = null === $includeNetWorth ? true : '1' === $includeNetWorth;
|
||||||
@@ -97,7 +97,6 @@ class ReportController extends Controller
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
while ($current < $end) {
|
while ($current < $end) {
|
||||||
// get balances by date, grouped by currency.
|
// get balances by date, grouped by currency.
|
||||||
$result = $helper->getNetWorthByCurrency($filtered, $current);
|
$result = $helper->getNetWorthByCurrency($filtered, $current);
|
||||||
@@ -263,67 +262,4 @@ class ReportController extends Controller
|
|||||||
|
|
||||||
return response()->json($data);
|
return response()->json($data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Collects the incomes and expenses for the given periods, grouped per month. Will cache its results.
|
|
||||||
*
|
|
||||||
* @param Collection $accounts
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
*/
|
|
||||||
protected function getChartData(Collection $accounts, Carbon $start, Carbon $end): array // chart helper function
|
|
||||||
{
|
|
||||||
$cache = new CacheProperties;
|
|
||||||
$cache->addProperty('chart.report.get-chart-data');
|
|
||||||
$cache->addProperty($start);
|
|
||||||
$cache->addProperty($accounts);
|
|
||||||
$cache->addProperty($end);
|
|
||||||
if ($cache->has()) {
|
|
||||||
return $cache->get(); // @codeCoverageIgnore
|
|
||||||
}
|
|
||||||
|
|
||||||
$currentStart = clone $start;
|
|
||||||
$spentArray = [];
|
|
||||||
$earnedArray = [];
|
|
||||||
|
|
||||||
/** @var AccountTaskerInterface $tasker */
|
|
||||||
$tasker = app(AccountTaskerInterface::class);
|
|
||||||
|
|
||||||
while ($currentStart <= $end) {
|
|
||||||
$currentEnd = app('navigation')->endOfPeriod($currentStart, '1M');
|
|
||||||
$earned = (string)array_sum(
|
|
||||||
array_map(
|
|
||||||
function ($item) {
|
|
||||||
return $item['sum'];
|
|
||||||
},
|
|
||||||
$tasker->getIncomeReport($currentStart, $currentEnd, $accounts)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$spent = (string)array_sum(
|
|
||||||
array_map(
|
|
||||||
function ($item) {
|
|
||||||
return $item['sum'];
|
|
||||||
},
|
|
||||||
$tasker->getExpenseReport($currentStart, $currentEnd, $accounts)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
$label = $currentStart->format('Y-m') . '-01';
|
|
||||||
$spentArray[$label] = bcmul($spent, '-1');
|
|
||||||
$earnedArray[$label] = $earned;
|
|
||||||
$currentStart = app('navigation')->addPeriod($currentStart, '1M', 0);
|
|
||||||
}
|
|
||||||
$result = [
|
|
||||||
'spent' => $spentArray,
|
|
||||||
'earned' => $earnedArray,
|
|
||||||
];
|
|
||||||
$cache->store($result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -340,294 +340,4 @@ class ExpenseController extends Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
|
||||||
/**
|
|
||||||
* Group by category (earnings).
|
|
||||||
*
|
|
||||||
* @param Collection $assets
|
|
||||||
* @param Collection $opposing
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
*/
|
|
||||||
protected function earnedByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
/** @var TransactionCollectorInterface $collector */
|
|
||||||
$collector = app(TransactionCollectorInterface::class);
|
|
||||||
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
|
|
||||||
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
|
|
||||||
$set = $collector->getTransactions();
|
|
||||||
$sum = [];
|
|
||||||
// loop to support multi currency
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$currencyId = $transaction->transaction_currency_id;
|
|
||||||
$categoryName = $transaction->transaction_category_name;
|
|
||||||
$categoryId = (int)$transaction->transaction_category_id;
|
|
||||||
// if null, grab from journal:
|
|
||||||
if (0 === $categoryId) {
|
|
||||||
$categoryName = $transaction->transaction_journal_category_name;
|
|
||||||
$categoryId = (int)$transaction->transaction_journal_category_id;
|
|
||||||
}
|
|
||||||
if (0 !== $categoryId) {
|
|
||||||
$categoryName = app('steam')->tryDecrypt($categoryName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not set, set to zero:
|
|
||||||
if (!isset($sum[$categoryId][$currencyId])) {
|
|
||||||
$sum[$categoryId] = [
|
|
||||||
'grand_total' => '0',
|
|
||||||
'name' => $categoryName,
|
|
||||||
'per_currency' => [
|
|
||||||
$currencyId => [
|
|
||||||
'sum' => '0',
|
|
||||||
'category' => [
|
|
||||||
'id' => $categoryId,
|
|
||||||
'name' => $categoryName,
|
|
||||||
],
|
|
||||||
'currency' => [
|
|
||||||
'symbol' => $transaction->transaction_currency_symbol,
|
|
||||||
'dp' => $transaction->transaction_currency_dp,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// add amount
|
|
||||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
|
|
||||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
|
|
||||||
);
|
|
||||||
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $transaction->transaction_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
|
||||||
/**
|
|
||||||
* Earned in period for accounts.
|
|
||||||
*
|
|
||||||
* @param Collection $assets
|
|
||||||
* @param Collection $opposing
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function earnedInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
/** @var TransactionCollectorInterface $collector */
|
|
||||||
$collector = app(TransactionCollectorInterface::class);
|
|
||||||
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
|
|
||||||
$collector->setOpposingAccounts($opposing);
|
|
||||||
$set = $collector->getTransactions();
|
|
||||||
$sum = [
|
|
||||||
'grand_sum' => '0',
|
|
||||||
'per_currency' => [],
|
|
||||||
];
|
|
||||||
// loop to support multi currency
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$currencyId = $transaction->transaction_currency_id;
|
|
||||||
|
|
||||||
// if not set, set to zero:
|
|
||||||
if (!isset($sum['per_currency'][$currencyId])) {
|
|
||||||
$sum['per_currency'][$currencyId] = [
|
|
||||||
'sum' => '0',
|
|
||||||
'currency' => [
|
|
||||||
'symbol' => $transaction->transaction_currency_symbol,
|
|
||||||
'dp' => $transaction->transaction_currency_dp,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// add amount
|
|
||||||
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $transaction->transaction_amount);
|
|
||||||
$sum['grand_sum'] = bcadd($sum['grand_sum'], $transaction->transaction_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
|
||||||
/**
|
|
||||||
* Spent by budget.
|
|
||||||
*
|
|
||||||
* @param Collection $assets
|
|
||||||
* @param Collection $opposing
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
*/
|
|
||||||
protected function spentByBudget(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
/** @var TransactionCollectorInterface $collector */
|
|
||||||
$collector = app(TransactionCollectorInterface::class);
|
|
||||||
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
|
||||||
$collector->setOpposingAccounts($opposing)->withBudgetInformation();
|
|
||||||
$set = $collector->getTransactions();
|
|
||||||
$sum = [];
|
|
||||||
// loop to support multi currency
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$currencyId = $transaction->transaction_currency_id;
|
|
||||||
$budgetName = $transaction->transaction_budget_name;
|
|
||||||
$budgetId = (int)$transaction->transaction_budget_id;
|
|
||||||
// if null, grab from journal:
|
|
||||||
if (0 === $budgetId) {
|
|
||||||
$budgetName = $transaction->transaction_journal_budget_name;
|
|
||||||
$budgetId = (int)$transaction->transaction_journal_budget_id;
|
|
||||||
}
|
|
||||||
if (0 !== $budgetId) {
|
|
||||||
$budgetName = app('steam')->tryDecrypt($budgetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not set, set to zero:
|
|
||||||
if (!isset($sum[$budgetId][$currencyId])) {
|
|
||||||
$sum[$budgetId] = [
|
|
||||||
'grand_total' => '0',
|
|
||||||
'name' => $budgetName,
|
|
||||||
'per_currency' => [
|
|
||||||
$currencyId => [
|
|
||||||
'sum' => '0',
|
|
||||||
'budget' => [
|
|
||||||
'id' => $budgetId,
|
|
||||||
'name' => $budgetName,
|
|
||||||
],
|
|
||||||
'currency' => [
|
|
||||||
'symbol' => $transaction->transaction_currency_symbol,
|
|
||||||
'dp' => $transaction->transaction_currency_dp,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// add amount
|
|
||||||
$sum[$budgetId]['per_currency'][$currencyId]['sum'] = bcadd(
|
|
||||||
$sum[$budgetId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
|
|
||||||
);
|
|
||||||
$sum[$budgetId]['grand_total'] = bcadd($sum[$budgetId]['grand_total'], $transaction->transaction_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
|
||||||
/**
|
|
||||||
* Spent by category.
|
|
||||||
*
|
|
||||||
* @param Collection $assets
|
|
||||||
* @param Collection $opposing
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
*/
|
|
||||||
protected function spentByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
/** @var TransactionCollectorInterface $collector */
|
|
||||||
$collector = app(TransactionCollectorInterface::class);
|
|
||||||
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
|
||||||
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
|
|
||||||
$set = $collector->getTransactions();
|
|
||||||
$sum = [];
|
|
||||||
// loop to support multi currency
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$currencyId = $transaction->transaction_currency_id;
|
|
||||||
$categoryName = $transaction->transaction_category_name;
|
|
||||||
$categoryId = (int)$transaction->transaction_category_id;
|
|
||||||
// if null, grab from journal:
|
|
||||||
if (0 === $categoryId) {
|
|
||||||
$categoryName = $transaction->transaction_journal_category_name;
|
|
||||||
$categoryId = (int)$transaction->transaction_journal_category_id;
|
|
||||||
}
|
|
||||||
if (0 !== $categoryId) {
|
|
||||||
$categoryName = app('steam')->tryDecrypt($categoryName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if not set, set to zero:
|
|
||||||
if (!isset($sum[$categoryId][$currencyId])) {
|
|
||||||
$sum[$categoryId] = [
|
|
||||||
'grand_total' => '0',
|
|
||||||
'name' => $categoryName,
|
|
||||||
'per_currency' => [
|
|
||||||
$currencyId => [
|
|
||||||
'sum' => '0',
|
|
||||||
'category' => [
|
|
||||||
'id' => $categoryId,
|
|
||||||
'name' => $categoryName,
|
|
||||||
],
|
|
||||||
'currency' => [
|
|
||||||
'symbol' => $transaction->transaction_currency_symbol,
|
|
||||||
'dp' => $transaction->transaction_currency_dp,
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// add amount
|
|
||||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
|
|
||||||
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
|
|
||||||
);
|
|
||||||
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $transaction->transaction_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
|
||||||
/**
|
|
||||||
* Spent in a period.
|
|
||||||
*
|
|
||||||
* @param Collection $assets
|
|
||||||
* @param Collection $opposing
|
|
||||||
* @param Carbon $start
|
|
||||||
* @param Carbon $end
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function spentInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
|
||||||
{
|
|
||||||
/** @var TransactionCollectorInterface $collector */
|
|
||||||
$collector = app(TransactionCollectorInterface::class);
|
|
||||||
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
|
||||||
$collector->setOpposingAccounts($opposing);
|
|
||||||
$set = $collector->getTransactions();
|
|
||||||
$sum = [
|
|
||||||
'grand_sum' => '0',
|
|
||||||
'per_currency' => [],
|
|
||||||
];
|
|
||||||
// loop to support multi currency
|
|
||||||
foreach ($set as $transaction) {
|
|
||||||
$currencyId = (int)$transaction->transaction_currency_id;
|
|
||||||
|
|
||||||
// if not set, set to zero:
|
|
||||||
if (!isset($sum['per_currency'][$currencyId])) {
|
|
||||||
$sum['per_currency'][$currencyId] = [
|
|
||||||
'sum' => '0',
|
|
||||||
'currency' => [
|
|
||||||
'symbol' => $transaction->transaction_currency_symbol,
|
|
||||||
'dp' => $transaction->transaction_currency_dp,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// add amount
|
|
||||||
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $transaction->transaction_amount);
|
|
||||||
$sum['grand_sum'] = bcadd($sum['grand_sum'], $transaction->transaction_amount);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sum;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,8 @@ use FireflyIII\Http\Requests\RuleFormRequest;
|
|||||||
use FireflyIII\Models\Bill;
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\RuleGroup;
|
use FireflyIII\Models\RuleGroup;
|
||||||
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Http\Controllers\AugumentData;
|
||||||
|
use FireflyIII\Support\Http\Controllers\ModelInformation;
|
||||||
use FireflyIII\Support\Http\Controllers\RuleManagement;
|
use FireflyIII\Support\Http\Controllers\RuleManagement;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -40,7 +42,7 @@ use Throwable;
|
|||||||
*/
|
*/
|
||||||
class CreateController extends Controller
|
class CreateController extends Controller
|
||||||
{
|
{
|
||||||
use RuleManagement;
|
use RuleManagement, ModelInformation;
|
||||||
/** @var RuleRepositoryInterface Rule repository */
|
/** @var RuleRepositoryInterface Rule repository */
|
||||||
private $ruleRepos;
|
private $ruleRepos;
|
||||||
|
|
||||||
@@ -199,78 +201,4 @@ class CreateController extends Controller
|
|||||||
return $redirect;
|
return $redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get actions based on a bill.
|
|
||||||
*
|
|
||||||
* @param Bill $bill
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getActionsForBill(Bill $bill): array // get info and augument
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$result = view(
|
|
||||||
'rules.partials.action',
|
|
||||||
[
|
|
||||||
'oldAction' => 'link_to_bill',
|
|
||||||
'oldValue' => $bill->name,
|
|
||||||
'oldChecked' => false,
|
|
||||||
'count' => 1,
|
|
||||||
]
|
|
||||||
)->render();
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
Log::error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
|
|
||||||
Log::error($e->getTraceAsString());
|
|
||||||
$result = 'Could not render view. See log files.';
|
|
||||||
}
|
|
||||||
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
|
|
||||||
return [$result];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create fake triggers to match the bill's properties
|
|
||||||
*
|
|
||||||
* @param Bill $bill
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getTriggersForBill(Bill $bill): array // get info and augument
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
$triggers = ['currency_is', 'amount_more', 'amount_less', 'description_contains'];
|
|
||||||
$values = [
|
|
||||||
$bill->transactionCurrency()->first()->name,
|
|
||||||
round((float)$bill->amount_min, 12),
|
|
||||||
round((float)$bill->amount_max, 12),
|
|
||||||
$bill->name,
|
|
||||||
];
|
|
||||||
foreach ($triggers as $index => $trigger) {
|
|
||||||
try {
|
|
||||||
$string = view(
|
|
||||||
'rules.partials.trigger',
|
|
||||||
[
|
|
||||||
'oldTrigger' => $trigger,
|
|
||||||
'oldValue' => $values[$index],
|
|
||||||
'oldChecked' => false,
|
|
||||||
'count' => $index + 1,
|
|
||||||
]
|
|
||||||
)->render();
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
|
|
||||||
Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
|
|
||||||
Log::debug($e->getTraceAsString());
|
|
||||||
$string = '';
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
}
|
|
||||||
if ('' !== $string) {
|
|
||||||
$result[] = $string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -30,6 +30,8 @@ use FireflyIII\Models\Rule;
|
|||||||
use FireflyIII\Models\RuleAction;
|
use FireflyIII\Models\RuleAction;
|
||||||
use FireflyIII\Models\RuleTrigger;
|
use FireflyIII\Models\RuleTrigger;
|
||||||
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||||
|
use FireflyIII\Support\Http\Controllers\ModelInformation;
|
||||||
|
use FireflyIII\Support\Http\Controllers\RenderPartialViews;
|
||||||
use FireflyIII\Support\Http\Controllers\RuleManagement;
|
use FireflyIII\Support\Http\Controllers\RuleManagement;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -41,7 +43,7 @@ use Throwable;
|
|||||||
*/
|
*/
|
||||||
class EditController extends Controller
|
class EditController extends Controller
|
||||||
{
|
{
|
||||||
use RuleManagement;
|
use RuleManagement, RenderPartialViews;
|
||||||
|
|
||||||
/** @var RuleRepositoryInterface Rule repository */
|
/** @var RuleRepositoryInterface Rule repository */
|
||||||
private $ruleRepos;
|
private $ruleRepos;
|
||||||
@@ -146,81 +148,4 @@ class EditController extends Controller
|
|||||||
|
|
||||||
return $redirect;
|
return $redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current (from system) rule actions.
|
|
||||||
*
|
|
||||||
* @param Rule $rule
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getCurrentActions(Rule $rule): array // get info from object and present.
|
|
||||||
{
|
|
||||||
$index = 0;
|
|
||||||
$actions = [];
|
|
||||||
$currentActions = $rule->ruleActions()->orderBy('order','ASC')->get();
|
|
||||||
/** @var RuleAction $entry */
|
|
||||||
foreach ($currentActions as $entry) {
|
|
||||||
$count = ($index + 1);
|
|
||||||
try {
|
|
||||||
$actions[] = view(
|
|
||||||
'rules.partials.action',
|
|
||||||
[
|
|
||||||
'oldAction' => $entry->action_type,
|
|
||||||
'oldValue' => $entry->action_value,
|
|
||||||
'oldChecked' => $entry->stop_processing,
|
|
||||||
'count' => $count,
|
|
||||||
]
|
|
||||||
)->render();
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
|
|
||||||
Log::error($e->getTraceAsString());
|
|
||||||
}
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
++$index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $actions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get current (from DB) rule triggers.
|
|
||||||
*
|
|
||||||
* @param Rule $rule
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
protected function getCurrentTriggers(Rule $rule): array // get info from object and present.
|
|
||||||
{
|
|
||||||
$index = 0;
|
|
||||||
$triggers = [];
|
|
||||||
$currentTriggers = $rule->ruleTriggers()->orderBy('order','ASC')->get();
|
|
||||||
/** @var RuleTrigger $entry */
|
|
||||||
foreach ($currentTriggers as $entry) {
|
|
||||||
if ('user_action' !== $entry->trigger_type) {
|
|
||||||
$count = ($index + 1);
|
|
||||||
try {
|
|
||||||
$triggers[] = view(
|
|
||||||
'rules.partials.trigger',
|
|
||||||
[
|
|
||||||
'oldTrigger' => $entry->trigger_type,
|
|
||||||
'oldValue' => $entry->trigger_value,
|
|
||||||
'oldChecked' => $entry->stop_processing,
|
|
||||||
'count' => $count,
|
|
||||||
]
|
|
||||||
)->render();
|
|
||||||
// @codeCoverageIgnoreStart
|
|
||||||
} catch (Throwable $e) {
|
|
||||||
Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
|
|
||||||
Log::error($e->getTraceAsString());
|
|
||||||
}
|
|
||||||
// @codeCoverageIgnoreEnd
|
|
||||||
++$index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $triggers;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -25,10 +25,8 @@ namespace FireflyIII\Http\Controllers\Transaction;
|
|||||||
use FireflyIII\Events\UpdatedTransactionJournal;
|
use FireflyIII\Events\UpdatedTransactionJournal;
|
||||||
use FireflyIII\Exceptions\FireflyException;
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
use FireflyIII\Http\Controllers\Controller;
|
use FireflyIII\Http\Controllers\Controller;
|
||||||
use FireflyIII\Models\Account;
|
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
|
||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
use FireflyIII\Support\Http\Controllers\ModelInformation;
|
use FireflyIII\Support\Http\Controllers\ModelInformation;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
@@ -163,6 +161,7 @@ class ConvertController extends Controller
|
|||||||
|
|
||||||
if ($errors->count() > 0) {
|
if ($errors->count() > 0) {
|
||||||
Log::error('Errors while converting: ', $errors->toArray());
|
Log::error('Errors while converting: ', $errors->toArray());
|
||||||
|
|
||||||
return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput();
|
return redirect(route('transactions.convert.index', [strtolower($destinationType->type), $journal->id]))->withErrors($errors)->withInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,126 +173,4 @@ class ConvertController extends Controller
|
|||||||
|
|
||||||
return redirect(route('transactions.show', [$journal->id]));
|
return redirect(route('transactions.show', [$journal->id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the destination account. Is complex.
|
|
||||||
*
|
|
||||||
* @param TransactionJournal $journal
|
|
||||||
* @param TransactionType $destinationType
|
|
||||||
* @param array $data
|
|
||||||
*
|
|
||||||
* @return Account
|
|
||||||
*
|
|
||||||
* @throws FireflyException
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*/
|
|
||||||
protected function getDestinationAccount(TransactionJournal $journal, TransactionType $destinationType, array $data
|
|
||||||
): Account // helper for conversion. Get info from obj.
|
|
||||||
{
|
|
||||||
/** @var AccountRepositoryInterface $accountRepository */
|
|
||||||
$accountRepository = app(AccountRepositoryInterface::class);
|
|
||||||
$sourceAccount = $this->repository->getJournalSourceAccounts($journal)->first();
|
|
||||||
$destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first();
|
|
||||||
$sourceType = $journal->transactionType;
|
|
||||||
$joined = $sourceType->type . '-' . $destinationType->type;
|
|
||||||
switch ($joined) {
|
|
||||||
default:
|
|
||||||
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
|
|
||||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT:
|
|
||||||
// one
|
|
||||||
$destination = $sourceAccount;
|
|
||||||
break;
|
|
||||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
|
|
||||||
// two
|
|
||||||
$destination = $accountRepository->findNull((int)$data['destination_account_asset']);
|
|
||||||
break;
|
|
||||||
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
|
|
||||||
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
|
|
||||||
// three and five
|
|
||||||
if ('' === $data['destination_account_expense'] || null === $data['destination_account_expense']) {
|
|
||||||
// destination is a cash account.
|
|
||||||
return $accountRepository->getCashAccount();
|
|
||||||
}
|
|
||||||
$data = [
|
|
||||||
'name' => $data['destination_account_expense'],
|
|
||||||
'accountType' => 'expense',
|
|
||||||
'account_type_id' => null,
|
|
||||||
'virtualBalance' => 0,
|
|
||||||
'active' => true,
|
|
||||||
'iban' => null,
|
|
||||||
];
|
|
||||||
$destination = $accountRepository->store($data);
|
|
||||||
break;
|
|
||||||
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
|
|
||||||
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT:
|
|
||||||
// four and six
|
|
||||||
$destination = $destinationAccount;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the source account.
|
|
||||||
*
|
|
||||||
* @param TransactionJournal $journal
|
|
||||||
* @param TransactionType $destinationType
|
|
||||||
* @param array $data
|
|
||||||
*
|
|
||||||
* @return Account
|
|
||||||
*
|
|
||||||
* @throws FireflyException
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*/
|
|
||||||
protected function getSourceAccount(TransactionJournal $journal, TransactionType $destinationType, array $data
|
|
||||||
): Account // helper for conversion. Get info from obj.
|
|
||||||
{
|
|
||||||
/** @var AccountRepositoryInterface $accountRepository */
|
|
||||||
$accountRepository = app(AccountRepositoryInterface::class);
|
|
||||||
$sourceAccount = $this->repository->getJournalSourceAccounts($journal)->first();
|
|
||||||
$destinationAccount = $this->repository->getJournalDestinationAccounts($journal)->first();
|
|
||||||
$sourceType = $journal->transactionType;
|
|
||||||
$joined = $sourceType->type . '-' . $destinationType->type;
|
|
||||||
switch ($joined) {
|
|
||||||
default:
|
|
||||||
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
|
|
||||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT:
|
|
||||||
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT:
|
|
||||||
|
|
||||||
if ('' === $data['source_account_revenue'] || null === $data['source_account_revenue']) {
|
|
||||||
// destination is a cash account.
|
|
||||||
return $accountRepository->getCashAccount();
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = [
|
|
||||||
'name' => $data['source_account_revenue'],
|
|
||||||
'accountType' => 'revenue',
|
|
||||||
'virtualBalance' => 0,
|
|
||||||
'active' => true,
|
|
||||||
'account_type_id' => null,
|
|
||||||
'iban' => null,
|
|
||||||
];
|
|
||||||
$source = $accountRepository->store($data);
|
|
||||||
break;
|
|
||||||
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
|
|
||||||
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
|
|
||||||
$source = $sourceAccount;
|
|
||||||
break;
|
|
||||||
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
|
|
||||||
$source = $destinationAccount;
|
|
||||||
break;
|
|
||||||
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
|
|
||||||
$source = $accountRepository->findNull((int)$data['source_account_asset']);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $source;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -171,42 +171,4 @@ class SplitController extends Controller
|
|||||||
return redirect($this->getPreviousUri('transactions.edit-split.uri'));
|
return redirect($this->getPreviousUri('transactions.edit-split.uri'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get info from old input.
|
|
||||||
*
|
|
||||||
* @param $array
|
|
||||||
* @param $old
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*
|
|
||||||
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
|
||||||
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
|
||||||
*/
|
|
||||||
protected function updateWithPrevious($array, $old): array // update object with new info
|
|
||||||
{
|
|
||||||
if (0 === \count($old) || !isset($old['transactions'])) {
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
$old = $old['transactions'];
|
|
||||||
|
|
||||||
foreach ($old as $index => $row) {
|
|
||||||
if (isset($array[$index])) {
|
|
||||||
/** @noinspection SlowArrayOperationsInLoopInspection */
|
|
||||||
$array[$index] = array_merge($array[$index], $row);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// take some info from first transaction, that should at least exist.
|
|
||||||
$array[$index] = $row;
|
|
||||||
$array[$index]['currency_id'] = $array[0]['currency_id'];
|
|
||||||
$array[$index]['currency_code'] = $array[0]['currency_code'] ?? '';
|
|
||||||
$array[$index]['currency_symbol'] = $array[0]['currency_symbol'] ?? '';
|
|
||||||
$array[$index]['foreign_amount'] = round($array[0]['foreign_destination_amount'] ?? '0', 12);
|
|
||||||
$array[$index]['foreign_currency_id'] = $array[0]['foreign_currency_id'];
|
|
||||||
$array[$index]['foreign_currency_code'] = $array[0]['foreign_currency_code'];
|
|
||||||
$array[$index]['foreign_currency_symbol'] = $array[0]['foreign_currency_symbol'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -24,17 +24,22 @@ declare(strict_types=1);
|
|||||||
namespace FireflyIII\Support\Http\Controllers;
|
namespace FireflyIII\Support\Http\Controllers;
|
||||||
|
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use FireflyIII\Helpers\Collector\TransactionCollectorInterface;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
use FireflyIII\Models\BudgetLimit;
|
use FireflyIII\Models\BudgetLimit;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Models\Transaction;
|
use FireflyIII\Models\Transaction;
|
||||||
|
use FireflyIII\Models\TransactionType;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
|
use Log;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait AugumentData
|
* Trait AugumentData
|
||||||
@@ -42,6 +47,8 @@ use Illuminate\Support\Collection;
|
|||||||
*/
|
*/
|
||||||
trait AugumentData
|
trait AugumentData
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches for the opposing account.
|
* Searches for the opposing account.
|
||||||
*
|
*
|
||||||
@@ -69,6 +76,116 @@ trait AugumentData
|
|||||||
return $combined;
|
return $combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group by category (earnings).
|
||||||
|
*
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
*/
|
||||||
|
protected function earnedByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var TransactionCollectorInterface $collector */
|
||||||
|
$collector = app(TransactionCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
|
||||||
|
$set = $collector->getTransactions();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
$categoryName = $transaction->transaction_category_name;
|
||||||
|
$categoryId = (int)$transaction->transaction_category_id;
|
||||||
|
// if null, grab from journal:
|
||||||
|
if (0 === $categoryId) {
|
||||||
|
$categoryName = $transaction->transaction_journal_category_name;
|
||||||
|
$categoryId = (int)$transaction->transaction_journal_category_id;
|
||||||
|
}
|
||||||
|
if (0 !== $categoryId) {
|
||||||
|
$categoryName = app('steam')->tryDecrypt($categoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$categoryId][$currencyId])) {
|
||||||
|
$sum[$categoryId] = [
|
||||||
|
'grand_total' => '0',
|
||||||
|
'name' => $categoryName,
|
||||||
|
'per_currency' => [
|
||||||
|
$currencyId => [
|
||||||
|
'sum' => '0',
|
||||||
|
'category' => [
|
||||||
|
'id' => $categoryId,
|
||||||
|
'name' => $categoryName,
|
||||||
|
],
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
|
||||||
|
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
|
||||||
|
);
|
||||||
|
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Earned in period for accounts.
|
||||||
|
*
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function earnedInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var TransactionCollectorInterface $collector */
|
||||||
|
$collector = app(TransactionCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing);
|
||||||
|
$set = $collector->getTransactions();
|
||||||
|
$sum = [
|
||||||
|
'grand_sum' => '0',
|
||||||
|
'per_currency' => [],
|
||||||
|
];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum['per_currency'][$currencyId])) {
|
||||||
|
$sum['per_currency'][$currencyId] = [
|
||||||
|
'sum' => '0',
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $transaction->transaction_amount);
|
||||||
|
$sum['grand_sum'] = bcadd($sum['grand_sum'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Small helper function for the revenue and expense account charts.
|
* Small helper function for the revenue and expense account charts.
|
||||||
*
|
*
|
||||||
@@ -180,6 +297,39 @@ trait AugumentData
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the amount of money budgeted in a period.
|
||||||
|
*
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getBudgetedInPeriod(Budget $budget, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
|
||||||
|
$key = app('navigation')->preferredCarbonFormat($start, $end);
|
||||||
|
$range = app('navigation')->preferredRangeFormat($start, $end);
|
||||||
|
$current = clone $start;
|
||||||
|
$budgeted = [];
|
||||||
|
while ($current < $end) {
|
||||||
|
/** @var Carbon $currentStart */
|
||||||
|
$currentStart = app('navigation')->startOfPeriod($current, $range);
|
||||||
|
/** @var Carbon $currentEnd */
|
||||||
|
$currentEnd = app('navigation')->endOfPeriod($current, $range);
|
||||||
|
$budgetLimits = $repository->getBudgetLimits($budget, $currentStart, $currentEnd);
|
||||||
|
$index = $currentStart->format($key);
|
||||||
|
$budgeted[$index] = $budgetLimits->sum('amount');
|
||||||
|
$currentEnd->addDay();
|
||||||
|
$current = clone $currentEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $budgeted;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the category names from a set of category ID's. Small helper function for some of the charts.
|
* Get the category names from a set of category ID's. Small helper function for some of the charts.
|
||||||
*
|
*
|
||||||
@@ -204,6 +354,46 @@ trait AugumentData
|
|||||||
return $return;
|
return $return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the expenses for a budget in a date range.
|
||||||
|
*
|
||||||
|
* @param Collection $limits
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
*/
|
||||||
|
protected function getExpensesForBudget(Collection $limits, Budget $budget, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
|
||||||
|
$return = [];
|
||||||
|
if (0 === $limits->count()) {
|
||||||
|
$spent = $repository->spentInPeriod(new Collection([$budget]), new Collection, $start, $end);
|
||||||
|
if (0 !== bccomp($spent, '0')) {
|
||||||
|
$return[$budget->name]['spent'] = bcmul($spent, '-1');
|
||||||
|
$return[$budget->name]['left'] = 0;
|
||||||
|
$return[$budget->name]['overspent'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = $this->spentInPeriodMulti($budget, $limits);
|
||||||
|
foreach ($rows as $name => $row) {
|
||||||
|
if (0 !== bccomp($row['spent'], '0') || 0 !== bccomp($row['left'], '0')) {
|
||||||
|
$return[$name] = $row;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($rows);
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets all budget limits for a budget.
|
* Gets all budget limits for a budget.
|
||||||
*
|
*
|
||||||
@@ -241,6 +431,7 @@ trait AugumentData
|
|||||||
return $set;
|
return $set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function that groups expenses.
|
* Helper function that groups expenses.
|
||||||
*
|
*
|
||||||
@@ -333,4 +524,277 @@ trait AugumentData
|
|||||||
|
|
||||||
return $grouped;
|
return $grouped;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spent by budget.
|
||||||
|
*
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
*/
|
||||||
|
protected function spentByBudget(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var TransactionCollectorInterface $collector */
|
||||||
|
$collector = app(TransactionCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing)->withBudgetInformation();
|
||||||
|
$set = $collector->getTransactions();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
$budgetName = $transaction->transaction_budget_name;
|
||||||
|
$budgetId = (int)$transaction->transaction_budget_id;
|
||||||
|
// if null, grab from journal:
|
||||||
|
if (0 === $budgetId) {
|
||||||
|
$budgetName = $transaction->transaction_journal_budget_name;
|
||||||
|
$budgetId = (int)$transaction->transaction_journal_budget_id;
|
||||||
|
}
|
||||||
|
if (0 !== $budgetId) {
|
||||||
|
$budgetName = app('steam')->tryDecrypt($budgetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$budgetId][$currencyId])) {
|
||||||
|
$sum[$budgetId] = [
|
||||||
|
'grand_total' => '0',
|
||||||
|
'name' => $budgetName,
|
||||||
|
'per_currency' => [
|
||||||
|
$currencyId => [
|
||||||
|
'sum' => '0',
|
||||||
|
'budget' => [
|
||||||
|
'id' => $budgetId,
|
||||||
|
'name' => $budgetName,
|
||||||
|
],
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$budgetId]['per_currency'][$currencyId]['sum'] = bcadd(
|
||||||
|
$sum[$budgetId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
|
||||||
|
);
|
||||||
|
$sum[$budgetId]['grand_total'] = bcadd($sum[$budgetId]['grand_total'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spent by category.
|
||||||
|
*
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
*/
|
||||||
|
protected function spentByCategory(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var TransactionCollectorInterface $collector */
|
||||||
|
$collector = app(TransactionCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing)->withCategoryInformation();
|
||||||
|
$set = $collector->getTransactions();
|
||||||
|
$sum = [];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = $transaction->transaction_currency_id;
|
||||||
|
$categoryName = $transaction->transaction_category_name;
|
||||||
|
$categoryId = (int)$transaction->transaction_category_id;
|
||||||
|
// if null, grab from journal:
|
||||||
|
if (0 === $categoryId) {
|
||||||
|
$categoryName = $transaction->transaction_journal_category_name;
|
||||||
|
$categoryId = (int)$transaction->transaction_journal_category_id;
|
||||||
|
}
|
||||||
|
if (0 !== $categoryId) {
|
||||||
|
$categoryName = app('steam')->tryDecrypt($categoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum[$categoryId][$currencyId])) {
|
||||||
|
$sum[$categoryId] = [
|
||||||
|
'grand_total' => '0',
|
||||||
|
'name' => $categoryName,
|
||||||
|
'per_currency' => [
|
||||||
|
$currencyId => [
|
||||||
|
'sum' => '0',
|
||||||
|
'category' => [
|
||||||
|
'id' => $categoryId,
|
||||||
|
'name' => $categoryName,
|
||||||
|
],
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum[$categoryId]['per_currency'][$currencyId]['sum'] = bcadd(
|
||||||
|
$sum[$categoryId]['per_currency'][$currencyId]['sum'], $transaction->transaction_amount
|
||||||
|
);
|
||||||
|
$sum[$categoryId]['grand_total'] = bcadd($sum[$categoryId]['grand_total'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Spent in a period.
|
||||||
|
*
|
||||||
|
* @param Collection $assets
|
||||||
|
* @param Collection $opposing
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function spentInPeriod(Collection $assets, Collection $opposing, Carbon $start, Carbon $end): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var TransactionCollectorInterface $collector */
|
||||||
|
$collector = app(TransactionCollectorInterface::class);
|
||||||
|
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setAccounts($assets);
|
||||||
|
$collector->setOpposingAccounts($opposing);
|
||||||
|
$set = $collector->getTransactions();
|
||||||
|
$sum = [
|
||||||
|
'grand_sum' => '0',
|
||||||
|
'per_currency' => [],
|
||||||
|
];
|
||||||
|
// loop to support multi currency
|
||||||
|
foreach ($set as $transaction) {
|
||||||
|
$currencyId = (int)$transaction->transaction_currency_id;
|
||||||
|
|
||||||
|
// if not set, set to zero:
|
||||||
|
if (!isset($sum['per_currency'][$currencyId])) {
|
||||||
|
$sum['per_currency'][$currencyId] = [
|
||||||
|
'sum' => '0',
|
||||||
|
'currency' => [
|
||||||
|
'symbol' => $transaction->transaction_currency_symbol,
|
||||||
|
'dp' => $transaction->transaction_currency_dp,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// add amount
|
||||||
|
$sum['per_currency'][$currencyId]['sum'] = bcadd($sum['per_currency'][$currencyId]['sum'], $transaction->transaction_amount);
|
||||||
|
$sum['grand_sum'] = bcadd($sum['grand_sum'], $transaction->transaction_amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Returns an array with the following values:
|
||||||
|
* 0 =>
|
||||||
|
* 'name' => name of budget + repetition
|
||||||
|
* 'left' => left in budget repetition (always zero)
|
||||||
|
* 'overspent' => spent more than budget repetition? (always zero)
|
||||||
|
* 'spent' => actually spent in period for budget
|
||||||
|
* 1 => (etc)
|
||||||
|
*
|
||||||
|
* @param Budget $budget
|
||||||
|
* @param Collection $limits
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function spentInPeriodMulti(Budget $budget, Collection $limits): array // get data + augment with info
|
||||||
|
{
|
||||||
|
/** @var BudgetRepositoryInterface $repository */
|
||||||
|
$repository = app(BudgetRepositoryInterface::class);
|
||||||
|
|
||||||
|
$return = [];
|
||||||
|
$format = (string)trans('config.month_and_day');
|
||||||
|
$name = $budget->name;
|
||||||
|
/** @var BudgetLimit $budgetLimit */
|
||||||
|
foreach ($limits as $budgetLimit) {
|
||||||
|
$expenses = $repository->spentInPeriod(new Collection([$budget]), new Collection, $budgetLimit->start_date, $budgetLimit->end_date);
|
||||||
|
$expenses = app('steam')->positive($expenses);
|
||||||
|
|
||||||
|
if ($limits->count() > 1) {
|
||||||
|
$name = $budget->name . ' ' . trans(
|
||||||
|
'firefly.between_dates',
|
||||||
|
[
|
||||||
|
'start' => $budgetLimit->start_date->formatLocalized($format),
|
||||||
|
'end' => $budgetLimit->end_date->formatLocalized($format),
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$amount = $budgetLimit->amount;
|
||||||
|
$leftInLimit = bcsub($amount, $expenses);
|
||||||
|
$hasOverspent = bccomp($leftInLimit, '0') === -1;
|
||||||
|
$left = $hasOverspent ? '0' : bcsub($amount, $expenses);
|
||||||
|
$spent = $hasOverspent ? $amount : $expenses;
|
||||||
|
$overspent = $hasOverspent ? app('steam')->positive($leftInLimit) : '0';
|
||||||
|
|
||||||
|
$return[$name] = [
|
||||||
|
'left' => $left,
|
||||||
|
'overspent' => $overspent,
|
||||||
|
'spent' => $spent,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array with the following values:
|
||||||
|
* 'name' => "no budget" in local language
|
||||||
|
* 'repetition_left' => left in budget repetition (always zero)
|
||||||
|
* 'repetition_overspent' => spent more than budget repetition? (always zero)
|
||||||
|
* 'spent' => actually spent in period for budget.
|
||||||
|
*
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function spentInPeriodWithout(Carbon $start, Carbon $end): string // get data + augment with info
|
||||||
|
{
|
||||||
|
// collector
|
||||||
|
/** @var TransactionCollectorInterface $collector */
|
||||||
|
$collector = app(TransactionCollectorInterface::class);
|
||||||
|
$types = [TransactionType::WITHDRAWAL];
|
||||||
|
$collector->setAllAssetAccounts()->setTypes($types)->setRange($start, $end)->withoutBudget();
|
||||||
|
$transactions = $collector->getTransactions();
|
||||||
|
$sum = '0';
|
||||||
|
/** @var Transaction $entry */
|
||||||
|
foreach ($transactions as $entry) {
|
||||||
|
$sum = bcadd($entry->transaction_amount, $sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $sum;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -90,4 +90,6 @@ trait BasicDataSupport
|
|||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,11 @@ namespace FireflyIII\Support\Http\Controllers;
|
|||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
use FireflyIII\Generator\Chart\Basic\GeneratorInterface;
|
||||||
use FireflyIII\Models\Account;
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\AccountType;
|
||||||
|
use FireflyIII\Models\Category;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
|
use FireflyIII\Repositories\Account\AccountTaskerInterface;
|
||||||
|
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||||
use FireflyIII\Support\CacheProperties;
|
use FireflyIII\Support\CacheProperties;
|
||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
@@ -103,4 +107,156 @@ trait ChartGeneration
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects the incomes and expenses for the given periods, grouped per month. Will cache its results.
|
||||||
|
*
|
||||||
|
* @param Collection $accounts
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
*/
|
||||||
|
protected function getChartData(Collection $accounts, Carbon $start, Carbon $end): array // chart helper function
|
||||||
|
{
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty('chart.report.get-chart-data');
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($accounts);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentStart = clone $start;
|
||||||
|
$spentArray = [];
|
||||||
|
$earnedArray = [];
|
||||||
|
|
||||||
|
/** @var AccountTaskerInterface $tasker */
|
||||||
|
$tasker = app(AccountTaskerInterface::class);
|
||||||
|
|
||||||
|
while ($currentStart <= $end) {
|
||||||
|
$currentEnd = app('navigation')->endOfPeriod($currentStart, '1M');
|
||||||
|
$earned = (string)array_sum(
|
||||||
|
array_map(
|
||||||
|
function ($item) {
|
||||||
|
return $item['sum'];
|
||||||
|
},
|
||||||
|
$tasker->getIncomeReport($currentStart, $currentEnd, $accounts)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$spent = (string)array_sum(
|
||||||
|
array_map(
|
||||||
|
function ($item) {
|
||||||
|
return $item['sum'];
|
||||||
|
},
|
||||||
|
$tasker->getExpenseReport($currentStart, $currentEnd, $accounts)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$label = $currentStart->format('Y-m') . '-01';
|
||||||
|
$spentArray[$label] = bcmul($spent, '-1');
|
||||||
|
$earnedArray[$label] = $earned;
|
||||||
|
$currentStart = app('navigation')->addPeriod($currentStart, '1M', 0);
|
||||||
|
}
|
||||||
|
$result = [
|
||||||
|
'spent' => $spentArray,
|
||||||
|
'earned' => $earnedArray,
|
||||||
|
];
|
||||||
|
$cache->store($result);
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Chart for a specific period (start and end).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param Category $category
|
||||||
|
* @param Carbon $start
|
||||||
|
* @param Carbon $end
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
*/
|
||||||
|
protected function makePeriodChart(Category $category, Carbon $start, Carbon $end): array // chart helper method.
|
||||||
|
{
|
||||||
|
$cache = new CacheProperties;
|
||||||
|
$cache->addProperty($start);
|
||||||
|
$cache->addProperty($end);
|
||||||
|
$cache->addProperty($category->id);
|
||||||
|
$cache->addProperty('chart.category.period-chart');
|
||||||
|
|
||||||
|
|
||||||
|
if ($cache->has()) {
|
||||||
|
return $cache->get(); // @codeCoverageIgnore
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var AccountRepositoryInterface $accountRepository */
|
||||||
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
$accounts = $accountRepository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]);
|
||||||
|
$repository = app(CategoryRepositoryInterface::class);
|
||||||
|
/** @var GeneratorInterface $generator */
|
||||||
|
$generator = app(GeneratorInterface::class);
|
||||||
|
|
||||||
|
// chart data
|
||||||
|
$chartData = [
|
||||||
|
[
|
||||||
|
'label' => (string)trans('firefly.spent'),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
'backgroundColor' => 'rgba(219, 68, 55, 0.5)', // red
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => (string)trans('firefly.earned'),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'bar',
|
||||||
|
'backgroundColor' => 'rgba(0, 141, 76, 0.5)', // green
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'label' => (string)trans('firefly.sum'),
|
||||||
|
'entries' => [],
|
||||||
|
'type' => 'line',
|
||||||
|
'fill' => false,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
$step = $this->calculateStep($start, $end);
|
||||||
|
|
||||||
|
|
||||||
|
while ($start <= $end) {
|
||||||
|
$spent = $repository->spentInPeriod(new Collection([$category]), $accounts, $start, $start);
|
||||||
|
$earned = $repository->earnedInPeriod(new Collection([$category]), $accounts, $start, $start);
|
||||||
|
$sum = bcadd($spent, $earned);
|
||||||
|
$label = trim(app('navigation')->periodShow($start, $step));
|
||||||
|
$chartData[0]['entries'][$label] = round(bcmul($spent, '-1'), 12);
|
||||||
|
$chartData[1]['entries'][$label] = round($earned, 12);
|
||||||
|
$chartData[2]['entries'][$label] = round($sum, 12);
|
||||||
|
|
||||||
|
switch ($step) {
|
||||||
|
default:
|
||||||
|
case '1D':
|
||||||
|
$start->addDay();
|
||||||
|
break;
|
||||||
|
case '1W':
|
||||||
|
$start->addDays(7);
|
||||||
|
break;
|
||||||
|
case '1M':
|
||||||
|
$start->addMonth();
|
||||||
|
break;
|
||||||
|
case '1Y':
|
||||||
|
$start->addYear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $generator->multiSet($chartData);
|
||||||
|
$cache->store($data);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
@@ -23,9 +23,15 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Support\Http\Controllers;
|
namespace FireflyIII\Support\Http\Controllers;
|
||||||
|
|
||||||
|
use FireflyIII\Exceptions\FireflyException;
|
||||||
|
use FireflyIII\Models\Account;
|
||||||
|
use FireflyIII\Models\Bill;
|
||||||
use FireflyIII\Models\TransactionJournal;
|
use FireflyIII\Models\TransactionJournal;
|
||||||
use FireflyIII\Models\TransactionType;
|
use FireflyIII\Models\TransactionType;
|
||||||
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||||
|
use Log;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trait ModelInformation
|
* Trait ModelInformation
|
||||||
@@ -33,6 +39,205 @@ use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
|||||||
*/
|
*/
|
||||||
trait ModelInformation
|
trait ModelInformation
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Get actions based on a bill.
|
||||||
|
*
|
||||||
|
* @param Bill $bill
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getActionsForBill(Bill $bill): array // get info and augument
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$result = view(
|
||||||
|
'rules.partials.action',
|
||||||
|
[
|
||||||
|
'oldAction' => 'link_to_bill',
|
||||||
|
'oldValue' => $bill->name,
|
||||||
|
'oldChecked' => false,
|
||||||
|
'count' => 1,
|
||||||
|
]
|
||||||
|
)->render();
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Log::error(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
|
||||||
|
Log::error($e->getTraceAsString());
|
||||||
|
$result = 'Could not render view. See log files.';
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
|
||||||
|
return [$result];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the destination account. Is complex.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param TransactionType $destinationType
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*
|
||||||
|
* @throws FireflyException
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
*/
|
||||||
|
protected function getDestinationAccount(TransactionJournal $journal, TransactionType $destinationType, array $data
|
||||||
|
): Account // helper for conversion. Get info from obj.
|
||||||
|
{
|
||||||
|
/** @var AccountRepositoryInterface $accountRepository */
|
||||||
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
/** @var JournalRepositoryInterface $journalRepos */
|
||||||
|
$journalRepos = app(JournalRepositoryInterface::class);
|
||||||
|
$sourceAccount = $journalRepos->getJournalSourceAccounts($journal)->first();
|
||||||
|
$destinationAccount = $journalRepos->getJournalDestinationAccounts($journal)->first();
|
||||||
|
$sourceType = $journal->transactionType;
|
||||||
|
$joined = $sourceType->type . '-' . $destinationType->type;
|
||||||
|
switch ($joined) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
|
||||||
|
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT:
|
||||||
|
// one
|
||||||
|
$destination = $sourceAccount;
|
||||||
|
break;
|
||||||
|
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
|
||||||
|
// two
|
||||||
|
$destination = $accountRepository->findNull((int)$data['destination_account_asset']);
|
||||||
|
break;
|
||||||
|
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
|
||||||
|
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
|
||||||
|
// three and five
|
||||||
|
if ('' === $data['destination_account_expense'] || null === $data['destination_account_expense']) {
|
||||||
|
// destination is a cash account.
|
||||||
|
return $accountRepository->getCashAccount();
|
||||||
|
}
|
||||||
|
$data = [
|
||||||
|
'name' => $data['destination_account_expense'],
|
||||||
|
'accountType' => 'expense',
|
||||||
|
'account_type_id' => null,
|
||||||
|
'virtualBalance' => 0,
|
||||||
|
'active' => true,
|
||||||
|
'iban' => null,
|
||||||
|
];
|
||||||
|
$destination = $accountRepository->store($data);
|
||||||
|
break;
|
||||||
|
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
|
||||||
|
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT:
|
||||||
|
// four and six
|
||||||
|
$destination = $destinationAccount;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the source account.
|
||||||
|
*
|
||||||
|
* @param TransactionJournal $journal
|
||||||
|
* @param TransactionType $destinationType
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return Account
|
||||||
|
*
|
||||||
|
* @throws FireflyException
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
*/
|
||||||
|
protected function getSourceAccount(TransactionJournal $journal, TransactionType $destinationType, array $data
|
||||||
|
): Account // helper for conversion. Get info from obj.
|
||||||
|
{
|
||||||
|
/** @var AccountRepositoryInterface $accountRepository */
|
||||||
|
$accountRepository = app(AccountRepositoryInterface::class);
|
||||||
|
/** @var JournalRepositoryInterface $journalRepos */
|
||||||
|
$journalRepos = app(JournalRepositoryInterface::class);
|
||||||
|
$sourceAccount = $journalRepos->getJournalSourceAccounts($journal)->first();
|
||||||
|
$destinationAccount = $journalRepos->getJournalDestinationAccounts($journal)->first();
|
||||||
|
$sourceType = $journal->transactionType;
|
||||||
|
$joined = $sourceType->type . '-' . $destinationType->type;
|
||||||
|
switch ($joined) {
|
||||||
|
default:
|
||||||
|
throw new FireflyException('Cannot handle ' . $joined); // @codeCoverageIgnore
|
||||||
|
case TransactionType::WITHDRAWAL . '-' . TransactionType::DEPOSIT:
|
||||||
|
case TransactionType::TRANSFER . '-' . TransactionType::DEPOSIT:
|
||||||
|
|
||||||
|
if ('' === $data['source_account_revenue'] || null === $data['source_account_revenue']) {
|
||||||
|
// destination is a cash account.
|
||||||
|
return $accountRepository->getCashAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [
|
||||||
|
'name' => $data['source_account_revenue'],
|
||||||
|
'accountType' => 'revenue',
|
||||||
|
'virtualBalance' => 0,
|
||||||
|
'active' => true,
|
||||||
|
'account_type_id' => null,
|
||||||
|
'iban' => null,
|
||||||
|
];
|
||||||
|
$source = $accountRepository->store($data);
|
||||||
|
break;
|
||||||
|
case TransactionType::WITHDRAWAL . '-' . TransactionType::TRANSFER:
|
||||||
|
case TransactionType::TRANSFER . '-' . TransactionType::WITHDRAWAL:
|
||||||
|
$source = $sourceAccount;
|
||||||
|
break;
|
||||||
|
case TransactionType::DEPOSIT . '-' . TransactionType::WITHDRAWAL:
|
||||||
|
$source = $destinationAccount;
|
||||||
|
break;
|
||||||
|
case TransactionType::DEPOSIT . '-' . TransactionType::TRANSFER:
|
||||||
|
$source = $accountRepository->findNull((int)$data['source_account_asset']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create fake triggers to match the bill's properties
|
||||||
|
*
|
||||||
|
* @param Bill $bill
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getTriggersForBill(Bill $bill): array // get info and augument
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
$triggers = ['currency_is', 'amount_more', 'amount_less', 'description_contains'];
|
||||||
|
$values = [
|
||||||
|
$bill->transactionCurrency()->first()->name,
|
||||||
|
round((float)$bill->amount_min, 12),
|
||||||
|
round((float)$bill->amount_max, 12),
|
||||||
|
$bill->name,
|
||||||
|
];
|
||||||
|
foreach ($triggers as $index => $trigger) {
|
||||||
|
try {
|
||||||
|
$string = view(
|
||||||
|
'rules.partials.trigger',
|
||||||
|
[
|
||||||
|
'oldTrigger' => $trigger,
|
||||||
|
'oldValue' => $values[$index],
|
||||||
|
'oldChecked' => false,
|
||||||
|
'count' => $index + 1,
|
||||||
|
]
|
||||||
|
)->render();
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
|
||||||
|
Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
|
||||||
|
Log::debug($e->getTraceAsString());
|
||||||
|
$string = '';
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
}
|
||||||
|
if ('' !== $string) {
|
||||||
|
$result[] = $string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is transaction opening balance?
|
* Is transaction opening balance?
|
||||||
*
|
*
|
||||||
|
@@ -23,11 +23,13 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace FireflyIII\Support\Http\Controllers;
|
namespace FireflyIII\Support\Http\Controllers;
|
||||||
|
|
||||||
|
|
||||||
use FireflyIII\Helpers\Collection\BalanceLine;
|
use FireflyIII\Helpers\Collection\BalanceLine;
|
||||||
use FireflyIII\Helpers\Report\PopupReportInterface;
|
use FireflyIII\Helpers\Report\PopupReportInterface;
|
||||||
use FireflyIII\Models\AccountType;
|
use FireflyIII\Models\AccountType;
|
||||||
use FireflyIII\Models\Budget;
|
use FireflyIII\Models\Budget;
|
||||||
|
use FireflyIII\Models\Rule;
|
||||||
|
use FireflyIII\Models\RuleAction;
|
||||||
|
use FireflyIII\Models\RuleTrigger;
|
||||||
use FireflyIII\Models\Tag;
|
use FireflyIII\Models\Tag;
|
||||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||||
@@ -43,6 +45,7 @@ use Throwable;
|
|||||||
*/
|
*/
|
||||||
trait RenderPartialViews
|
trait RenderPartialViews
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get options for account report.
|
* Get options for account report.
|
||||||
*
|
*
|
||||||
@@ -103,7 +106,7 @@ trait RenderPartialViews
|
|||||||
break;
|
break;
|
||||||
case BalanceLine::ROLE_DEFAULTROLE === $role && null === $budget && null !== $account:
|
case BalanceLine::ROLE_DEFAULTROLE === $role && null === $budget && null !== $account:
|
||||||
// normal row without a budget:
|
// normal row without a budget:
|
||||||
$budget = new Budget;
|
$budget = new Budget;
|
||||||
$journals = $popupHelper->balanceForNoBudget($account, $attributes);
|
$journals = $popupHelper->balanceForNoBudget($account, $attributes);
|
||||||
$budget->name = (string)trans('firefly.no_budget');
|
$budget->name = (string)trans('firefly.no_budget');
|
||||||
break;
|
break;
|
||||||
@@ -254,6 +257,85 @@ trait RenderPartialViews
|
|||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current (from system) rule actions.
|
||||||
|
*
|
||||||
|
* @param Rule $rule
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getCurrentActions(Rule $rule): array // get info from object and present.
|
||||||
|
{
|
||||||
|
$index = 0;
|
||||||
|
$actions = [];
|
||||||
|
// todo must be repos
|
||||||
|
$currentActions = $rule->ruleActions()->orderBy('order', 'ASC')->get();
|
||||||
|
/** @var RuleAction $entry */
|
||||||
|
foreach ($currentActions as $entry) {
|
||||||
|
$count = ($index + 1);
|
||||||
|
try {
|
||||||
|
$actions[] = view(
|
||||||
|
'rules.partials.action',
|
||||||
|
[
|
||||||
|
'oldAction' => $entry->action_type,
|
||||||
|
'oldValue' => $entry->action_value,
|
||||||
|
'oldChecked' => $entry->stop_processing,
|
||||||
|
'count' => $count,
|
||||||
|
]
|
||||||
|
)->render();
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
|
||||||
|
Log::error($e->getTraceAsString());
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
++$index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get current (from DB) rule triggers.
|
||||||
|
*
|
||||||
|
* @param Rule $rule
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
protected function getCurrentTriggers(Rule $rule): array // get info from object and present.
|
||||||
|
{
|
||||||
|
$index = 0;
|
||||||
|
$triggers = [];
|
||||||
|
// todo must be repos
|
||||||
|
$currentTriggers = $rule->ruleTriggers()->orderBy('order', 'ASC')->get();
|
||||||
|
/** @var RuleTrigger $entry */
|
||||||
|
foreach ($currentTriggers as $entry) {
|
||||||
|
if ('user_action' !== $entry->trigger_type) {
|
||||||
|
$count = ($index + 1);
|
||||||
|
try {
|
||||||
|
$triggers[] = view(
|
||||||
|
'rules.partials.trigger',
|
||||||
|
[
|
||||||
|
'oldTrigger' => $entry->trigger_type,
|
||||||
|
'oldValue' => $entry->trigger_value,
|
||||||
|
'oldChecked' => $entry->stop_processing,
|
||||||
|
'count' => $count,
|
||||||
|
]
|
||||||
|
)->render();
|
||||||
|
// @codeCoverageIgnoreStart
|
||||||
|
} catch (Throwable $e) {
|
||||||
|
Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
|
||||||
|
Log::error($e->getTraceAsString());
|
||||||
|
}
|
||||||
|
// @codeCoverageIgnoreEnd
|
||||||
|
++$index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $triggers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all the incomes that went to the given asset account.
|
* Returns all the incomes that went to the given asset account.
|
||||||
*
|
*
|
||||||
|
@@ -54,6 +54,43 @@ use Symfony\Component\HttpFoundation\ParameterBag;
|
|||||||
*/
|
*/
|
||||||
trait RequestInformation
|
trait RequestInformation
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Get info from old input.
|
||||||
|
*
|
||||||
|
* @param $array
|
||||||
|
* @param $old
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*
|
||||||
|
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
|
||||||
|
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
|
||||||
|
*/
|
||||||
|
protected function updateWithPrevious($array, $old): array // update object with new info
|
||||||
|
{
|
||||||
|
if (0 === \count($old) || !isset($old['transactions'])) {
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
$old = $old['transactions'];
|
||||||
|
|
||||||
|
foreach ($old as $index => $row) {
|
||||||
|
if (isset($array[$index])) {
|
||||||
|
/** @noinspection SlowArrayOperationsInLoopInspection */
|
||||||
|
$array[$index] = array_merge($array[$index], $row);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// take some info from first transaction, that should at least exist.
|
||||||
|
$array[$index] = $row;
|
||||||
|
$array[$index]['currency_id'] = $array[0]['currency_id'];
|
||||||
|
$array[$index]['currency_code'] = $array[0]['currency_code'] ?? '';
|
||||||
|
$array[$index]['currency_symbol'] = $array[0]['currency_symbol'] ?? '';
|
||||||
|
$array[$index]['foreign_amount'] = round($array[0]['foreign_destination_amount'] ?? '0', 12);
|
||||||
|
$array[$index]['foreign_currency_id'] = $array[0]['foreign_currency_id'];
|
||||||
|
$array[$index]['foreign_currency_code'] = $array[0]['foreign_currency_code'];
|
||||||
|
$array[$index]['foreign_currency_symbol'] = $array[0]['foreign_currency_symbol'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $array;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create data-array from a journal.
|
* Create data-array from a journal.
|
||||||
@@ -66,8 +103,10 @@ trait RequestInformation
|
|||||||
*/
|
*/
|
||||||
protected function arrayFromJournal(Request $request, TransactionJournal $journal): array // convert user input.
|
protected function arrayFromJournal(Request $request, TransactionJournal $journal): array // convert user input.
|
||||||
{
|
{
|
||||||
$sourceAccounts = $this->repository->getJournalSourceAccounts($journal);
|
/** @var JournalRepositoryInterface $repository */
|
||||||
$destinationAccounts = $this->repository->getJournalDestinationAccounts($journal);
|
$repository = app(JournalRepositoryInterface::class);
|
||||||
|
$sourceAccounts = $repository->getJournalSourceAccounts($journal);
|
||||||
|
$destinationAccounts = $repository->getJournalDestinationAccounts($journal);
|
||||||
$array = [
|
$array = [
|
||||||
'journal_description' => $request->old('journal_description', $journal->description),
|
'journal_description' => $request->old('journal_description', $journal->description),
|
||||||
'journal_amount' => '0',
|
'journal_amount' => '0',
|
||||||
@@ -82,14 +121,14 @@ trait RequestInformation
|
|||||||
'tags' => implode(',', $journal->tags->pluck('tag')->toArray()),
|
'tags' => implode(',', $journal->tags->pluck('tag')->toArray()),
|
||||||
|
|
||||||
// all custom fields:
|
// all custom fields:
|
||||||
'interest_date' => $request->old('interest_date', $this->repository->getMetaField($journal, 'interest_date')),
|
'interest_date' => $request->old('interest_date', $repository->getMetaField($journal, 'interest_date')),
|
||||||
'book_date' => $request->old('book_date', $this->repository->getMetaField($journal, 'book_date')),
|
'book_date' => $request->old('book_date', $repository->getMetaField($journal, 'book_date')),
|
||||||
'process_date' => $request->old('process_date', $this->repository->getMetaField($journal, 'process_date')),
|
'process_date' => $request->old('process_date', $repository->getMetaField($journal, 'process_date')),
|
||||||
'due_date' => $request->old('due_date', $this->repository->getMetaField($journal, 'due_date')),
|
'due_date' => $request->old('due_date', $repository->getMetaField($journal, 'due_date')),
|
||||||
'payment_date' => $request->old('payment_date', $this->repository->getMetaField($journal, 'payment_date')),
|
'payment_date' => $request->old('payment_date', $repository->getMetaField($journal, 'payment_date')),
|
||||||
'invoice_date' => $request->old('invoice_date', $this->repository->getMetaField($journal, 'invoice_date')),
|
'invoice_date' => $request->old('invoice_date', $repository->getMetaField($journal, 'invoice_date')),
|
||||||
'internal_reference' => $request->old('internal_reference', $this->repository->getMetaField($journal, 'internal_reference')),
|
'internal_reference' => $request->old('internal_reference', $repository->getMetaField($journal, 'internal_reference')),
|
||||||
'notes' => $request->old('notes', $this->repository->getNoteText($journal)),
|
'notes' => $request->old('notes', $repository->getNoteText($journal)),
|
||||||
|
|
||||||
// transactions.
|
// transactions.
|
||||||
'transactions' => $this->getTransactionDataFromJournal($journal),
|
'transactions' => $this->getTransactionDataFromJournal($journal),
|
||||||
|
Reference in New Issue
Block a user