mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-12 15:35:15 +00:00
@@ -27,13 +27,16 @@ namespace FireflyIII\Api\V1\Controllers\Chart;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Data\DateRequest;
|
||||
use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Chart\ChartData;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use FireflyIII\Support\Http\Api\ApiSupport;
|
||||
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
@@ -43,8 +46,10 @@ use Illuminate\Http\JsonResponse;
|
||||
class AccountController extends Controller
|
||||
{
|
||||
use ApiSupport;
|
||||
use CollectsAccountsFromFilter;
|
||||
|
||||
private AccountRepositoryInterface $repository;
|
||||
private ChartData $chartData;
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
@@ -56,6 +61,7 @@ class AccountController extends Controller
|
||||
function ($request, $next) {
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$this->chartData = new ChartData();
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->repository->setUser($user);
|
||||
|
||||
@@ -64,6 +70,30 @@ class AccountController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* TODO fix documentation
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function dashboard(ChartRequest $request): JsonResponse
|
||||
{
|
||||
$queryParameters = $request->getParameters();
|
||||
$accounts = $this->getAccountList($queryParameters);
|
||||
|
||||
// move date to end of day
|
||||
$queryParameters['start']->startOfDay();
|
||||
$queryParameters['end']->endOfDay();
|
||||
|
||||
// loop each account, and collect info:
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$this->renderAccountData($queryParameters, $account);
|
||||
}
|
||||
|
||||
return response()->json($this->chartData->render());
|
||||
}
|
||||
|
||||
/**
|
||||
* This endpoint is documented at:
|
||||
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/charts/getChartAccountOverview
|
||||
@@ -133,4 +163,46 @@ class AccountController extends Controller
|
||||
|
||||
return response()->json($chartData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function renderAccountData(array $params, Account $account): void
|
||||
{
|
||||
$currency = $this->repository->getAccountCurrency($account);
|
||||
if (null === $currency) {
|
||||
$currency = $this->default;
|
||||
}
|
||||
$currentSet = [
|
||||
'label' => $account->name,
|
||||
|
||||
// the currency that belongs to the account.
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
|
||||
// the default currency of the user (could be the same!)
|
||||
'date' => $params['start']->toAtomString(),
|
||||
'start' => $params['start']->toAtomString(),
|
||||
'end' => $params['end']->toAtomString(),
|
||||
'period' => '1D',
|
||||
'entries' => [],
|
||||
];
|
||||
$currentStart = clone $params['start'];
|
||||
$range = Steam::finalAccountBalanceInRange($account, $params['start'], clone $params['end'], $this->convertToNative);
|
||||
|
||||
$previous = array_values($range)[0]['balance'];
|
||||
while ($currentStart <= $params['end']) {
|
||||
$format = $currentStart->format('Y-m-d');
|
||||
$label = $currentStart->toAtomString();
|
||||
$balance = array_key_exists($format, $range) ? $range[$format]['balance'] : $previous;
|
||||
$previous = $balance;
|
||||
|
||||
$currentStart->addDay();
|
||||
$currentSet['entries'][$label] = $balance;
|
||||
}
|
||||
$this->chartData->add($currentSet);
|
||||
}
|
||||
}
|
||||
|
260
app/Api/V1/Controllers/Chart/BudgetController.php
Normal file
260
app/Api/V1/Controllers/Chart/BudgetController.php
Normal file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* BudgetController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Generic\DateRequest;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*/
|
||||
class BudgetController extends Controller
|
||||
{
|
||||
use CleansChartData;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
|
||||
|
||||
protected OperationsRepositoryInterface $opsRepository;
|
||||
private BudgetLimitRepositoryInterface $blRepository;
|
||||
private array $currencies = [];
|
||||
private TransactionCurrency $currency;
|
||||
private BudgetRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
$this->blRepository = app(BudgetLimitRepositoryInterface::class);
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
$this->opsRepository->setUserGroup($userGroup);
|
||||
$this->blRepository->setUserGroup($userGroup);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO see autocomplete/accountcontroller
|
||||
*/
|
||||
public function dashboard(DateRequest $request): JsonResponse
|
||||
{
|
||||
$params = $request->getAll();
|
||||
|
||||
/** @var Carbon $start */
|
||||
$start = $params['start'];
|
||||
|
||||
/** @var Carbon $end */
|
||||
$end = $params['end'];
|
||||
|
||||
// code from FrontpageChartGenerator, but not in separate class
|
||||
$budgets = $this->repository->getActiveBudgets();
|
||||
$data = [];
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
// could return multiple arrays, so merge.
|
||||
$data = array_merge($data, $this->processBudget($budget, $start, $end));
|
||||
}
|
||||
|
||||
return response()->json($this->clean($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function processBudget(Budget $budget, Carbon $start, Carbon $end): array
|
||||
{
|
||||
// get all limits:
|
||||
$limits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
$rows = [];
|
||||
|
||||
// if no limits
|
||||
if (0 === $limits->count()) {
|
||||
// return as a single item in an array
|
||||
$rows = $this->noBudgetLimits($budget, $start, $end);
|
||||
}
|
||||
if ($limits->count() > 0) {
|
||||
$rows = $this->budgetLimits($budget, $limits);
|
||||
}
|
||||
// is always an array
|
||||
$return = [];
|
||||
foreach ($rows as $row) {
|
||||
$current = [
|
||||
'label' => $budget->name,
|
||||
'currency_id' => (string) $row['currency_id'],
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_name' => $row['currency_name'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'period' => null,
|
||||
'start' => $row['start'],
|
||||
'end' => $row['end'],
|
||||
'entries' => [
|
||||
'spent' => $row['spent'],
|
||||
'left' => $row['left'],
|
||||
'overspent' => $row['overspent'],
|
||||
],
|
||||
];
|
||||
$return[] = $current;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* When no budget limits are present, the expenses of the whole period are collected and grouped.
|
||||
* This is grouped per currency. Because there is no limit set, "left to spend" and "overspent" are empty.
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function noBudgetLimits(Budget $budget, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, null, new Collection([$budget]));
|
||||
|
||||
return $this->processExpenses($budget->id, $spent, $start, $end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shared between the "noBudgetLimits" function and "processLimit". Will take a single set of expenses and return
|
||||
* its info.
|
||||
*
|
||||
* @param array<int, array<int, string>> $array
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function processExpenses(int $budgetId, array $array, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$return = [];
|
||||
|
||||
/**
|
||||
* This array contains the expenses in this budget. Grouped per currency.
|
||||
* The grouping is on the main currency only.
|
||||
*
|
||||
* @var int $currencyId
|
||||
* @var array $block
|
||||
*/
|
||||
foreach ($array as $currencyId => $block) {
|
||||
$this->currencies[$currencyId] ??= TransactionCurrency::find($currencyId);
|
||||
$return[$currencyId] ??= [
|
||||
'currency_id' => (string) $currencyId,
|
||||
'currency_code' => $block['currency_code'],
|
||||
'currency_name' => $block['currency_name'],
|
||||
'currency_symbol' => $block['currency_symbol'],
|
||||
'currency_decimal_places' => (int) $block['currency_decimal_places'],
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'spent' => '0',
|
||||
'left' => '0',
|
||||
'overspent' => '0',
|
||||
];
|
||||
$currentBudgetArray = $block['budgets'][$budgetId];
|
||||
|
||||
// var_dump($return);
|
||||
/** @var array $journal */
|
||||
foreach ($currentBudgetArray['transaction_journals'] as $journal) {
|
||||
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']);
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that processes each budget limit (per budget).
|
||||
*
|
||||
* If you have a budget limit in EUR, only transactions in EUR will be considered.
|
||||
* If you have a budget limit in GBP, only transactions in GBP will be considered.
|
||||
*
|
||||
* If you have a budget limit in EUR, and a transaction in GBP, it will not be considered for the EUR budget limit.
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function budgetLimits(Budget $budget, Collection $limits): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in budgetLimits(#%d)', $budget->id));
|
||||
$data = [];
|
||||
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($limits as $limit) {
|
||||
$data = array_merge($data, $this->processLimit($budget, $limit));
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function processLimit(Budget $budget, BudgetLimit $limit): array
|
||||
{
|
||||
Log::debug(sprintf('Created new ExchangeRateConverter in %s', __METHOD__));
|
||||
$end = clone $limit->end_date;
|
||||
$end->endOfDay();
|
||||
$spent = $this->opsRepository->listExpenses($limit->start_date, $end, null, new Collection([$budget]));
|
||||
$limitCurrencyId = $limit->transaction_currency_id;
|
||||
$filtered = [];
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $currencyId => $entry) {
|
||||
// only spent the entry where the entry's currency matches the budget limit's currency
|
||||
// so $filtered will only have 1 or 0 entries
|
||||
if ($entry['currency_id'] === $limitCurrencyId) {
|
||||
$filtered[$currencyId] = $entry;
|
||||
}
|
||||
}
|
||||
$result = $this->processExpenses($budget->id, $filtered, $limit->start_date, $end);
|
||||
if (1 === count($result)) {
|
||||
$compare = bccomp($limit->amount, app('steam')->positive($result[$limitCurrencyId]['spent']));
|
||||
if (1 === $compare) {
|
||||
// convert this amount into the native currency:
|
||||
$result[$limitCurrencyId]['left'] = bcadd($limit->amount, $result[$limitCurrencyId]['spent']);
|
||||
}
|
||||
if ($compare <= 0) {
|
||||
$result[$limitCurrencyId]['overspent'] = app('steam')->positive(bcadd($limit->amount, $result[$limitCurrencyId]['spent']));
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
128
app/Api/V1/Controllers/Chart/CategoryController.php
Normal file
128
app/Api/V1/Controllers/Chart/CategoryController.php
Normal file
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* CategoryController.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Api\V2\Controllers\Controller;
|
||||
use FireflyIII\Api\V2\Request\Generic\DateRequest;
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class BudgetController
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
use CleansChartData;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
private AccountRepositoryInterface $accountRepos;
|
||||
private CurrencyRepositoryInterface $currencyRepos;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
$this->accountRepos->setUserGroup($userGroup);
|
||||
$this->currencyRepos->setUserGroup($userGroup);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO may be worth to move to a handler but the data is simple enough.
|
||||
* TODO see autoComplete/account controller
|
||||
*
|
||||
* @throws FireflyException
|
||||
*
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function dashboard(DateRequest $request): JsonResponse
|
||||
{
|
||||
/** @var Carbon $start */
|
||||
$start = $this->parameters->get('start');
|
||||
|
||||
/** @var Carbon $end */
|
||||
$end = $this->parameters->get('end');
|
||||
$accounts = $this->accountRepos->getAccountsByType([AccountTypeEnum::DEBT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value]);
|
||||
$currencies = [];
|
||||
$return = [];
|
||||
|
||||
// get journals for entire period:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->withAccountInformation();
|
||||
$collector->setXorAccounts($accounts)->withCategoryInformation();
|
||||
$collector->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::RECONCILIATION->value]);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int) $journal['currency_id'];
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
$currencies[$currencyId] = $currency;
|
||||
$categoryName = null === $journal['category_name'] ? (string) trans('firefly.no_category') : $journal['category_name'];
|
||||
$amount = app('steam')->positive($journal['amount']);
|
||||
$key = sprintf('%s-%s', $categoryName, $currency->code);
|
||||
// create arrays
|
||||
$return[$key] ??= [
|
||||
'label' => $categoryName,
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'period' => null,
|
||||
'start' => $start->toAtomString(),
|
||||
'end' => $end->toAtomString(),
|
||||
'amount' => '0',
|
||||
];
|
||||
|
||||
// add monies
|
||||
$return[$key]['amount'] = bcadd($return[$key]['amount'], $amount);
|
||||
}
|
||||
$return = array_values($return);
|
||||
|
||||
// order by amount
|
||||
usort($return, static function (array $a, array $b) {
|
||||
return (float) $a['amount'] < (float) $b['amount'] ? 1 : -1;
|
||||
});
|
||||
|
||||
return response()->json($this->clean($return));
|
||||
}
|
||||
}
|
@@ -39,6 +39,8 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -93,24 +95,24 @@ class BasicController extends Controller
|
||||
public function basic(DateRequest $request): JsonResponse
|
||||
{
|
||||
// parameters for boxes:
|
||||
$dates = $request->getAll();
|
||||
$start = $dates['start'];
|
||||
$end = $dates['end'];
|
||||
$code = $request->get('currency_code');
|
||||
$dates = $request->getAll();
|
||||
$start = $dates['start'];
|
||||
$end = $dates['end'];
|
||||
$code = $request->get('currency_code');
|
||||
|
||||
// balance information:
|
||||
$balanceData = $this->getBalanceInformation($start, $end);
|
||||
$billData = $this->getBillInformation($start, $end);
|
||||
$billData = $this->getSubscriptionInformation($start, $end);
|
||||
$spentData = $this->getLeftToSpendInfo($start, $end);
|
||||
$netWorthData = $this->getNetWorthInfo($end);
|
||||
// $balanceData = [];
|
||||
// $billData = [];
|
||||
// $spentData = [];
|
||||
// $netWorthData = [];
|
||||
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
|
||||
$total = array_merge($balanceData, $billData, $spentData, $netWorthData);
|
||||
|
||||
// give new keys
|
||||
$return = [];
|
||||
$return = [];
|
||||
foreach ($total as $entry) {
|
||||
if (null === $code || ($code === $entry['currency_code'])) {
|
||||
$return[$entry['key']] = $entry;
|
||||
@@ -122,55 +124,119 @@ class BasicController extends Controller
|
||||
|
||||
private function getBalanceInformation(Carbon $start, Carbon $end): array
|
||||
{
|
||||
Log::debug('getBalanceInformation');
|
||||
// some config settings
|
||||
$convertToNative = Amount::convertToNative();
|
||||
$default = Amount::getNativeCurrency();
|
||||
// prep some arrays:
|
||||
$incomes = [];
|
||||
$expenses = [];
|
||||
$sums = [];
|
||||
$return = [];
|
||||
$incomes = [];
|
||||
$expenses = [];
|
||||
$sums = [];
|
||||
$return = [];
|
||||
$currencies = [
|
||||
$default->id => $default,
|
||||
];
|
||||
|
||||
// collect income of user using the new group collector.
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::DEPOSIT->value]);
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$summarizer = new TransactionSummarizer();
|
||||
$set = $collector->setRange($start, $end)->setTypes([TransactionTypeEnum::DEPOSIT->value])->getExtractedJournals();
|
||||
$incomes = $summarizer->groupByCurrencyId($set, 'positive', false);
|
||||
|
||||
$set = $collector->getExtractedJournals();
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($set as $journal) {
|
||||
$currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
|
||||
$amount = Amount::getAmountFromJournal($journal);
|
||||
$incomes[$currencyId] ??= '0';
|
||||
$incomes[$currencyId] = bcadd(
|
||||
$incomes[$currencyId],
|
||||
bcmul($amount, '-1')
|
||||
);
|
||||
$sums[$currencyId] ??= '0';
|
||||
$sums[$currencyId] = bcadd($sums[$currencyId], bcmul($amount, '-1'));
|
||||
}
|
||||
|
||||
// collect expenses of user using the new group collector.
|
||||
// collect expenses of user.
|
||||
// collect expenses of user using the new group collector.
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
$set = $collector->getExtractedJournals();
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$set = $collector->setRange($start, $end)->setPage($this->parameters->get('page'))->setTypes([TransactionTypeEnum::WITHDRAWAL->value])->getExtractedJournals();
|
||||
$expenses = $summarizer->groupByCurrencyId($set, 'negative', false);
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($set as $journal) {
|
||||
$currencyId = $convertToNative ? $default->id : (int) $journal['currency_id'];
|
||||
$amount = Amount::getAmountFromJournal($journal);
|
||||
$expenses[$currencyId] ??= '0';
|
||||
$expenses[$currencyId] = bcadd($expenses[$currencyId], $amount);
|
||||
$sums[$currencyId] ??= '0';
|
||||
$sums[$currencyId] = bcadd($sums[$currencyId], $amount);
|
||||
// if convert to native, do so right now.
|
||||
if ($convertToNative) {
|
||||
$newExpenses = [
|
||||
$default->id => [
|
||||
'currency_id' => $default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => $default->decimal_places,
|
||||
'sum' => '0',
|
||||
],
|
||||
];
|
||||
$newIncomes = [
|
||||
$default->id => [
|
||||
'currency_id' => $default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => $default->decimal_places,
|
||||
'sum' => '0',
|
||||
],
|
||||
];
|
||||
$sums = [
|
||||
$default->id => [
|
||||
'currency_id' => $default->id,
|
||||
'currency_code' => $default->code,
|
||||
'currency_symbol' => $default->symbol,
|
||||
'currency_decimal_places' => $default->decimal_places,
|
||||
'sum' => '0',
|
||||
],
|
||||
];
|
||||
|
||||
$converter = new ExchangeRateConverter();
|
||||
// loop over income and expenses
|
||||
foreach ([$expenses, $incomes] as $index => $array) {
|
||||
|
||||
// loop over either one.
|
||||
foreach ($array as $entry) {
|
||||
|
||||
// if it is the native currency already.
|
||||
if ($entry['currency_id'] === $default->id) {
|
||||
$sums[$default->id]['sum'] = bcadd($entry['sum'], $sums[$default->id]['sum']);
|
||||
|
||||
// don't forget to add it to newExpenses and newIncome
|
||||
if (0 === $index) {
|
||||
$newExpenses[$default->id]['sum'] = bcadd($newExpenses[$default->id]['sum'], $entry['sum']);
|
||||
}
|
||||
if (1 === $index) {
|
||||
$newIncomes[$default->id]['sum'] = bcadd($newIncomes[$default->id]['sum'], $entry['sum']);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$currencies[$entry['currency_id']] ??= $this->currencyRepos->find($entry['currency_id']);
|
||||
$convertedSum = $converter->convert($currencies[$entry['currency_id']], $default, $start, $entry['sum']);
|
||||
$sums[$default->id]['sum'] = bcadd($sums[$default->id]['sum'], $convertedSum);
|
||||
if (0 === $index) {
|
||||
$newExpenses[$default->id]['sum'] = bcadd($newExpenses[$default->id]['sum'], $convertedSum);
|
||||
}
|
||||
if (1 === $index) {
|
||||
$newIncomes[$default->id]['sum'] = bcadd($newIncomes[$default->id]['sum'], $convertedSum);
|
||||
}
|
||||
}
|
||||
}
|
||||
$incomes = $newIncomes;
|
||||
$expenses = $newExpenses;
|
||||
}
|
||||
if (!$convertToNative) {
|
||||
foreach ([$expenses, $incomes] as $array) {
|
||||
foreach ($array as $entry) {
|
||||
$currencyId = $entry['currency_id'];
|
||||
$sums[$currencyId] ??= [
|
||||
'currency_id' => $entry['currency_id'],
|
||||
'currency_code' => $entry['currency_code'],
|
||||
'currency_symbol' => $entry['currency_symbol'],
|
||||
'currency_decimal_places' => $entry['currency_decimal_places'],
|
||||
'sum' => '0',
|
||||
];
|
||||
$sums[$currencyId]['sum'] = bcadd($sums[$currencyId]['sum'], $entry['sum']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// format amounts:
|
||||
$keys = array_keys($sums);
|
||||
$keys = array_keys($sums);
|
||||
foreach ($keys as $currencyId) {
|
||||
$currency = $this->currencyRepos->find($currencyId);
|
||||
$currency = $currencies[$currencyId] ?? $this->currencyRepos->find($currencyId);
|
||||
if (null === $currency) {
|
||||
continue;
|
||||
}
|
||||
@@ -178,37 +244,37 @@ class BasicController extends Controller
|
||||
$return[] = [
|
||||
'key' => sprintf('balance-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_balance_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $sums[$currencyId] ?? '0',
|
||||
'monetary_value' => $sums[$currencyId]['sum'] ?? '0',
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId] ?? '0', false),
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false)
|
||||
.' + '.app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
|
||||
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false)
|
||||
. ' + ' . app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_spent_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $expenses[$currencyId] ?? '0',
|
||||
'monetary_value' => $expenses[$currencyId]['sum'] ?? '0',
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false),
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('earned-in-%s', $currency->code),
|
||||
'title' => trans('firefly.box_earned_in_currency', ['currency' => $currency->symbol]),
|
||||
'monetary_value' => $incomes[$currencyId] ?? '0',
|
||||
'monetary_value' => $incomes[$currencyId]['sum'] ?? '0',
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false),
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -227,7 +293,7 @@ class BasicController extends Controller
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => app('amount')->formatAnything($currency, '0', false)
|
||||
.' + '.app('amount')->formatAnything($currency, '0', false),
|
||||
. ' + ' . app('amount')->formatAnything($currency, '0', false),
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
@@ -258,17 +324,71 @@ class BasicController extends Controller
|
||||
return $return;
|
||||
}
|
||||
|
||||
private function getBillInformation(Carbon $start, Carbon $end): array
|
||||
private function getSubscriptionInformation(Carbon $start, Carbon $end): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
|
||||
Log::debug(sprintf('Now in getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
|
||||
/*
|
||||
* Since both this method and the chart use the exact same data, we can suffice
|
||||
* with calling the one method in the bill repository that will get this amount.
|
||||
*/
|
||||
$paidAmount = $this->billRepository->sumPaidInRange($start, $end);
|
||||
$unpaidAmount = $this->billRepository->sumUnpaidInRange($start, $end);
|
||||
$currencies = [
|
||||
$this->nativeCurrency->id => $this->nativeCurrency,
|
||||
];
|
||||
|
||||
$return = [];
|
||||
if ($this->convertToNative) {
|
||||
$converter = new ExchangeRateConverter();
|
||||
$newPaidAmount = [[
|
||||
'id' => $this->nativeCurrency->id,
|
||||
'name' => $this->nativeCurrency->name,
|
||||
'symbol' => $this->nativeCurrency->symbol,
|
||||
'code' => $this->nativeCurrency->code,
|
||||
'decimal_places' => $this->nativeCurrency->decimal_places,
|
||||
'sum' => '0',
|
||||
]];
|
||||
|
||||
$newUnpaidAmount = [[
|
||||
'id' => $this->nativeCurrency->id,
|
||||
'name' => $this->nativeCurrency->name,
|
||||
'symbol' => $this->nativeCurrency->symbol,
|
||||
'code' => $this->nativeCurrency->code,
|
||||
'decimal_places' => $this->nativeCurrency->decimal_places,
|
||||
'sum' => '0',
|
||||
]];
|
||||
foreach ([$paidAmount, $unpaidAmount] as $index => $array) {
|
||||
foreach ($array as $item) {
|
||||
$currencyId = (int) $item['id'];
|
||||
if (0 === $index) {
|
||||
// paid amount
|
||||
if ($currencyId === $this->nativeCurrency->id) {
|
||||
$newPaidAmount[0]['sum'] = bcadd($newPaidAmount[0]['sum'], $item['sum']);
|
||||
continue;
|
||||
}
|
||||
$currencies[$currencyId] ??= $this->currencyRepos->find($currencyId);
|
||||
$convertedAmount = $converter->convert($currencies[$currencyId], $this->nativeCurrency, $start, $item['sum']);
|
||||
$newPaidAmount[0]['sum'] = bcadd($newPaidAmount[0]['sum'], $convertedAmount);
|
||||
continue;
|
||||
}
|
||||
// unpaid amount
|
||||
if ($currencyId === $this->nativeCurrency->id) {
|
||||
$newUnpaidAmount[0]['sum'] = bcadd($newUnpaidAmount[0]['sum'], $item['sum']);
|
||||
continue;
|
||||
}
|
||||
$currencies[$currencyId] ??= $this->currencyRepos->find($currencyId);
|
||||
$convertedAmount = $converter->convert($currencies[$currencyId], $this->nativeCurrency, $start, $item['sum']);
|
||||
$newUnpaidAmount[0]['sum'] = bcadd($newUnpaidAmount[0]['sum'], $convertedAmount);
|
||||
}
|
||||
}
|
||||
$paidAmount = $newPaidAmount;
|
||||
$unpaidAmount = $newUnpaidAmount;
|
||||
}
|
||||
|
||||
// var_dump($paidAmount);
|
||||
// var_dump($unpaidAmount);
|
||||
// exit;
|
||||
|
||||
$return = [];
|
||||
|
||||
/**
|
||||
* @var array $info
|
||||
@@ -307,7 +427,7 @@ class BasicController extends Controller
|
||||
'sub_title' => '',
|
||||
];
|
||||
}
|
||||
app('log')->debug(sprintf('Done with getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
|
||||
Log::debug(sprintf('Done with getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
|
||||
|
||||
if (0 === count($return)) {
|
||||
$currency = $this->nativeCurrency;
|
||||
@@ -369,7 +489,7 @@ class BasicController extends Controller
|
||||
|
||||
Log::debug(sprintf('Spent %s %s', $row['currency_code'], $row['sum']));
|
||||
|
||||
$return[] = [
|
||||
$return[] = [
|
||||
'key' => sprintf('left-to-spend-in-%s', $row['currency_code']),
|
||||
'title' => trans('firefly.box_left_to_spend_in_currency', ['currency' => $row['currency_symbol']]),
|
||||
'monetary_value' => $leftToSpend,
|
||||
@@ -416,16 +536,16 @@ class BasicController extends Controller
|
||||
$end->endOfDay();
|
||||
|
||||
/** @var User $user */
|
||||
$user = auth()->user();
|
||||
$user = auth()->user();
|
||||
Log::debug(sprintf('getNetWorthInfo up until "%s".', $end->format('Y-m-d H:i:s')));
|
||||
|
||||
/** @var NetWorthInterface $netWorthHelper */
|
||||
$netWorthHelper = app(NetWorthInterface::class);
|
||||
$netWorthHelper->setUser($user);
|
||||
$allAccounts = $this->accountRepository->getActiveAccountsByType([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::DEBT->value]);
|
||||
$allAccounts = $this->accountRepository->getActiveAccountsByType([AccountTypeEnum::ASSET->value, AccountTypeEnum::DEFAULT->value, AccountTypeEnum::LOAN->value, AccountTypeEnum::MORTGAGE->value, AccountTypeEnum::DEBT->value]);
|
||||
|
||||
// filter list on preference of being included.
|
||||
$filtered = $allAccounts->filter(
|
||||
$filtered = $allAccounts->filter(
|
||||
function (Account $account) {
|
||||
$includeNetWorth = $this->accountRepository->getMetaValue($account, 'include_net_worth');
|
||||
|
||||
@@ -433,13 +553,13 @@ class BasicController extends Controller
|
||||
}
|
||||
);
|
||||
|
||||
$netWorthSet = $netWorthHelper->byAccounts($filtered, $end);
|
||||
$return = [];
|
||||
$netWorthSet = $netWorthHelper->byAccounts($filtered, $end);
|
||||
$return = [];
|
||||
foreach ($netWorthSet as $key => $data) {
|
||||
if ('native' === $key) {
|
||||
continue;
|
||||
}
|
||||
$amount = $data['balance'];
|
||||
$amount = $data['balance'];
|
||||
if (0 === bccomp($amount, '0')) {
|
||||
continue;
|
||||
}
|
||||
|
91
app/Api/V1/Requests/Chart/ChartRequest.php
Normal file
91
app/Api/V1/Requests/Chart/ChartRequest.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* DashboardChartRequest.php
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Chart;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class ChartRequest
|
||||
*/
|
||||
class ChartRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::READ_ONLY];
|
||||
|
||||
public function getParameters(): array
|
||||
{
|
||||
return [
|
||||
'start' => $this->convertDateTime('start')?->startOfDay(),
|
||||
'end' => $this->convertDateTime('end')?->endOfDay(),
|
||||
'preselected' => $this->convertString('preselected', 'empty'),
|
||||
'period' => $this->convertString('period', '1M'),
|
||||
'accounts' => $this->arrayFromValue($this->get('accounts')),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'required|date|after:1900-01-01|before:2099-12-31|before_or_equal:end',
|
||||
'end' => 'required|date|after:1900-01-01|before:2099-12-31|after_or_equal:start',
|
||||
'preselected' => sprintf('nullable|in:%s', implode(',', config('firefly.preselected_accounts'))),
|
||||
'period' => sprintf('nullable|in:%s', implode(',', config('firefly.valid_view_ranges'))),
|
||||
'accounts.*' => 'exists:accounts,id',
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(
|
||||
static function (Validator $validator): void {
|
||||
// validate transaction query data.
|
||||
$data = $validator->getData();
|
||||
if (!array_key_exists('accounts', $data)) {
|
||||
// $validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
|
||||
return;
|
||||
}
|
||||
if (!is_array($data['accounts'])) {
|
||||
$validator->errors()->add('accounts', trans('validation.filled', ['attribute' => 'accounts']));
|
||||
}
|
||||
}
|
||||
);
|
||||
if ($validator->fails()) {
|
||||
Log::channel('audit')->error(sprintf('Validation errors in %s', __CLASS__), $validator->errors()->toArray());
|
||||
}
|
||||
}
|
||||
}
|
62
app/Api/V1/Requests/Generic/DateRequest.php
Normal file
62
app/Api/V1/Requests/Generic/DateRequest.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* DateRequest.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Generic;
|
||||
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Request class for end points that require date parameters.
|
||||
*
|
||||
* Class DateRequest
|
||||
*/
|
||||
class DateRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
'start' => $this->getCarbonDate('start')->startOfDay(),
|
||||
'end' => $this->getCarbonDate('end')->endOfDay(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'start' => 'required|date|after:1900-01-01|before:2099-12-31',
|
||||
'end' => 'required|date|after_or_equal:start|before:2099-12-31|after:1900-01-01',
|
||||
];
|
||||
}
|
||||
}
|
59
app/Api/V1/Requests/Generic/SingleDateRequest.php
Normal file
59
app/Api/V1/Requests/Generic/SingleDateRequest.php
Normal file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* DateRequest.php
|
||||
* Copyright (c) 2021 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Generic;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Request class for end points that require a date parameter.
|
||||
*
|
||||
* Class SingleDateRequest
|
||||
*/
|
||||
class SingleDateRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*/
|
||||
public function getDate(): Carbon
|
||||
{
|
||||
return $this->getCarbonDate('date');
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'date' => 'required|date|after:1900-01-01|before:2099-12-31',
|
||||
];
|
||||
}
|
||||
}
|
@@ -138,7 +138,7 @@ class AvailableBudgetRepository implements AvailableBudgetRepositoryInterface, U
|
||||
->where('end_date', $end->format('Y-m-d'))->get()
|
||||
;
|
||||
|
||||
Log::debug(sprintf('Found %d available budgets', $availableBudgets->count()));
|
||||
Log::debug(sprintf('Found %d available budgets (already converted)', $availableBudgets->count()));
|
||||
|
||||
// use native amount if necessary?
|
||||
$convertToNative = Amount::convertToNative($this->user);
|
||||
|
@@ -46,7 +46,7 @@ class ChartData
|
||||
if (array_key_exists('native_currency_id', $data)) {
|
||||
$data['native_currency_id'] = (string) $data['native_currency_id'];
|
||||
}
|
||||
$required = ['start', 'date', 'end', 'entries', 'native_entries'];
|
||||
$required = ['start', 'date', 'end', 'entries'];
|
||||
foreach ($required as $field) {
|
||||
if (!array_key_exists($field, $data)) {
|
||||
throw new FireflyException(sprintf('Data-set is missing the "%s"-variable.', $field));
|
||||
|
@@ -49,7 +49,7 @@ class TransactionSummarizer
|
||||
$this->convertToNative = Amount::convertToNative($user);
|
||||
}
|
||||
|
||||
public function groupByCurrencyId(array $journals, string $method = 'negative'): array
|
||||
public function groupByCurrencyId(array $journals, string $method = 'negative', bool $includeForeign = true): array
|
||||
{
|
||||
Log::debug(sprintf('Now in groupByCurrencyId(array, "%s")', $method));
|
||||
$array = [];
|
||||
@@ -94,10 +94,10 @@ class TransactionSummarizer
|
||||
}
|
||||
}
|
||||
if (!$this->convertToNative) {
|
||||
Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is %s)', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
|
||||
// use foreign amount?
|
||||
$foreignCurrencyId = (int) $journal['foreign_currency_id'];
|
||||
if (0 !== $foreignCurrencyId) {
|
||||
Log::debug(sprintf('Journal #%d also includes foreign amount (foreign is "%s")', $journal['transaction_journal_id'], $journal['foreign_currency_code']));
|
||||
$foreignCurrencyName = $journal['foreign_currency_name'];
|
||||
$foreignCurrencySymbol = $journal['foreign_currency_symbol'];
|
||||
$foreignCurrencyCode = $journal['foreign_currency_code'];
|
||||
@@ -124,7 +124,7 @@ class TransactionSummarizer
|
||||
}
|
||||
|
||||
// then process foreign amount, if it exists.
|
||||
if (0 !== $foreignCurrencyId) {
|
||||
if (0 !== $foreignCurrencyId && true === $includeForeign) {
|
||||
$amount = (string) ($journal['foreign_amount'] ?? '0');
|
||||
$array[$foreignCurrencyId] ??= [
|
||||
'sum' => '0',
|
||||
|
@@ -184,6 +184,7 @@ return [
|
||||
'currencyPreference' => 'EUR',
|
||||
'language' => 'en_US',
|
||||
'locale' => 'equal',
|
||||
'convertToNative' => false,
|
||||
],
|
||||
'default_currency' => 'EUR',
|
||||
'default_language' => envNonEmpty('DEFAULT_LANGUAGE', 'en_US'),
|
||||
|
65
package-lock.json
generated
65
package-lock.json
generated
@@ -13,42 +13,6 @@
|
||||
"postcss": "^8.4.47"
|
||||
}
|
||||
},
|
||||
"node_modules/@ag-grid-community/client-side-row-model": {
|
||||
"version": "32.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@ag-grid-community/client-side-row-model/-/client-side-row-model-32.3.4.tgz",
|
||||
"integrity": "sha512-AZyLSemPyaCJi8wPJ/wvwow6v4MZKMkg9152TameKvaEf+m+N+gWJNKb1dQoqjgWCgEByqvM6SO8dJtYRrdr/A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ag-grid-community/core": "32.3.4",
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ag-grid-community/core": {
|
||||
"version": "32.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@ag-grid-community/core/-/core-32.3.4.tgz",
|
||||
"integrity": "sha512-g1CJOQuA4uRx1U3VP9SZLnTJBYdMwCTM348FsubdI6anaqxnHv3X0kridq9v1v26qXbl7yytm5X3v1hPcV8wVA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ag-charts-types": "10.3.4",
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ag-grid-community/infinite-row-model": {
|
||||
"version": "32.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@ag-grid-community/infinite-row-model/-/infinite-row-model-32.3.4.tgz",
|
||||
"integrity": "sha512-GWlUoU9UPGp0ZYdBCiV8R+A/mwdYweoB3HsVOEeQiNZYDC1TQJxiCSKBCCg9qk3KDY+VbJ/6ebV/BUN7cLwIuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ag-grid-community/core": "32.3.4",
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ag-grid-community/styles": {
|
||||
"version": "33.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@ag-grid-community/styles/-/styles-33.0.3.tgz",
|
||||
"integrity": "sha512-1bXrYoVj5TIpLvyjgXHvKnYrC0/JvrdGDdJ3mYfT58GulDt1iNQqhjxMnZB+sxMdQoOc681jmKTGcWzOEDE1Dw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
|
||||
@@ -3657,12 +3621,6 @@
|
||||
"integrity": "sha512-q2VoAOu1DtZ7z41M2gQ05VMNYkFCAMxFU+j/HUMwCOlr/e3VhO+qww2SGJw4OxBw5nZQ7YV78+wK2RiB7ConzQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ag-charts-types": {
|
||||
"version": "10.3.4",
|
||||
"resolved": "https://registry.npmjs.org/ag-charts-types/-/ag-charts-types-10.3.4.tgz",
|
||||
"integrity": "sha512-MU+3gvKn1jEyLlMHS0Vu0nHmIQxiVJAnA6ftUatLZvV0c7hOWap4VWghqZ0cVZUJsCdMI59Iuq1u3xquKv4LOQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||
@@ -11109,6 +11067,7 @@
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tty-browserify": {
|
||||
@@ -12291,18 +12250,14 @@
|
||||
"resources/assets/v2": {
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@ag-grid-community/client-side-row-model": "^32.0.2",
|
||||
"@ag-grid-community/core": "^32.0.2",
|
||||
"@ag-grid-community/infinite-row-model": "^32.0.2",
|
||||
"@ag-grid-community/styles": "^33.0.2",
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"admin-lte": "^4.0.0-alpha3",
|
||||
"admin-lte": "^4.0.0-beta3",
|
||||
"alpinejs": "^3.13.7",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap5-autocomplete": "^1.1.22",
|
||||
"bootstrap5-tags": "^1.7",
|
||||
"chart.js": "^4.4.0",
|
||||
"bootstrap": "^5",
|
||||
"bootstrap5-autocomplete": "^1",
|
||||
"bootstrap5-tags": "^1",
|
||||
"chart.js": "^4",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-chart-sankey": "^0.14.0",
|
||||
"date-fns": "^4.0.0",
|
||||
@@ -12314,10 +12269,10 @@
|
||||
"store": "^2.0.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.8.2",
|
||||
"laravel-vite-plugin": "^1.0.5",
|
||||
"patch-package": "^8.0.0",
|
||||
"sass": "^1.78.0",
|
||||
"axios": "^1",
|
||||
"laravel-vite-plugin": "^1",
|
||||
"patch-package": "^8",
|
||||
"sass": "^1",
|
||||
"vite": "^6",
|
||||
"vite-plugin-manifest-sri": "^0.2.0"
|
||||
}
|
||||
|
@@ -8,26 +8,22 @@
|
||||
"postinstall": "patch-package --error-on-fail"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.8.2",
|
||||
"laravel-vite-plugin": "^1.0.5",
|
||||
"patch-package": "^8.0.0",
|
||||
"sass": "^1.78.0",
|
||||
"axios": "^1",
|
||||
"laravel-vite-plugin": "^1",
|
||||
"patch-package": "^8",
|
||||
"sass": "^1",
|
||||
"vite": "^6",
|
||||
"vite-plugin-manifest-sri": "^0.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ag-grid-community/client-side-row-model": "^32.0.2",
|
||||
"@ag-grid-community/core": "^32.0.2",
|
||||
"@ag-grid-community/infinite-row-model": "^32.0.2",
|
||||
"@ag-grid-community/styles": "^33.0.2",
|
||||
"@fortawesome/fontawesome-free": "^6.4.0",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"admin-lte": "^4.0.0-alpha3",
|
||||
"admin-lte": "^4.0.0-beta3",
|
||||
"alpinejs": "^3.13.7",
|
||||
"bootstrap": "^5.3.0",
|
||||
"bootstrap5-autocomplete": "^1.1.22",
|
||||
"bootstrap5-tags": "^1.7",
|
||||
"chart.js": "^4.4.0",
|
||||
"bootstrap": "^5",
|
||||
"bootstrap5-autocomplete": "^1",
|
||||
"bootstrap5-tags": "^1",
|
||||
"chart.js": "^4",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
"chartjs-chart-sankey": "^0.14.0",
|
||||
"date-fns": "^4.0.0",
|
||||
|
36
resources/assets/v2/src/api/v1/chart/account/dashboard.js
Normal file
36
resources/assets/v2/src/api/v1/chart/account/dashboard.js
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* overview.js
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
import {format} from "date-fns";
|
||||
|
||||
export default class Dashboard {
|
||||
dashboard(start, end) {
|
||||
let startStr = format(start, 'y-MM-dd');
|
||||
let endStr = format(end, 'y-MM-dd');
|
||||
return api.get('/api/v1/chart/account/dashboard', {params: {fix: true, start: startStr, end: endStr}});
|
||||
}
|
||||
|
||||
expense(start, end) {
|
||||
let startStr = format(start, 'y-MM-dd');
|
||||
let endStr = format(end, 'y-MM-dd');
|
||||
return api.get('/api/v1/chart/account/expense-dashboard', {params: {start: startStr, end: endStr}});
|
||||
}
|
||||
}
|
30
resources/assets/v2/src/api/v1/chart/budget/dashboard.js
Normal file
30
resources/assets/v2/src/api/v1/chart/budget/dashboard.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* overview.js
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
import {format} from "date-fns";
|
||||
|
||||
export default class Dashboard {
|
||||
dashboard(start, end) {
|
||||
let startStr = format(start, 'y-MM-dd');
|
||||
let endStr = format(end, 'y-MM-dd');
|
||||
return api.get('/api/v1/chart/budget/dashboard', {params: {start: startStr, end: endStr}});
|
||||
}
|
||||
}
|
30
resources/assets/v2/src/api/v1/chart/category/dashboard.js
Normal file
30
resources/assets/v2/src/api/v1/chart/category/dashboard.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* overview.js
|
||||
* Copyright (c) 2022 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
import {format} from "date-fns";
|
||||
|
||||
export default class Dashboard {
|
||||
dashboard(start, end) {
|
||||
let startStr = format(start, 'y-MM-dd');
|
||||
let endStr = format(end, 'y-MM-dd');
|
||||
return api.get('/api/v1/chart/category/dashboard', {params: {start: startStr, end: endStr}});
|
||||
}
|
||||
}
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../boot/axios";
|
||||
import {api} from "../../../../boot/axios";
|
||||
import format from "date-fns/format";
|
||||
|
||||
export default class Get {
|
||||
@@ -37,6 +37,18 @@ export default class Get {
|
||||
return api.get('/api/v1/accounts/' + identifier, {params: params});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param identifier
|
||||
* @param params
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
show(identifier, params) {
|
||||
return api.get('/api/v1/accounts/' + identifier, {params: params});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param identifier
|
35
resources/assets/v2/src/api/v1/model/piggy-bank/get.js
Normal file
35
resources/assets/v2/src/api/v1/model/piggy-bank/get.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* get.js
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
|
||||
export default class Get {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
list(params) {
|
||||
return api.get('/api/v1/piggy-banks', {params: params});
|
||||
}
|
||||
|
||||
}
|
42
resources/assets/v2/src/api/v1/model/subscription/get.js
Normal file
42
resources/assets/v2/src/api/v1/model/subscription/get.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* get.js
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
|
||||
export default class Get {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
list(params) {
|
||||
return api.get('/api/v1/subscriptions', {params: params});
|
||||
}
|
||||
|
||||
paid(params) {
|
||||
return api.get('/api/v1/subscriptions/sum/paid', {params: params});
|
||||
}
|
||||
|
||||
unpaid(params) {
|
||||
return api.get('/api/v1/subscriptions/sum/unpaid', {params: params});
|
||||
}
|
||||
}
|
37
resources/assets/v2/src/api/v1/model/transaction/get.js
Normal file
37
resources/assets/v2/src/api/v1/model/transaction/get.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* get.js
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
|
||||
export default class Get {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param params
|
||||
* @returns {Promise<AxiosResponse<any>>}
|
||||
*/
|
||||
list(params) {
|
||||
return api.get('/api/v1/transactions', {params: params});
|
||||
}
|
||||
show(id, params){
|
||||
return api.get('/api/v1/transactions/' + id, {params: params});
|
||||
}
|
||||
}
|
28
resources/assets/v2/src/api/v1/model/transaction/post.js
Normal file
28
resources/assets/v2/src/api/v1/model/transaction/post.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* post.js
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
|
||||
export default class Post {
|
||||
post(submission) {
|
||||
let url = '/api/v1/transactions';
|
||||
return api.post(url, submission);
|
||||
}
|
||||
}
|
28
resources/assets/v2/src/api/v1/model/transaction/put.js
Normal file
28
resources/assets/v2/src/api/v1/model/transaction/put.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* post.js
|
||||
* Copyright (c) 2023 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {api} from "../../../../boot/axios";
|
||||
|
||||
export default class Put {
|
||||
put(submission, params) {
|
||||
let url = '/api/v1/transactions/' + parseInt(params.id);
|
||||
return api.put(url, submission);
|
||||
}
|
||||
}
|
@@ -25,7 +25,7 @@ export default class Dashboard {
|
||||
dashboard(start, end) {
|
||||
let startStr = format(start, 'y-MM-dd');
|
||||
let endStr = format(end, 'y-MM-dd');
|
||||
return api.get('/api/v2/chart/account/dashboard', {params: {filter: {start: startStr, end: endStr}}});
|
||||
return api.get('/api/v2/chart/account/dashboard', {params: {start: startStr, end: endStr}});
|
||||
}
|
||||
|
||||
expense(start, end) {
|
||||
|
@@ -24,8 +24,8 @@ import i18next from "i18next";
|
||||
import {format} from "date-fns";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
|
||||
import Get from "../../api/v2/model/account/get.js";
|
||||
import Put from "../../api/v2/model/account/put.js";
|
||||
import Get from "../../api/v1/model/account/get.js";
|
||||
import Put from "../../api/v1/model/account/put.js";
|
||||
import AccountRenderer from "../../support/renderers/AccountRenderer.js";
|
||||
import {showInternalsButton} from "../../support/page-settings/show-internals-button.js";
|
||||
import {showWizardButton} from "../../support/page-settings/show-wizard-button.js";
|
||||
|
@@ -20,7 +20,7 @@
|
||||
|
||||
import '../../boot/bootstrap.js';
|
||||
import dates from "../shared/dates.js";
|
||||
import Post from "../../api/v2/model/user-group/post.js";
|
||||
import Post from "../../api/v1/model/user-group/post.js";
|
||||
import i18next from "i18next";
|
||||
|
||||
|
||||
|
@@ -20,10 +20,10 @@
|
||||
|
||||
import '../../boot/bootstrap.js';
|
||||
import dates from "../shared/dates.js";
|
||||
import Post from "../../api/v2/model/user-group/post.js";
|
||||
import Post from "../../api/v1/model/user-group/post.js";
|
||||
import i18next from "i18next";
|
||||
import Get from "../../api/v2/model/user-group/get.js";
|
||||
import Put from "../../api/v2/model/user-group/put.js";
|
||||
import Get from "../../api/v1/model/user-group/get.js";
|
||||
import Put from "../../api/v1/model/user-group/put.js";
|
||||
|
||||
|
||||
let administrations = function () {
|
||||
|
@@ -23,11 +23,9 @@ import dates from "../shared/dates.js";
|
||||
import i18next from "i18next";
|
||||
import {format} from "date-fns";
|
||||
|
||||
import '@ag-grid-community/styles/ag-grid.css';
|
||||
import '@ag-grid-community/styles/ag-theme-alpine.css';
|
||||
import '../../css/grid-ff3-theme.css';
|
||||
import Get from "../../api/v2/model/user-group/get.js";
|
||||
import Post from "../../api/v2/model/user-group/post.js";
|
||||
import Get from "../../api/v1/model/user-group/get.js";
|
||||
import Post from "../../api/v1/model/user-group/post.js";
|
||||
|
||||
let index = function () {
|
||||
return {
|
||||
|
@@ -20,9 +20,9 @@
|
||||
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import {setVariable} from "../../store/set-variable.js";
|
||||
import Dashboard from "../../api/v2/chart/account/dashboard.js";
|
||||
import Dashboard from "../../api/v1/chart/account/dashboard.js";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
import Get from "../../api/v2/model/account/get.js";
|
||||
import Get from "../../api/v1/model/account/get.js";
|
||||
import {Chart} from 'chart.js';
|
||||
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
|
||||
import {getCacheKey} from "../../support/get-cache-key.js";
|
||||
@@ -39,12 +39,12 @@ export default () => ({
|
||||
loading: false,
|
||||
loadingAccounts: false,
|
||||
accountList: [],
|
||||
autoConversion: false,
|
||||
autoConversionAvailable: false,
|
||||
convertToNative: false,
|
||||
convertToNativeAvailable: false,
|
||||
chartOptions: null,
|
||||
switchAutoConversion() {
|
||||
this.autoConversion = !this.autoConversion;
|
||||
setVariable('autoConversion', this.autoConversion);
|
||||
switchConvertToNative() {
|
||||
this.convertToNative = !this.convertToNative;
|
||||
setVariable('convertToNative', this.convertToNative);
|
||||
},
|
||||
localCacheKey(type) {
|
||||
return 'ds_accounts_' + type;
|
||||
@@ -90,18 +90,18 @@ export default () => ({
|
||||
dataset.label = current.label;
|
||||
|
||||
// use the "native" currency code and use the "native_entries" as array
|
||||
if (this.autoConversion) {
|
||||
currencies.push(current.native_currency_code);
|
||||
dataset.currency_code = current.native_currency_code;
|
||||
collection = Object.values(current.native_entries);
|
||||
yAxis = 'y' + current.native_currency_code;
|
||||
}
|
||||
if (!this.autoConversion) {
|
||||
// if (this.convertToNative) {
|
||||
// currencies.push(current.native_currency_code);
|
||||
// dataset.currency_code = current.native_currency_code;
|
||||
// collection = Object.values(current.native_entries);
|
||||
// yAxis = 'y' + current.native_currency_code;
|
||||
// }
|
||||
// if (!this.convertToNative) {
|
||||
yAxis = 'y' + current.currency_code;
|
||||
dataset.currency_code = current.currency_code;
|
||||
currencies.push(current.currency_code);
|
||||
collection = Object.values(current.entries);
|
||||
}
|
||||
// }
|
||||
dataset.yAxisID = yAxis;
|
||||
dataset.data = collection;
|
||||
|
||||
@@ -217,12 +217,12 @@ export default () => ({
|
||||
for (let iii = 0; iii < current.attributes.transactions.length; iii++) {
|
||||
let currentTransaction = current.attributes.transactions[iii];
|
||||
//console.log(currentTransaction);
|
||||
let nativeAmountRaw = 'withdrawal' === currentTransaction.type ? parseFloat(currentTransaction.native_amount) * -1 : parseFloat(currentTransaction.native_amount);
|
||||
//let nativeAmountRaw = 'withdrawal' === currentTransaction.type ? parseFloat(currentTransaction.native_amount) * -1 : parseFloat(currentTransaction.native_amount);
|
||||
let amountRaw = 'withdrawal' === currentTransaction.type ? parseFloat(currentTransaction.amount) * -1 : parseFloat(currentTransaction.amount);
|
||||
|
||||
// if transfer and source is this account, multiply again
|
||||
if('transfer' === currentTransaction.type && parseInt(currentTransaction.source_id) === accountId) { //
|
||||
nativeAmountRaw = nativeAmountRaw * -1;
|
||||
// nativeAmountRaw = nativeAmountRaw * -1;
|
||||
amountRaw = amountRaw * -1;
|
||||
}
|
||||
|
||||
@@ -232,8 +232,8 @@ export default () => ({
|
||||
type: currentTransaction.type,
|
||||
amount_raw: amountRaw,
|
||||
amount: formatMoney(amountRaw, currentTransaction.currency_code),
|
||||
native_amount_raw: nativeAmountRaw,
|
||||
native_amount: formatMoney(nativeAmountRaw, currentTransaction.native_currency_code),
|
||||
// native_amount_raw: nativeAmountRaw,
|
||||
// native_amount: formatMoney(nativeAmountRaw, currentTransaction.native_currency_code),
|
||||
});
|
||||
}
|
||||
groups.push(group);
|
||||
@@ -244,7 +244,7 @@ export default () => ({
|
||||
order: parent.attributes.order,
|
||||
id: parent.id,
|
||||
balance: parent.attributes.balance,
|
||||
native_balance: parent.attributes.native_balance,
|
||||
//native_balance: parent.attributes.native_balance,
|
||||
groups: groups,
|
||||
});
|
||||
// console.log(parent.attributes);
|
||||
@@ -266,12 +266,12 @@ export default () => ({
|
||||
|
||||
init() {
|
||||
// console.log('accounts init');
|
||||
Promise.all([getVariable('viewRange', '1M'), getVariable('autoConversion', false), getVariable('language', 'en_US'),
|
||||
Promise.all([getVariable('viewRange', '1M'), getVariable('convertToNative', false), getVariable('language', 'en_US'),
|
||||
getConfiguration('cer.enabled', false)
|
||||
]).then((values) => {
|
||||
//console.log('accounts after promises');
|
||||
this.autoConversion = values[1] && values[3];
|
||||
this.autoConversionAvailable = values[3];
|
||||
this.convertToNative = values[1] && values[3];
|
||||
this.convertToNativeAvailable = values[3];
|
||||
afterPromises = true;
|
||||
|
||||
// main dashboard chart:
|
||||
@@ -289,11 +289,11 @@ export default () => ({
|
||||
this.loadChart();
|
||||
this.loadAccounts();
|
||||
});
|
||||
window.store.observe('autoConversion', () => {
|
||||
window.store.observe('convertToNative', () => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
// console.log('accounts observe autoconversion');
|
||||
// console.log('accounts observe convertToNative');
|
||||
this.loadChart();
|
||||
this.loadAccounts();
|
||||
});
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Summary from "../../api/v2/summary/index.js";
|
||||
import Summary from "../../api/v1/summary/index.js";
|
||||
import {format} from "date-fns";
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
@@ -31,7 +31,7 @@ export default () => ({
|
||||
billBox: {paid: [], unpaid: []},
|
||||
leftBox: {left: [], perDay: []},
|
||||
netBox: {net: []},
|
||||
autoConversion: false,
|
||||
convertToNative: false,
|
||||
loading: false,
|
||||
boxData: null,
|
||||
boxOptions: null,
|
||||
@@ -42,8 +42,9 @@ export default () => ({
|
||||
const boxesCacheKey = getCacheKey('ds_boxes_data', {start: start, end: end});
|
||||
cleanupCache();
|
||||
|
||||
const cacheValid = window.store.get('cacheValid');
|
||||
//const cacheValid = window.store.get('cacheValid');
|
||||
let cachedData = window.store.get(boxesCacheKey);
|
||||
const cacheValid = false; // force refresh
|
||||
|
||||
if (cacheValid && typeof cachedData !== 'undefined') {
|
||||
this.boxData = cachedData;
|
||||
@@ -75,114 +76,56 @@ export default () => ({
|
||||
continue;
|
||||
}
|
||||
let key = current.key;
|
||||
// native (auto conversion):
|
||||
if (this.autoConversion) {
|
||||
if (key.startsWith('balance-in-native')) {
|
||||
this.balanceBox.amounts.push(formatMoney(current.value, current.currency_code));
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// spent info is used in subtitle:
|
||||
if (key.startsWith('spent-in-native')) {
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
// append the amount spent.
|
||||
subtitles[current.currency_code] =
|
||||
subtitles[current.currency_code] +
|
||||
formatMoney(current.value, current.currency_code);
|
||||
continue;
|
||||
}
|
||||
// earned info is used in subtitle:
|
||||
if (key.startsWith('earned-in-native')) {
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
// prepend the amount earned.
|
||||
subtitles[current.currency_code] =
|
||||
formatMoney(current.value, current.currency_code) + ' + ' +
|
||||
subtitles[current.currency_code];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.startsWith('bills-unpaid-in-native')) {
|
||||
this.billBox.unpaid.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('bills-paid-in-native')) {
|
||||
this.billBox.paid.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('left-to-spend-in-native')) {
|
||||
this.leftBox.left.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('left-per-day-to-spend-in-native')) { // per day
|
||||
this.leftBox.perDay.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('net-worth-in-native')) {
|
||||
this.netBox.net.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
console.log('NOT NATIVE');
|
||||
if (key.startsWith('balance-in-')) {
|
||||
this.balanceBox.amounts.push(formatMoney(current.monetary_value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
// not native
|
||||
if (!this.autoConversion && !key.endsWith('native')) {
|
||||
if (key.startsWith('balance-in-')) {
|
||||
this.balanceBox.amounts.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
// spent info is used in subtitle:
|
||||
if (key.startsWith('spent-in-')) {
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
// spent info is used in subtitle:
|
||||
if (key.startsWith('spent-in-')) {
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
// append the amount spent.
|
||||
subtitles[current.currency_code] =
|
||||
subtitles[current.currency_code] +
|
||||
formatMoney(current.value, current.currency_code);
|
||||
continue;
|
||||
}
|
||||
// earned info is used in subtitle:
|
||||
if (key.startsWith('earned-in-')) {
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
// prepend the amount earned.
|
||||
subtitles[current.currency_code] =
|
||||
formatMoney(current.value, current.currency_code) + ' + ' +
|
||||
subtitles[current.currency_code];
|
||||
continue;
|
||||
// append the amount spent.
|
||||
subtitles[current.currency_code] =
|
||||
subtitles[current.currency_code] +
|
||||
formatMoney(current.monetary_value, current.currency_code);
|
||||
continue;
|
||||
}
|
||||
// earned info is used in subtitle:
|
||||
if (key.startsWith('earned-in-')) {
|
||||
// prep subtitles (for later)
|
||||
if (!subtitles.hasOwnProperty(current.currency_code)) {
|
||||
subtitles[current.currency_code] = '';
|
||||
}
|
||||
// prepend the amount earned.
|
||||
subtitles[current.currency_code] =
|
||||
formatMoney(current.monetary_value, current.currency_code) + ' + ' +
|
||||
subtitles[current.currency_code];
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (key.startsWith('bills-unpaid-in-')) {
|
||||
this.billBox.unpaid.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('bills-paid-in-')) {
|
||||
this.billBox.paid.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('left-to-spend-in-')) {
|
||||
this.leftBox.left.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('left-per-day-to-spend-in-')) {
|
||||
this.leftBox.perDay.push(formatMoney(current.value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('net-worth-in-')) {
|
||||
this.netBox.net.push(formatMoney(current.value, current.currency_code));
|
||||
if (key.startsWith('bills-unpaid-in-')) {
|
||||
this.billBox.unpaid.push(formatMoney(current.monetary_value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('bills-paid-in-')) {
|
||||
this.billBox.paid.push(formatMoney(current.monetary_value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('left-to-spend-in-')) {
|
||||
this.leftBox.left.push(formatMoney(current.monetary_value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('left-per-day-to-spend-in-')) {
|
||||
this.leftBox.perDay.push(formatMoney(current.monetary_value, current.currency_code));
|
||||
continue;
|
||||
}
|
||||
if (key.startsWith('net-worth-in-')) {
|
||||
this.netBox.net.push(formatMoney(current.monetary_value, current.currency_code));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -210,10 +153,10 @@ export default () => ({
|
||||
init() {
|
||||
// console.log('boxes init');
|
||||
// TODO can be replaced by "getVariables"
|
||||
Promise.all([getVariable('viewRange'), getVariable('autoConversion', false)]).then((values) => {
|
||||
Promise.all([getVariable('viewRange'), getVariable('convertToNative', false)]).then((values) => {
|
||||
// console.log('boxes after promises');
|
||||
afterPromises = true;
|
||||
this.autoConversion = values[1];
|
||||
this.convertToNative = values[1];
|
||||
this.loadBoxes();
|
||||
});
|
||||
window.store.observe('end', () => {
|
||||
@@ -224,12 +167,12 @@ export default () => ({
|
||||
this.boxData = null;
|
||||
this.loadBoxes();
|
||||
});
|
||||
window.store.observe('autoConversion', (newValue) => {
|
||||
window.store.observe('convertToNative', (newValue) => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
// console.log('boxes observe autoConversion');
|
||||
this.autoConversion = newValue;
|
||||
// console.log('boxes observe convertToNative');
|
||||
this.convertToNative = newValue;
|
||||
this.loadBoxes();
|
||||
});
|
||||
},
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import Dashboard from "../../api/v2/chart/budget/dashboard.js";
|
||||
import Dashboard from "../../api/v1/chart/budget/dashboard.js";
|
||||
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
import {Chart} from 'chart.js';
|
||||
@@ -34,7 +34,7 @@ let afterPromises = false;
|
||||
|
||||
export default () => ({
|
||||
loading: false,
|
||||
autoConversion: false,
|
||||
convertToNative: false,
|
||||
loadChart() {
|
||||
if (true === this.loading) {
|
||||
return;
|
||||
@@ -134,7 +134,7 @@ export default () => ({
|
||||
// // convert to EUR yes no?
|
||||
let label = current.label + ' (' + current.currency_code + ')';
|
||||
options.data.labels.push(label);
|
||||
if (this.autoConversion) {
|
||||
if (this.convertToNative) {
|
||||
currencies.push(current.native_currency_code);
|
||||
// series 0: spent
|
||||
options.data.datasets[0].data.push(parseFloat(current.native_entries.spent) * -1);
|
||||
@@ -143,7 +143,7 @@ export default () => ({
|
||||
// series 2: overspent
|
||||
options.data.datasets[2].data.push(parseFloat(current.native_entries.overspent));
|
||||
}
|
||||
if (!this.autoConversion) {
|
||||
if (!this.convertToNative) {
|
||||
currencies.push(current.currency_code);
|
||||
// series 0: spent
|
||||
options.data.datasets[0].data.push(parseFloat(current.entries.spent) * -1);
|
||||
@@ -172,8 +172,8 @@ export default () => ({
|
||||
|
||||
|
||||
init() {
|
||||
Promise.all([getVariable('autoConversion', false)]).then((values) => {
|
||||
this.autoConversion = values[0];
|
||||
Promise.all([getVariable('convertToNative', false)]).then((values) => {
|
||||
this.convertToNative = values[0];
|
||||
afterPromises = true;
|
||||
if (false === this.loading) {
|
||||
this.loadChart();
|
||||
@@ -189,12 +189,12 @@ export default () => ({
|
||||
this.loadChart();
|
||||
}
|
||||
});
|
||||
window.store.observe('autoConversion', (newValue) => {
|
||||
window.store.observe('convertToNative', (newValue) => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
// console.log('boxes observe autoConversion');
|
||||
this.autoConversion = newValue;
|
||||
// console.log('boxes observe convertToNative');
|
||||
this.convertToNative = newValue;
|
||||
if (false === this.loading) {
|
||||
this.loadChart();
|
||||
}
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import Dashboard from "../../api/v2/chart/category/dashboard.js";
|
||||
import Dashboard from "../../api/v1/chart/category/dashboard.js";
|
||||
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
|
||||
import {Chart} from "chart.js";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
@@ -32,7 +32,7 @@ let afterPromises = false;
|
||||
|
||||
export default () => ({
|
||||
loading: false,
|
||||
autoConversion: false,
|
||||
convertToNative: false,
|
||||
generateOptions(data) {
|
||||
currencies = [];
|
||||
let options = getDefaultChartSettings('column');
|
||||
@@ -44,7 +44,7 @@ export default () => ({
|
||||
let current = data[i];
|
||||
let code = current.currency_code;
|
||||
// only use native code when doing auto conversion.
|
||||
if (this.autoConversion) {
|
||||
if (this.convertToNative) {
|
||||
code = current.native_currency_code;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ export default () => ({
|
||||
let yAxis = 'y';
|
||||
let current = data[i];
|
||||
let code = current.currency_code;
|
||||
if (this.autoConversion) {
|
||||
if (this.convertToNative) {
|
||||
code = current.native_currency_code;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ export default () => ({
|
||||
// this series' currency matches this column's currency.
|
||||
amount = parseFloat(current.amount);
|
||||
yAxis = 'y' + current.currency_code;
|
||||
if (this.autoConversion) {
|
||||
if (this.convertToNative) {
|
||||
amount = parseFloat(current.native_amount);
|
||||
yAxis = 'y' + current.native_currency_code;
|
||||
}
|
||||
@@ -183,8 +183,8 @@ export default () => ({
|
||||
},
|
||||
init() {
|
||||
// console.log('categories init');
|
||||
Promise.all([getVariable('autoConversion', false),]).then((values) => {
|
||||
this.autoConversion = values[0];
|
||||
Promise.all([getVariable('convertToNative', false),]).then((values) => {
|
||||
this.convertToNative = values[0];
|
||||
afterPromises = true;
|
||||
this.loadChart();
|
||||
});
|
||||
@@ -195,11 +195,11 @@ export default () => ({
|
||||
this.chartData = null;
|
||||
this.loadChart();
|
||||
});
|
||||
window.store.observe('autoConversion', (newValue) => {
|
||||
window.store.observe('convertToNative', (newValue) => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
this.autoConversion = newValue;
|
||||
this.convertToNative = newValue;
|
||||
this.loadChart();
|
||||
});
|
||||
},
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import Get from "../../api/v2/model/piggy-bank/get.js";
|
||||
import Get from "../../api/v1/model/piggy-bank/get.js";
|
||||
import {getCacheKey} from "../../support/get-cache-key.js";
|
||||
import {format} from "date-fns";
|
||||
import i18next from "i18next";
|
||||
@@ -29,7 +29,7 @@ const PIGGY_CACHE_KEY = 'ds_pg_data';
|
||||
|
||||
export default () => ({
|
||||
loading: false,
|
||||
autoConversion: false,
|
||||
convertToNative: false,
|
||||
sankeyGrouping: 'account',
|
||||
piggies: [],
|
||||
getFreshData() {
|
||||
@@ -96,14 +96,14 @@ export default () => ({
|
||||
id: current.id,
|
||||
name: current.attributes.name,
|
||||
percentage: parseInt(current.attributes.percentage),
|
||||
amount: this.autoConversion ? current.attributes.native_current_amount : current.attributes.current_amount,
|
||||
amount: this.convertToNative ? current.attributes.native_current_amount : current.attributes.current_amount,
|
||||
// left to save
|
||||
left_to_save: this.autoConversion ? current.attributes.native_left_to_save : current.attributes.left_to_save,
|
||||
left_to_save: this.convertToNative ? current.attributes.native_left_to_save : current.attributes.left_to_save,
|
||||
// target amount
|
||||
target_amount: this.autoConversion ? current.attributes.native_target_amount : current.attributes.target_amount,
|
||||
target_amount: this.convertToNative ? current.attributes.native_target_amount : current.attributes.target_amount,
|
||||
// save per month
|
||||
save_per_month: this.autoConversion ? current.attributes.native_save_per_month : current.attributes.save_per_month,
|
||||
currency_code: this.autoConversion ? current.attributes.native_currency_code : current.attributes.currency_code,
|
||||
save_per_month: this.convertToNative ? current.attributes.native_save_per_month : current.attributes.save_per_month,
|
||||
currency_code: this.convertToNative ? current.attributes.native_currency_code : current.attributes.currency_code,
|
||||
|
||||
};
|
||||
dataSet[groupName].piggies.push(piggy);
|
||||
@@ -129,10 +129,10 @@ export default () => ({
|
||||
init() {
|
||||
// console.log('piggies init');
|
||||
apiData = [];
|
||||
Promise.all([getVariable('autoConversion', false)]).then((values) => {
|
||||
Promise.all([getVariable('convertToNative', false)]).then((values) => {
|
||||
|
||||
afterPromises = true;
|
||||
this.autoConversion = values[0];
|
||||
this.convertToNative = values[0];
|
||||
this.loadPiggyBanks();
|
||||
|
||||
});
|
||||
@@ -144,12 +144,12 @@ export default () => ({
|
||||
apiData = [];
|
||||
this.loadPiggyBanks();
|
||||
});
|
||||
window.store.observe('autoConversion', (newValue) => {
|
||||
window.store.observe('convertToNative', (newValue) => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
// console.log('piggies observe autoConversion');
|
||||
this.autoConversion = newValue;
|
||||
// console.log('piggies observe convertToNative');
|
||||
this.convertToNative = newValue;
|
||||
this.loadPiggyBanks();
|
||||
});
|
||||
},
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import Get from "../../api/v2/model/transaction/get.js";
|
||||
import Get from "../../api/v1/model/transaction/get.js";
|
||||
import {getDefaultChartSettings} from "../../support/default-chart-settings.js";
|
||||
import {Chart} from 'chart.js';
|
||||
import {Flow, SankeyController} from 'chartjs-chart-sankey';
|
||||
@@ -33,7 +33,7 @@ let currencies = [];
|
||||
let afterPromises = false;
|
||||
let chart = null;
|
||||
let transactions = [];
|
||||
let autoConversion = false;
|
||||
let convertToNative = false;
|
||||
let translations = {
|
||||
category: null,
|
||||
unknown_category: null,
|
||||
@@ -83,37 +83,37 @@ function getObjectName(type, name, direction, code) {
|
||||
|
||||
// category 4x
|
||||
if ('category' === type && null !== name && 'in' === direction) {
|
||||
return translations.category + ' "' + name + '" (' + translations.in + (autoConversion ? ', ' + code + ')' : ')');
|
||||
return translations.category + ' "' + name + '" (' + translations.in + (convertToNative ? ', ' + code + ')' : ')');
|
||||
}
|
||||
if ('category' === type && null === name && 'in' === direction) {
|
||||
return translations.unknown_category + ' (' + translations.in + (autoConversion ? ', ' + code + ')' : ')');
|
||||
return translations.unknown_category + ' (' + translations.in + (convertToNative ? ', ' + code + ')' : ')');
|
||||
}
|
||||
if ('category' === type && null !== name && 'out' === direction) {
|
||||
return translations.category + ' "' + name + '" (' + translations.out + (autoConversion ? ', ' + code + ')' : ')');
|
||||
return translations.category + ' "' + name + '" (' + translations.out + (convertToNative ? ', ' + code + ')' : ')');
|
||||
}
|
||||
if ('category' === type && null === name && 'out' === direction) {
|
||||
return translations.unknown_category + ' (' + translations.out + (autoConversion ? ', ' + code + ')' : ')');
|
||||
return translations.unknown_category + ' (' + translations.out + (convertToNative ? ', ' + code + ')' : ')');
|
||||
}
|
||||
// account 4x
|
||||
if ('account' === type && null === name && 'in' === direction) {
|
||||
return translations.unknown_source + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.unknown_source + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('account' === type && null !== name && 'in' === direction) {
|
||||
return translations.revenue_account + '"' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.revenue_account + '"' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('account' === type && null === name && 'out' === direction) {
|
||||
return translations.unknown_dest + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.unknown_dest + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('account' === type && null !== name && 'out' === direction) {
|
||||
return translations.expense_account + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.expense_account + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
|
||||
// budget 2x
|
||||
if ('budget' === type && null !== name) {
|
||||
return translations.budget + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.budget + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('budget' === type && null === name) {
|
||||
return translations.unknown_budget + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.unknown_budget + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
console.error('Cannot handle: type:"' + type + '", dir: "' + direction + '"');
|
||||
}
|
||||
@@ -121,25 +121,25 @@ function getObjectName(type, name, direction, code) {
|
||||
function getLabelName(type, name, code) {
|
||||
// category
|
||||
if ('category' === type && null !== name) {
|
||||
return translations.category + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.category + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('category' === type && null === name) {
|
||||
return translations.unknown_category + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.unknown_category + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
// account
|
||||
if ('account' === type && null === name) {
|
||||
return translations.unknown_account + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.unknown_account + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('account' === type && null !== name) {
|
||||
return name + (autoConversion ? ' (' + code + ')' : '');
|
||||
return name + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
|
||||
// budget 2x
|
||||
if ('budget' === type && null !== name) {
|
||||
return translations.budget + ' "' + name + '"' + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.budget + ' "' + name + '"' + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
if ('budget' === type && null === name) {
|
||||
return translations.unknown_budget + (autoConversion ? ' (' + code + ')' : '');
|
||||
return translations.unknown_budget + (convertToNative ? ' (' + code + ')' : '');
|
||||
}
|
||||
console.error('Cannot handle: type:"' + type + '"');
|
||||
}
|
||||
@@ -147,7 +147,7 @@ function getLabelName(type, name, code) {
|
||||
|
||||
export default () => ({
|
||||
loading: false,
|
||||
autoConversion: false,
|
||||
convertToNative: false,
|
||||
generateOptions() {
|
||||
let options = getDefaultChartSettings('sankey');
|
||||
|
||||
@@ -164,8 +164,8 @@ export default () => ({
|
||||
if (group.attributes.transactions.hasOwnProperty(ii)) {
|
||||
// properties of the transaction, used in the generation of the chart:
|
||||
let transaction = group.attributes.transactions[ii];
|
||||
let currencyCode = this.autoConversion ? transaction.native_currency_code : transaction.currency_code;
|
||||
let amount = this.autoConversion ? parseFloat(transaction.native_amount) : parseFloat(transaction.amount);
|
||||
let currencyCode = this.convertToNative ? transaction.native_currency_code : transaction.currency_code;
|
||||
let amount = this.convertToNative ? parseFloat(transaction.native_amount) : parseFloat(transaction.amount);
|
||||
let flowKey;
|
||||
|
||||
/*
|
||||
@@ -194,7 +194,7 @@ export default () => ({
|
||||
if (!amounts.hasOwnProperty(flowKey)) {
|
||||
amounts[flowKey] = {
|
||||
from: category,
|
||||
to: translations.all_money + (this.autoConversion ? ' (' + currencyCode + ')' : ''),
|
||||
to: translations.all_money + (this.convertToNative ? ' (' + currencyCode + ')' : ''),
|
||||
amount: 0
|
||||
};
|
||||
}
|
||||
@@ -214,7 +214,7 @@ export default () => ({
|
||||
|
||||
if (!amounts.hasOwnProperty(flowKey)) {
|
||||
amounts[flowKey] = {
|
||||
from: translations.all_money + (this.autoConversion ? ' (' + currencyCode + ')' : ''),
|
||||
from: translations.all_money + (this.convertToNative ? ' (' + currencyCode + ')' : ''),
|
||||
to: budget,
|
||||
amount: 0
|
||||
};
|
||||
@@ -348,9 +348,9 @@ export default () => ({
|
||||
init() {
|
||||
// console.log('sankey init');
|
||||
transactions = [];
|
||||
Promise.all([getVariable('autoConversion', false)]).then((values) => {
|
||||
this.autoConversion = values[0];
|
||||
autoConversion = values[0];
|
||||
Promise.all([getVariable('convertToNative', false)]).then((values) => {
|
||||
this.convertToNative = values[0];
|
||||
convertToNative = values[0];
|
||||
// some translations:
|
||||
translations.all_money = i18next.t('firefly.all_money');
|
||||
translations.category = i18next.t('firefly.category');
|
||||
@@ -378,12 +378,12 @@ export default () => ({
|
||||
this.transactions = [];
|
||||
this.loadChart();
|
||||
});
|
||||
window.store.observe('autoConversion', (newValue) => {
|
||||
window.store.observe('convertToNative', (newValue) => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
// console.log('sankey observe autoConversion');
|
||||
this.autoConversion = newValue;
|
||||
// console.log('sankey observe convertToNative');
|
||||
this.convertToNative = newValue;
|
||||
this.loadChart();
|
||||
});
|
||||
},
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import {getVariable} from "../../store/get-variable.js";
|
||||
import Get from "../../api/v2/model/subscription/get.js";
|
||||
import Get from "../../api/v1/model/subscription/get.js";
|
||||
import {format} from "date-fns";
|
||||
import {getCacheKey} from "../../support/get-cache-key.js";
|
||||
import {Chart} from "chart.js";
|
||||
@@ -66,10 +66,10 @@ function downloadSubscriptions(params) {
|
||||
currency_code: current.attributes.currency_code,
|
||||
|
||||
// native amount
|
||||
native_amount_min: current.attributes.native_amount_min,
|
||||
native_amount_max: current.attributes.native_amount_max,
|
||||
native_amount: (parseFloat(current.attributes.native_amount_max) + parseFloat(current.attributes.native_amount_min)) / 2,
|
||||
native_currency_code: current.attributes.native_currency_code,
|
||||
// native_amount_min: current.attributes.native_amount_min,
|
||||
// native_amount_max: current.attributes.native_amount_max,
|
||||
// native_amount: (parseFloat(current.attributes.native_amount_max) + parseFloat(current.attributes.native_amount_min)) / 2,
|
||||
// native_currency_code: current.attributes.native_currency_code,
|
||||
|
||||
// paid transactions:
|
||||
transactions: [],
|
||||
@@ -79,8 +79,7 @@ function downloadSubscriptions(params) {
|
||||
paid: current.attributes.paid_dates.length > 0,
|
||||
};
|
||||
// set variables
|
||||
bill.expected_amount = params.autoConversion ? formatMoney(bill.native_amount, bill.native_currency_code) :
|
||||
formatMoney(bill.amount, bill.currency_code);
|
||||
bill.expected_amount = formatMoney(bill.amount, bill.currency_code);
|
||||
bill.expected_times = i18next.t('firefly.subscr_expected_x_times', {
|
||||
times: current.attributes.pay_dates.length,
|
||||
amount: bill.expected_amount
|
||||
@@ -92,22 +91,25 @@ function downloadSubscriptions(params) {
|
||||
const currentPayment = current.attributes.paid_dates[iii];
|
||||
let percentage = 100;
|
||||
// math: -100+(paid/expected)*100
|
||||
if (params.autoConversion) {
|
||||
if (params.convertToNative) {
|
||||
percentage = Math.round(-100 + ((parseFloat(currentPayment.native_amount) * -1) / parseFloat(bill.native_amount)) * 100);
|
||||
}
|
||||
if (!params.autoConversion) {
|
||||
if (!params.convertToNative) {
|
||||
percentage = Math.round(-100 + ((parseFloat(currentPayment.amount) * -1) / parseFloat(bill.amount)) * 100);
|
||||
}
|
||||
|
||||
// TODO fix me
|
||||
currentPayment.currency_code = 'EUR';
|
||||
console.log('Currency code: "'+currentPayment+'"');
|
||||
console.log(currentPayment);
|
||||
let currentTransaction = {
|
||||
amount: params.autoConversion ? formatMoney(currentPayment.native_amount, currentPayment.native_currency_code) : formatMoney(currentPayment.amount, currentPayment.currency_code),
|
||||
amount: formatMoney(currentPayment.amount, currentPayment.currency_code),
|
||||
percentage: percentage,
|
||||
date: format(new Date(currentPayment.date), 'PP'),
|
||||
foreign_amount: null,
|
||||
};
|
||||
if (null !== currentPayment.foreign_currency_code) {
|
||||
currentTransaction.foreign_amount = params.autoConversion ? currentPayment.foreign_native_amount : currentPayment.foreign_amount;
|
||||
currentTransaction.foreign_currency_code = params.autoConversion ? currentPayment.native_currency_code : currentPayment.foreign_currency_code;
|
||||
currentTransaction.foreign_amount = currentPayment.foreign_amount;
|
||||
currentTransaction.foreign_currency_code = currentPayment.foreign_currency_code;
|
||||
}
|
||||
|
||||
bill.transactions.push(currentTransaction);
|
||||
@@ -119,7 +121,7 @@ function downloadSubscriptions(params) {
|
||||
// bill is unpaid, count the "pay_dates" and multiply with the "amount".
|
||||
// since bill is unpaid, this can only be in currency amount and native currency amount.
|
||||
const totalAmount = current.attributes.pay_dates.length * bill.amount;
|
||||
const totalNativeAmount = current.attributes.pay_dates.length * bill.native_amount;
|
||||
// const totalNativeAmount = current.attributes.pay_dates.length * bill.native_amount;
|
||||
// for bill's currency
|
||||
if (!subscriptionData[objectGroupId].payment_info.hasOwnProperty(bill.currency_code)) {
|
||||
subscriptionData[objectGroupId].payment_info[bill.currency_code] = {
|
||||
@@ -128,11 +130,11 @@ function downloadSubscriptions(params) {
|
||||
unpaid: 0,
|
||||
native_currency_code: bill.native_currency_code,
|
||||
native_paid: 0,
|
||||
native_unpaid: 0,
|
||||
//native_unpaid: 0,
|
||||
};
|
||||
}
|
||||
subscriptionData[objectGroupId].payment_info[bill.currency_code].unpaid += totalAmount;
|
||||
subscriptionData[objectGroupId].payment_info[bill.currency_code].native_unpaid += totalNativeAmount;
|
||||
//subscriptionData[objectGroupId].payment_info[bill.currency_code].native_unpaid += totalNativeAmount;
|
||||
}
|
||||
|
||||
if (current.attributes.paid_dates.length > 0) {
|
||||
@@ -149,15 +151,15 @@ function downloadSubscriptions(params) {
|
||||
currency_code: bill.currency_code,
|
||||
paid: 0,
|
||||
unpaid: 0,
|
||||
native_currency_code: bill.native_currency_code,
|
||||
native_paid: 0,
|
||||
native_unpaid: 0,
|
||||
// native_currency_code: bill.native_currency_code,
|
||||
// native_paid: 0,
|
||||
//native_unpaid: 0,
|
||||
};
|
||||
}
|
||||
const amount = parseFloat(currentJournal.amount) * -1;
|
||||
const nativeAmount = parseFloat(currentJournal.native_amount) * -1;
|
||||
// const nativeAmount = parseFloat(currentJournal.native_amount) * -1;
|
||||
subscriptionData[objectGroupId].payment_info[currentJournal.currency_code].paid += amount;
|
||||
subscriptionData[objectGroupId].payment_info[currentJournal.currency_code].native_paid += nativeAmount;
|
||||
// subscriptionData[objectGroupId].payment_info[currentJournal.currency_code].native_paid += nativeAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,7 +180,7 @@ function downloadSubscriptions(params) {
|
||||
|
||||
export default () => ({
|
||||
loading: false,
|
||||
autoConversion: false,
|
||||
convertToNative: false,
|
||||
subscriptions: [],
|
||||
startSubscriptions() {
|
||||
this.loading = true;
|
||||
@@ -198,7 +200,7 @@ export default () => ({
|
||||
let params = {
|
||||
start: format(start, 'y-MM-dd'),
|
||||
end: format(end, 'y-MM-dd'),
|
||||
autoConversion: this.autoConversion,
|
||||
// convertToNative: this.convertToNative,
|
||||
page: 1
|
||||
};
|
||||
downloadSubscriptions(params).then(() => {
|
||||
@@ -226,9 +228,9 @@ export default () => ({
|
||||
drawPieChart(groupId, groupTitle, data) {
|
||||
let id = '#pie_' + groupId + '_' + data.currency_code;
|
||||
//console.log(data);
|
||||
const unpaidAmount = this.autoConversion ? data.native_unpaid : data.unpaid;
|
||||
const paidAmount = this.autoConversion ? data.native_paid : data.paid;
|
||||
const currencyCode = this.autoConversion ? data.native_currency_code : data.currency_code;
|
||||
const unpaidAmount = data.unpaid;
|
||||
const paidAmount = data.paid;
|
||||
const currencyCode = data.currency_code;
|
||||
const chartData = {
|
||||
labels: [
|
||||
i18next.t('firefly.paid'),
|
||||
@@ -267,8 +269,8 @@ export default () => ({
|
||||
},
|
||||
|
||||
init() {
|
||||
Promise.all([getVariable('autoConversion', false)]).then((values) => {
|
||||
this.autoConversion = values[0];
|
||||
Promise.all([getVariable('convertToNative', false)]).then((values) => {
|
||||
this.convertToNative = values[0];
|
||||
afterPromises = true;
|
||||
|
||||
if (false === this.loading) {
|
||||
@@ -285,11 +287,11 @@ export default () => ({
|
||||
this.startSubscriptions();
|
||||
}
|
||||
});
|
||||
window.store.observe('autoConversion', (newValue) => {
|
||||
window.store.observe('convertToNative', (newValue) => {
|
||||
if (!afterPromises) {
|
||||
return;
|
||||
}
|
||||
this.autoConversion = newValue;
|
||||
this.convertToNative = newValue;
|
||||
if (false === this.loading) {
|
||||
this.startSubscriptions();
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ import dates from '../../pages/shared/dates.js';
|
||||
import {createEmptySplit, defaultErrorSet} from "./shared/create-empty-split.js";
|
||||
import {parseFromEntries} from "./shared/parse-from-entries.js";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
import Post from "../../api/v2/model/transaction/post.js";
|
||||
import Post from "../../api/v1/model/transaction/post.js";
|
||||
import {loadCurrencies} from "./shared/load-currencies.js";
|
||||
import {loadBudgets} from "./shared/load-budgets.js";
|
||||
import {loadPiggyBanks} from "./shared/load-piggy-banks.js";
|
||||
|
@@ -21,7 +21,7 @@
|
||||
import '../../boot/bootstrap.js';
|
||||
import dates from '../../pages/shared/dates.js';
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
import Get from "../../api/v2/model/transaction/get.js";
|
||||
import Get from "../../api/v1/model/transaction/get.js";
|
||||
import {parseDownloadedSplits} from "./shared/parse-downloaded-splits.js";
|
||||
import {addAutocomplete, getUrls} from "./shared/add-autocomplete.js";
|
||||
import {
|
||||
@@ -40,7 +40,7 @@ import Tags from "bootstrap5-tags";
|
||||
import i18next from "i18next";
|
||||
import {defaultErrorSet} from "./shared/create-empty-split.js";
|
||||
import {parseFromEntries} from "./shared/parse-from-entries.js";
|
||||
import Put from "../../api/v2/model/transaction/put.js";
|
||||
import Put from "../../api/v1/model/transaction/put.js";
|
||||
import {processAttachments} from "./shared/process-attachments.js";
|
||||
import {spliceErrorsIntoTransactions} from "./shared/splice-errors-into-transactions.js";
|
||||
|
||||
|
@@ -24,10 +24,8 @@ import i18next from "i18next";
|
||||
import {format} from "date-fns";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
|
||||
import '@ag-grid-community/styles/ag-grid.css';
|
||||
import '@ag-grid-community/styles/ag-theme-alpine.css';
|
||||
import '../../css/grid-ff3-theme.css';
|
||||
import Get from "../../api/v2/model/transaction/get.js";
|
||||
import Get from "../../api/v1/model/transaction/get.js";
|
||||
|
||||
let index = function () {
|
||||
return {
|
||||
|
@@ -22,10 +22,10 @@ import Autocomplete from "bootstrap5-autocomplete";
|
||||
|
||||
export function getUrls() {
|
||||
return {
|
||||
description: '/api/v2/autocomplete/transaction-descriptions',
|
||||
account: '/api/v2/autocomplete/accounts',
|
||||
category: '/api/v2/autocomplete/categories',
|
||||
tag: '/api/v2/autocomplete/tags',
|
||||
description: '/api/v1/autocomplete/transaction-descriptions',
|
||||
account: '/api/v1/autocomplete/accounts',
|
||||
category: '/api/v1/autocomplete/categories',
|
||||
tag: '/api/v1/autocomplete/tags',
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
|
||||
import Get from "../../../api/v2/model/budget/get.js";
|
||||
import Get from "../../../api/v1/model/budget/get.js";
|
||||
|
||||
export function loadBudgets() {
|
||||
let params = {
|
||||
|
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
|
||||
import Get from "../../../api/v2/model/currency/get.js";
|
||||
import Get from "../../../api/v1/model/currency/get.js";
|
||||
|
||||
export function loadCurrencies() {
|
||||
let params = {
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Get from "../../../api/v2/model/piggy-bank/get.js";
|
||||
import Get from "../../../api/v1/model/piggy-bank/get.js";
|
||||
|
||||
export function loadPiggyBanks() {
|
||||
let params = {
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import SubscriptionGet from "../../../api/v2/model/subscription/get.js";
|
||||
import SubscriptionGet from "../../../api/v1/model/subscription/get.js";
|
||||
|
||||
export function loadSubscriptions() {
|
||||
let params = {
|
||||
|
@@ -21,7 +21,7 @@
|
||||
import '../../boot/bootstrap.js';
|
||||
import dates from "../shared/dates.js";
|
||||
import i18next from "i18next";
|
||||
import Get from "../../api/v2/model/transaction/get.js";
|
||||
import Get from "../../api/v1/model/transaction/get.js";
|
||||
import {parseDownloadedSplits} from "./shared/parse-downloaded-splits.js";
|
||||
import {format} from "date-fns";
|
||||
import formatMoney from "../../util/format-money.js";
|
||||
|
@@ -36,8 +36,8 @@ export default defineConfig(({command, mode, isSsrBuild, isPreview}) => {
|
||||
let https = null;
|
||||
if (command === 'serve') {
|
||||
https = {
|
||||
key: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.key`),
|
||||
cert: fs.readFileSync(`/sites/vm/tls-certificates/wildcard.sd.internal.crt`),
|
||||
key: fs.readFileSync(`/vagrant/tls-certificates/wildcard.sd.internal.key`),
|
||||
cert: fs.readFileSync(`/vagrant/tls-certificates/wildcard.sd.internal.crt`),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -82,11 +82,13 @@ export default defineConfig(({command, mode, isSsrBuild, isPreview}) => {
|
||||
|
||||
|
||||
server: {
|
||||
origin: 'http://127.0.0.1:8000',
|
||||
cors: true,
|
||||
origin: 'https://firefly.sd.internal:5173',
|
||||
watch: {
|
||||
usePolling: true,
|
||||
},
|
||||
host: '10.0.0.15',
|
||||
port: 5173,
|
||||
host: true,
|
||||
// hmr: {
|
||||
// protocol: 'wss',
|
||||
// },
|
||||
|
@@ -9,17 +9,17 @@
|
||||
<div class="card-body p-0" style="position: relative;height:400px;">
|
||||
<canvas id="account-chart"></canvas>
|
||||
</div>
|
||||
<template x-if="autoConversionAvailable">
|
||||
<template x-if="convertToNativeAvailable">
|
||||
<div class="card-footer text-end">
|
||||
<template x-if="autoConversion">
|
||||
<button type="button" @click="switchAutoConversion"
|
||||
<template x-if="convertToNative">
|
||||
<button type="button" @click="switchConvertToNative"
|
||||
class="btn btn-outline-info btm-sm">
|
||||
<span
|
||||
class="fa-solid fa-comments-dollar"></span> {{ __('firefly.disable_auto_convert') }}
|
||||
</button>
|
||||
</template>
|
||||
<template x-if="!autoConversion">
|
||||
<button type="button" @click="switchAutoConversion"
|
||||
<template x-if="!convertToNative">
|
||||
<button type="button" @click="switchConvertToNative"
|
||||
class="btn btn-outline-info btm-sm">
|
||||
<span
|
||||
class="fa-solid fa-comments-dollar"></span> {{ __('firefly.enable_auto_convert') }}
|
||||
|
@@ -75,7 +75,7 @@
|
||||
<ul class="list-unstyled list-no-margin">
|
||||
<template x-for="transaction in group.transactions">
|
||||
<li>
|
||||
@include('partials.elements.amount', ['autoConversion' => true,'type' => 'transaction.type','amount' => 'transaction.amount','native' => 'transaction.native_amount'])
|
||||
@include('partials.elements.amount', ['convertToNative' => true,'type' => 'transaction.type','amount' => 'transaction.amount','native' => 'transaction.native_amount'])
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
@if($autoConversion)
|
||||
<template x-if="autoConversion">
|
||||
@if($convertToNative)
|
||||
<template x-if="convertToNative">
|
||||
<span>
|
||||
<template x-if="{{ $native }}_raw < 0">
|
||||
<span class="text-danger">
|
||||
@@ -20,7 +20,7 @@
|
||||
</template>
|
||||
</span>
|
||||
</template>
|
||||
<template x-if="!autoConversion">
|
||||
<template x-if="!convertToNative">
|
||||
<span>
|
||||
<template x-if="{{ $amount }}_raw < 0">
|
||||
|
||||
|
@@ -337,9 +337,33 @@ Route::group(
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('overview', ['uses' => 'AccountController@overview', 'as' => 'overview']);
|
||||
Route::get('dashboard', ['uses' => 'AccountController@dashboard', 'as' => 'dashboard']);
|
||||
}
|
||||
);
|
||||
|
||||
Route::group(
|
||||
[
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\Chart',
|
||||
'prefix' => 'v1/chart/budget',
|
||||
'as' => 'api.v1.chart.budget.',
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('dashboard', ['uses' => 'BudgetController@dashboard', 'as' => 'dashboard']);
|
||||
}
|
||||
);
|
||||
|
||||
Route::group(
|
||||
[
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\Chart',
|
||||
'prefix' => 'v1/chart/category',
|
||||
'as' => 'api.v1.chart.category.',
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('dashboard', ['uses' => 'CategoryController@dashboard', 'as' => 'dashboard']);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// DATA ROUTES
|
||||
// Export data API routes
|
||||
Route::group(
|
||||
@@ -351,6 +375,7 @@ Route::group(
|
||||
static function (): void {
|
||||
Route::get('accounts', ['uses' => 'ExportController@accounts', 'as' => 'accounts']);
|
||||
Route::get('bills', ['uses' => 'ExportController@bills', 'as' => 'bills']);
|
||||
Route::get('subscriptions', ['uses' => 'ExportController@bills', 'as' => 'subscriptions']);
|
||||
Route::get('budgets', ['uses' => 'ExportController@budgets', 'as' => 'budgets']);
|
||||
Route::get('categories', ['uses' => 'ExportController@categories', 'as' => 'categories']);
|
||||
Route::get('piggy-banks', ['uses' => 'ExportController@piggyBanks', 'as' => 'piggy-banks']);
|
||||
@@ -556,6 +581,24 @@ Route::group(
|
||||
Route::get('{bill}/transactions', ['uses' => 'ListController@transactions', 'as' => 'transactions']);
|
||||
}
|
||||
);
|
||||
Route::group(
|
||||
[
|
||||
'namespace' => 'FireflyIII\Api\V1\Controllers\Models\Bill',
|
||||
'prefix' => 'v1/subscriptions',
|
||||
'as' => 'api.v1.subscriptions.',
|
||||
],
|
||||
static function (): void {
|
||||
Route::get('', ['uses' => 'ShowController@index', 'as' => 'index']);
|
||||
Route::post('', ['uses' => 'StoreController@store', 'as' => 'store']);
|
||||
Route::get('{bill}', ['uses' => 'ShowController@show', 'as' => 'show']);
|
||||
Route::put('{bill}', ['uses' => 'UpdateController@update', 'as' => 'update']);
|
||||
Route::delete('{bill}', ['uses' => 'DestroyController@destroy', 'as' => 'delete']);
|
||||
|
||||
Route::get('{bill}/attachments', ['uses' => 'ListController@attachments', 'as' => 'attachments']);
|
||||
Route::get('{bill}/rules', ['uses' => 'ListController@rules', 'as' => 'rules']);
|
||||
Route::get('{bill}/transactions', ['uses' => 'ListController@transactions', 'as' => 'transactions']);
|
||||
}
|
||||
);
|
||||
|
||||
// Available Budget API routes:
|
||||
Route::group(
|
||||
|
Reference in New Issue
Block a user