mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-10-19 10:53:31 +00:00
Compare commits
150 Commits
develop-20
...
v6.3.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
fe702a3030 | ||
|
2244d366bd | ||
|
ac16e0294e | ||
|
bf1b0ee3c2 | ||
|
ffec4bbfba | ||
|
ae6e103c09 | ||
|
99d4471f75 | ||
|
7f1fb72298 | ||
|
009c2ed5d9 | ||
|
44fc00299c | ||
|
774fc4281c | ||
|
c47955c069 | ||
|
e7569644f7 | ||
|
c567474043 | ||
|
9f394e92fe | ||
|
66befc7e44 | ||
|
c3a28fc698 | ||
|
ef317d5b3c | ||
|
152301f9ee | ||
|
645e9ba1f7 | ||
|
56487c3a33 | ||
|
b8062a915c | ||
|
5780c9512a | ||
|
71d39707d9 | ||
|
9ccb8ae692 | ||
|
8cd50bb5bd | ||
|
ae9e1278e5 | ||
|
58c03797b2 | ||
|
7db38b4c6c | ||
|
da6b447e64 | ||
|
c19ac2b0f3 | ||
|
d5ca2171b3 | ||
|
20972cb29f | ||
|
7b714d0866 | ||
|
240ae8fa57 | ||
|
5a2f6b2652 | ||
|
4196ce31f0 | ||
|
be8ca5db50 | ||
|
30a417ea3c | ||
|
695ed940e0 | ||
|
1353554cf8 | ||
|
e1ba2732af | ||
|
42b57c0e0e | ||
|
a6072753b2 | ||
|
e92c224c39 | ||
|
a3ed7ec8f6 | ||
|
17a2f99dff | ||
|
c14971543c | ||
|
55f899608d | ||
|
83be63f27e | ||
|
ed48d190e5 | ||
|
3c3b6615e6 | ||
|
e71e5a877b | ||
|
b2a65dc660 | ||
|
d66dccd076 | ||
|
c1128b28f2 | ||
|
da8e78c28d | ||
|
f50aa6b0ce | ||
|
661e4e53e6 | ||
|
3eeda4a6aa | ||
|
4dba9cea21 | ||
|
6aab5fab05 | ||
|
4b0597d19a | ||
|
92f534bcb3 | ||
|
76e91be4dc | ||
|
deca4fed56 | ||
|
73512b0365 | ||
|
aaffc125e7 | ||
|
41a48c39a0 | ||
|
2d96bd84b5 | ||
|
ad1c1d2254 | ||
|
813206766d | ||
|
bb25d4a82a | ||
|
f3b78beecc | ||
|
64073768fe | ||
|
fe6dd0f901 | ||
|
aac8d11ff6 | ||
|
afa99a35b5 | ||
|
e9cb0a51d7 | ||
|
9fbcccfd02 | ||
|
468c9c9d56 | ||
|
f76b27a73d | ||
|
579fe81616 | ||
|
ec9ba53690 | ||
|
85337c53d4 | ||
|
eb6d585bb2 | ||
|
378ffbc609 | ||
|
3b3c8e5bcd | ||
|
75cbdb6a57 | ||
|
cdaff0d983 | ||
|
dda3863889 | ||
|
57dc423b3f | ||
|
c0570bc3b2 | ||
|
65110d1666 | ||
|
5a10b29402 | ||
|
028544ca2e | ||
|
af46729372 | ||
|
4c7789a668 | ||
|
292908048c | ||
|
e300314e05 | ||
|
4f1f360346 | ||
|
bff856aeff | ||
|
7f5a1bda8d | ||
|
b506281bd6 | ||
|
dfe9b3e787 | ||
|
2428a2a7c5 | ||
|
0e8f608e00 | ||
|
70071767ab | ||
|
0ad6beb66c | ||
|
1197f65589 | ||
|
7bbf2dcc6f | ||
|
d4ab69ebe6 | ||
|
c8c552602e | ||
|
1921a8050b | ||
|
f488feda93 | ||
|
d90c033b83 | ||
|
9f256253f2 | ||
|
489b7c12e5 | ||
|
1049a8314d | ||
|
48301b6b9c | ||
|
5a92215921 | ||
|
ccfc75852a | ||
|
9804cffff3 | ||
|
901e113fef | ||
|
a4021ff056 | ||
|
902d91ad29 | ||
|
fa2cf22e73 | ||
|
970dad4c49 | ||
|
9d01c7bdb8 | ||
|
dc7d4fb258 | ||
|
a807ca5002 | ||
|
d59d326841 | ||
|
b915548e82 | ||
|
8200a81840 | ||
|
6a49918707 | ||
|
e55fc483bd | ||
|
4ff5f5883d | ||
|
eda2eae04a | ||
|
c07c30ea17 | ||
|
56f1eb03e0 | ||
|
d4e14dd262 | ||
|
0c7f04fb17 | ||
|
061c01da53 | ||
|
716d72d8af | ||
|
3233ca4a4c | ||
|
1041030b1e | ||
|
bb3b06cf08 | ||
|
f35e361915 | ||
|
47d697c7dc | ||
|
3745d79f1f |
2
.github/workflows/close-duplicates.yml
vendored
2
.github/workflows/close-duplicates.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
close_duplicates:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: github/command@v2.0.1
|
||||
- uses: github/command@v2.0.2
|
||||
id: command
|
||||
with:
|
||||
allowed_contexts: "issue"
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Debug\Timer;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use FireflyIII\Support\Http\Api\AccountFilter;
|
||||
use FireflyIII\User;
|
||||
@@ -79,17 +80,20 @@ class AccountController extends Controller
|
||||
*/
|
||||
public function accounts(AutocompleteRequest $request): JsonResponse
|
||||
{
|
||||
$data = $request->getData();
|
||||
$types = $data['types'];
|
||||
$query = $data['query'];
|
||||
$date = $data['date'] ?? today(config('app.timezone'));
|
||||
$return = [];
|
||||
Timer::start(sprintf('AC accounts "%s"', $query));
|
||||
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
|
||||
$data = $request->getData();
|
||||
$types = $data['types'];
|
||||
$query = $data['query'];
|
||||
$date = $data['date'] ?? today(config('app.timezone'));
|
||||
$return = [];
|
||||
$timer = Timer::getInstance();
|
||||
$timer->start(sprintf('AC accounts "%s"', $query));
|
||||
$result = $this->repository->searchAccount((string) $query, $types, $this->parameters->get('limit'));
|
||||
|
||||
// set date to subday + end-of-day for account balance. so it is at $date 23:59:59
|
||||
$date->endOfDay();
|
||||
|
||||
$allBalances = Steam::accountsBalancesOptimized($result, $date, $this->primaryCurrency, $this->convertToPrimary);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($result as $account) {
|
||||
$nameWithBalance = $account->name;
|
||||
@@ -98,15 +102,11 @@ class AccountController extends Controller
|
||||
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
|
||||
// this one is correct.
|
||||
Log::debug(sprintf('accounts: Call finalAccountBalance with date/time "%s"', $date->toIso8601String()));
|
||||
$balance = Steam::finalAccountBalance($account, $date);
|
||||
$balance = $allBalances[$account->id] ?? [];
|
||||
$key = $this->convertToPrimary && $currency->id !== $this->primaryCurrency->id ? 'pc_balance' : 'balance';
|
||||
$useCurrency = $this->convertToPrimary && $currency->id !== $this->primaryCurrency->id ? $this->primaryCurrency : $currency;
|
||||
$amount = $balance[$key] ?? '0';
|
||||
$nameWithBalance = sprintf(
|
||||
'%s (%s)',
|
||||
$account->name,
|
||||
app('amount')->formatAnything($useCurrency, $amount, false)
|
||||
);
|
||||
$nameWithBalance = sprintf('%s (%s)', $account->name, Amount::formatAnything($useCurrency, $amount, false));
|
||||
}
|
||||
|
||||
$return[] = [
|
||||
@@ -138,7 +138,7 @@ class AccountController extends Controller
|
||||
return $posA - $posB;
|
||||
}
|
||||
);
|
||||
Timer::stop(sprintf('AC accounts "%s"', $query));
|
||||
$timer->stop(sprintf('AC accounts "%s"', $query));
|
||||
|
||||
return response()->api($return);
|
||||
}
|
||||
|
97
app/Api/V1/Controllers/Chart/BalanceController.php
Normal file
97
app/Api/V1/Controllers/Chart/BalanceController.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Chart;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Chart\ChartRequest;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Chart\ChartData;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Http\Api\AccountBalanceGrouped;
|
||||
use FireflyIII\Support\Http\Api\CleansChartData;
|
||||
use FireflyIII\Support\Http\Api\CollectsAccountsFromFilter;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
||||
/**
|
||||
* Class BalanceController
|
||||
*/
|
||||
class BalanceController extends Controller
|
||||
{
|
||||
use CleansChartData;
|
||||
use CollectsAccountsFromFilter;
|
||||
|
||||
private ChartData $chartData;
|
||||
private GroupCollectorInterface $collector;
|
||||
private AccountRepositoryInterface $repository;
|
||||
|
||||
// private TransactionCurrency $default;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
$this->repository = app(AccountRepositoryInterface::class);
|
||||
$this->collector = app(GroupCollectorInterface::class);
|
||||
$userGroup = $this->validateUserGroup($request);
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
$this->collector->setUserGroup($userGroup);
|
||||
$this->chartData = new ChartData();
|
||||
// $this->default = app('amount')->getPrimaryCurrency();
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The code is practically a duplicate of ReportController::operations.
|
||||
*
|
||||
* Currency is up to the account/transactions in question, but conversion to the default
|
||||
* currency is possible.
|
||||
*
|
||||
* If the transaction being processed is already in native currency OR if the
|
||||
* foreign amount is in the native currency, the amount will not be converted.
|
||||
*
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function balance(ChartRequest $request): JsonResponse
|
||||
{
|
||||
$queryParameters = $request->getParameters();
|
||||
$accounts = $this->getAccountList($queryParameters);
|
||||
|
||||
// prepare for currency conversion and data collection:
|
||||
/** @var TransactionCurrency $primary */
|
||||
$primary = Amount::getPrimaryCurrency();
|
||||
|
||||
// get journals for entire period:
|
||||
|
||||
$this->collector->setRange($queryParameters['start'], $queryParameters['end'])
|
||||
->withAccountInformation()
|
||||
->setXorAccounts($accounts)
|
||||
->setTypes([TransactionTypeEnum::WITHDRAWAL->value, TransactionTypeEnum::DEPOSIT->value, TransactionTypeEnum::RECONCILIATION->value, TransactionTypeEnum::TRANSFER->value])
|
||||
;
|
||||
$journals = $this->collector->getExtractedJournals();
|
||||
|
||||
$object = new AccountBalanceGrouped();
|
||||
$object->setPreferredRange($queryParameters['period']);
|
||||
$object->setPrimary($primary);
|
||||
$object->setAccounts($accounts);
|
||||
$object->setJournals($journals);
|
||||
$object->setStart($queryParameters['start']);
|
||||
$object->setEnd($queryParameters['end']);
|
||||
$object->groupByCurrencyAndPeriod();
|
||||
$data = $object->convertToChartData();
|
||||
foreach ($data as $entry) {
|
||||
$this->chartData->add($entry);
|
||||
}
|
||||
|
||||
return response()->json($this->chartData->render());
|
||||
}
|
||||
}
|
@@ -291,7 +291,7 @@ class BudgetController extends Controller
|
||||
}
|
||||
if ($current->transaction_currency_id !== $this->primaryCurrency->id) {
|
||||
// convert and then add it.
|
||||
$converted = $converter->convert($current->transactionCurrency, $this->primaryCurrency, $limit->start_date, $limit->amount);
|
||||
$converted = $converter->convert($current->transactionCurrency, $this->primaryCurrency, $current->start_date, $current->amount);
|
||||
$amount = bcadd($amount, $converted);
|
||||
Log::debug(sprintf('Budgeted in limit #%d: %s %s, converted to %s %s', $current->id, $current->transactionCurrency->code, $current->amount, $this->primaryCurrency->code, $converted));
|
||||
Log::debug(sprintf('Set amount in limit to %s', $amount));
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
@@ -117,6 +118,13 @@ class ListController extends Controller
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.accounts.piggy-banks', [$account->id]).$this->buildParams());
|
||||
@@ -125,7 +133,7 @@ class ListController extends Controller
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks');
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -96,8 +96,8 @@ class ShowController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate($this->parameters->get('date'));
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$accounts = $enrichment->enrich($accounts);
|
||||
|
||||
// make paginator:
|
||||
@@ -131,8 +131,8 @@ class ShowController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate($this->parameters->get('date'));
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$account = $enrichment->enrichSingle($account);
|
||||
|
||||
|
||||
|
@@ -75,8 +75,8 @@ class StoreController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate(null);
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$account = $enrichment->enrichSingle($account);
|
||||
|
||||
/** @var AccountTransformer $transformer */
|
||||
|
@@ -80,8 +80,8 @@ class UpdateController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate(null);
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$account = $enrichment->enrichSingle($account);
|
||||
|
||||
/** @var AccountTransformer $transformer */
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Repositories\Budget\AvailableBudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AvailableBudgetEnrichment;
|
||||
use FireflyIII\Transformers\AvailableBudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -75,7 +76,6 @@ class ShowController extends Controller
|
||||
|
||||
// types to get, page size:
|
||||
$pageSize = $this->parameters->get('limit');
|
||||
|
||||
$start = $this->parameters->get('start');
|
||||
$end = $this->parameters->get('end');
|
||||
|
||||
@@ -84,6 +84,13 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$availableBudgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AvailableBudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$availableBudgets = $enrichment->enrich($availableBudgets);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($availableBudgets, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.available-budgets.index').$this->buildParams());
|
||||
@@ -106,13 +113,25 @@ class ShowController extends Controller
|
||||
*/
|
||||
public function show(AvailableBudget $availableBudget): JsonResponse
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
$manager = $this->getManager();
|
||||
$start = $this->parameters->get('start');
|
||||
$end = $this->parameters->get('end');
|
||||
|
||||
/** @var AvailableBudgetTransformer $transformer */
|
||||
$transformer = app(AvailableBudgetTransformer::class);
|
||||
$transformer = app(AvailableBudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($availableBudget, $transformer, 'available_budgets');
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AvailableBudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
$availableBudget = $enrichment->enrichSingle($availableBudget);
|
||||
|
||||
|
||||
$resource = new Item($availableBudget, $transformer, 'available_budgets');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
@@ -83,8 +83,6 @@ class ShowController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$bills = $enrichment->enrich($bills);
|
||||
@@ -114,8 +112,6 @@ class ShowController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$bill = $enrichment->enrichSingle($bill);
|
||||
|
@@ -79,8 +79,6 @@ class StoreController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$bill = $enrichment->enrichSingle($bill);
|
||||
|
@@ -74,8 +74,6 @@ class UpdateController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$bill = $enrichment->enrichSingle($bill);
|
||||
|
@@ -32,6 +32,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
@@ -117,6 +118,14 @@ class ListController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budgets.budget-limits', [$budget->id]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -29,7 +29,9 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
|
||||
use FireflyIII\Transformers\BudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -82,6 +84,15 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$budgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$budgets = $enrichment->enrich($budgets);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($budgets, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budgets.index').$this->buildParams());
|
||||
@@ -103,6 +114,15 @@ class ShowController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$budget = $enrichment->enrichSingle($budget);
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Budget\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
|
||||
use FireflyIII\Transformers\BudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -69,6 +71,13 @@ class StoreController extends Controller
|
||||
$budget->refresh();
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budget = $enrichment->enrichSingle($budget);
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Budget\UpdateRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
|
||||
use FireflyIII\Transformers\BudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -67,6 +69,13 @@ class UpdateController extends Controller
|
||||
$budget = $this->repository->update($budget, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budget = $enrichment->enrichSingle($budget);
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -84,6 +85,14 @@ class ShowController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budgets.limits.index', [$budget->id]).$this->buildParams());
|
||||
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
@@ -113,6 +122,13 @@ class ShowController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budget-limits.index').$this->buildParams());
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
@@ -137,6 +153,13 @@ class ShowController extends Controller
|
||||
// continue!
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimit = $enrichment->enrichSingle($budgetLimit);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\BudgetLimit\StoreRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -74,6 +75,13 @@ class StoreController extends Controller
|
||||
$budgetLimit = $this->blRepository->store($data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimit = $enrichment->enrichSingle($budgetLimit);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -80,6 +81,13 @@ class UpdateController extends Controller
|
||||
$budgetLimit = $this->blRepository->update($budgetLimit, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimit = $enrichment->enrich($budgetLimit);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment;
|
||||
use FireflyIII\Transformers\CategoryTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -78,6 +80,15 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$categories = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new CategoryEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$categories = $enrichment->enrich($categories);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($categories, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.categories.index').$this->buildParams());
|
||||
@@ -105,6 +116,15 @@ class ShowController extends Controller
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new CategoryEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$category = $enrichment->enrichSingle($category);
|
||||
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Category\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment;
|
||||
use FireflyIII\Transformers\CategoryTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -72,6 +74,15 @@ class StoreController extends Controller
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new CategoryEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$category = $enrichment->enrichSingle($category);
|
||||
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Category\UpdateRequest;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\CategoryEnrichment;
|
||||
use FireflyIII\Transformers\CategoryTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -71,6 +73,15 @@ class UpdateController extends Controller
|
||||
$transformer = app(CategoryTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new CategoryEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$category = $enrichment->enrichSingle($category);
|
||||
|
||||
$resource = new Item($category, $transformer, 'categories');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Transformers\ExchangeRateTransformer;
|
||||
@@ -39,7 +40,7 @@ class IndexController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'currency_exchange_rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
@@ -41,7 +42,7 @@ class ShowController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'exchange-rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreRequest;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
@@ -37,7 +38,7 @@ class StoreController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'exchange-rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\UpdateRequest;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
@@ -37,7 +38,7 @@ class UpdateController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'exchange-rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\SubscriptionEnrichment;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
@@ -85,8 +86,6 @@ class ListController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$bills = $enrichment->enrich($bills);
|
||||
@@ -126,6 +125,13 @@ class ListController extends Controller
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.object-groups.piggy-banks', [$objectGroup->id]).$this->buildParams());
|
||||
@@ -134,7 +140,7 @@ class ListController extends Controller
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks');
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEventEnrichment;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankEventTransformer;
|
||||
@@ -83,8 +84,8 @@ class ListController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate($this->parameters->get('date'));
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$accounts = $enrichment->enrich($accounts);
|
||||
|
||||
// make paginator:
|
||||
@@ -148,6 +149,13 @@ class ListController extends Controller
|
||||
$count = $collection->count();
|
||||
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEventEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$events = $enrichment->enrich($events);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.piggy-banks.events', [$piggyBank->id]).$this->buildParams());
|
||||
@@ -156,7 +164,7 @@ class ListController extends Controller
|
||||
$transformer = app(PiggyBankEventTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($events, $transformer, 'piggy_bank_events');
|
||||
$resource = new FractalCollection($events, $transformer, sprintf('piggy-banks/%d/events', $piggyBank->id));
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -77,6 +79,13 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.piggy-banks.index').$this->buildParams());
|
||||
@@ -85,7 +94,7 @@ class ShowController extends Controller
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks');
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy-banks');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -101,11 +110,19 @@ class ShowController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy-banks');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\PiggyBank\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -68,6 +70,13 @@ class StoreController extends Controller
|
||||
$piggyBank = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\PiggyBank\UpdateRequest;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -70,13 +72,20 @@ class UpdateController extends Controller
|
||||
$this->repository->setCurrentAmount($piggyBank, $data['current_amount']);
|
||||
}
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy_banks');
|
||||
$resource = new Item($piggyBank, $transformer, 'piggy-banks');
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
}
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -76,17 +78,24 @@ class ShowController extends Controller
|
||||
// get list of budgets. Count it and split it.
|
||||
$collection = $this->repository->get();
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$recurrences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrences = $enrichment->enrich($recurrences);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator = new LengthAwarePaginator($recurrences, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.recurrences.index').$this->buildParams());
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'recurrences');
|
||||
$resource = new FractalCollection($recurrences, $transformer, 'recurrences');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -102,6 +111,13 @@ class ShowController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Recurrence\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -69,6 +71,13 @@ class StoreController extends Controller
|
||||
$recurrence = $this->repository->store($data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Recurrence\UpdateRequest;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -67,6 +69,13 @@ class UpdateController extends Controller
|
||||
$recurrence = $this->repository->update($recurrence, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -29,6 +29,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\Journal\JournalAPIRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEventEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankEventTransformer;
|
||||
use FireflyIII\Transformers\TransactionLinkTransformer;
|
||||
@@ -113,6 +114,14 @@ class ListController extends Controller
|
||||
}
|
||||
$count = $collection->count();
|
||||
$events = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEventEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$events = $enrichment->enrich($events);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($events, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.transactions.piggy-bank-events', [$transactionGroup->id]).$this->buildParams());
|
||||
|
@@ -43,6 +43,8 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\AccountFilter;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\SubscriptionEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
@@ -107,8 +109,8 @@ class ListController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate($this->parameters->get('date'));
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$accounts = $enrichment->enrich($accounts);
|
||||
|
||||
// make paginator:
|
||||
@@ -188,8 +190,6 @@ class ListController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$bills = $enrichment->enrichSingle($bills);
|
||||
@@ -229,6 +229,13 @@ class ListController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.currencies.budget-limits', [$currency->code]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
@@ -270,17 +277,24 @@ class ListController extends Controller
|
||||
}
|
||||
);
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$recurrences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrences = $enrichment->enrich($recurrences);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator = new LengthAwarePaginator($recurrences, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.currencies.recurrences', [$currency->code]).$this->buildParams());
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'recurrences');
|
||||
$resource = new FractalCollection($recurrences, $transformer, 'recurrences');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -88,8 +88,8 @@ class AccountController extends Controller
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate($this->parameters->get('date'));
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$accounts = $enrichment->enrich($accounts);
|
||||
|
||||
/** @var AccountTransformer $transformer */
|
||||
|
@@ -248,10 +248,10 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId]['sum'] ?? '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, $sums[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false)
|
||||
.' + '.app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'sub_title' => Amount::formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false)
|
||||
.' + '.Amount::formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
@@ -261,7 +261,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -273,7 +273,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -289,10 +289,10 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => app('amount')->formatAnything($currency, '0', false)
|
||||
.' + '.app('amount')->formatAnything($currency, '0', false),
|
||||
'sub_title' => Amount::formatAnything($currency, '0', false)
|
||||
.' + '.Amount::formatAnything($currency, '0', false),
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
@@ -302,7 +302,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -314,7 +314,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -405,7 +405,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $info['code'],
|
||||
'currency_symbol' => $info['symbol'],
|
||||
'currency_decimal_places' => $info['decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'value_parsed' => Amount::formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'local_icon' => 'check',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -424,7 +424,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $info['code'],
|
||||
'currency_symbol' => $info['symbol'],
|
||||
'currency_decimal_places' => $info['decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'value_parsed' => Amount::formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'local_icon' => 'calendar-o',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -443,7 +443,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'value_parsed' => Amount::formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'local_icon' => 'check',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -455,7 +455,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'value_parsed' => Amount::formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'local_icon' => 'calendar-o',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -493,14 +493,9 @@ class BasicController extends Controller
|
||||
'currency_code' => $currencies[$currencyId]->code,
|
||||
'currency_symbol' => $currencies[$currencyId]->symbol,
|
||||
'currency_decimal_places' => $currencies[$currencyId]->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
|
||||
'value_parsed' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$currencies[$currencyId]->symbol,
|
||||
$currencies[$currencyId]->decimal_places,
|
||||
$availableBudget,
|
||||
false
|
||||
),
|
||||
'sub_title' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
|
||||
];
|
||||
}
|
||||
foreach ($spent as $row) {
|
||||
@@ -529,18 +524,14 @@ class BasicController extends Controller
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $leftToSpend, false),
|
||||
'value_parsed' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $leftToSpend, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$row['currency_symbol'],
|
||||
$row['currency_decimal_places'],
|
||||
$perDay,
|
||||
false
|
||||
),
|
||||
'sub_title' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $perDay, false),
|
||||
];
|
||||
}
|
||||
unset($leftToSpend);
|
||||
if (0 === count($return)) {
|
||||
$days = (int) $start->diffInDays($end, true) + 1;
|
||||
// a small trick to get every expense in this period, regardless of budget.
|
||||
$spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection());
|
||||
foreach ($spent as $row) {
|
||||
@@ -563,14 +554,9 @@ class BasicController extends Controller
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $spentInCurrency, false),
|
||||
'value_parsed' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $spentInCurrency, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$row['currency_symbol'],
|
||||
$row['currency_decimal_places'],
|
||||
$perDay,
|
||||
false
|
||||
),
|
||||
'sub_title' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $perDay, false),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -587,9 +573,9 @@ class BasicController extends Controller
|
||||
// 'currency_code' => $currency->code,
|
||||
// 'currency_symbol' => $currency->symbol,
|
||||
// 'currency_decimal_places' => $currency->decimal_places,
|
||||
// 'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
// 'value_parsed' => Amount::formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
// 'local_icon' => 'money',
|
||||
// 'sub_title' => app('amount')->formatFlat(
|
||||
// 'sub_title' => Amount::formatFlat(
|
||||
// $currency->symbol,
|
||||
// $currency->decimal_places,
|
||||
// '0',
|
||||
@@ -642,7 +628,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $data['currency_code'],
|
||||
'currency_symbol' => $data['currency_symbol'],
|
||||
'currency_decimal_places' => $data['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($data['currency_symbol'], $data['currency_decimal_places'], $data['balance'], false),
|
||||
'value_parsed' => Amount::formatFlat($data['currency_symbol'], $data['currency_decimal_places'], $data['balance'], false),
|
||||
'local_icon' => 'line-chart',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -656,7 +642,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $this->primaryCurrency->code,
|
||||
'currency_symbol' => $this->primaryCurrency->symbol,
|
||||
'currency_decimal_places' => $this->primaryCurrency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($this->primaryCurrency->symbol, $this->primaryCurrency->decimal_places, '0', false),
|
||||
'value_parsed' => Amount::formatFlat($this->primaryCurrency->symbol, $this->primaryCurrency->decimal_places, '0', false),
|
||||
'local_icon' => 'line-chart',
|
||||
'sub_title' => '',
|
||||
];
|
||||
|
@@ -54,6 +54,7 @@ class CronController extends Controller
|
||||
$return['exchange_rates'] = $this->exchangeRatesCronJob($config['force'], $config['date']);
|
||||
}
|
||||
$return['bill_notifications'] = $this->billWarningCronJob($config['force'], $config['date']);
|
||||
$return['webhooks'] = $this->webhookCronJob($config['force'], $config['date']);
|
||||
|
||||
return response()->api($return);
|
||||
}
|
||||
|
@@ -25,7 +25,6 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Requests\Models\PiggyBank;
|
||||
|
||||
use Illuminate\Contracts\Validation\Validator;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Rules\IsValidZeroOrMoreAmount;
|
||||
@@ -96,7 +95,10 @@ class StoreRequest extends FormRequest
|
||||
function (Validator $validator): void {
|
||||
// validate start before end only if both are there.
|
||||
$data = $validator->getData();
|
||||
$currency = $this->getCurrencyFromData($data);
|
||||
$currency = $this->getCurrencyFromData($validator, $data);
|
||||
if (null === $currency) {
|
||||
return;
|
||||
}
|
||||
$targetAmount = (string) ($data['target_amount'] ?? '0');
|
||||
$currentAmount = '0';
|
||||
if (array_key_exists('accounts', $data) && is_array($data['accounts'])) {
|
||||
@@ -130,7 +132,7 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
}
|
||||
|
||||
private function getCurrencyFromData(array $data): TransactionCurrency
|
||||
private function getCurrencyFromData(Validator $validator, array $data): ?TransactionCurrency
|
||||
{
|
||||
if (array_key_exists('transaction_currency_code', $data) && '' !== (string) $data['transaction_currency_code']) {
|
||||
$currency = TransactionCurrency::whereCode($data['transaction_currency_code'])->first();
|
||||
@@ -144,7 +146,8 @@ class StoreRequest extends FormRequest
|
||||
return $currency;
|
||||
}
|
||||
}
|
||||
$validator->errors()->add('transaction_currency_id', trans('validation.require_currency_id_code'));
|
||||
|
||||
throw new FireflyException('Unexpected empty currency.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,7 @@ use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Repositories\UserGroup\UserGroupRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use Illuminate\Console\Command;
|
||||
@@ -72,6 +73,8 @@ class CorrectsPrimaryCurrencyAmounts extends Command
|
||||
/** @var UserGroupRepositoryInterface $repository */
|
||||
$repository = app(UserGroupRepositoryInterface::class);
|
||||
|
||||
Preferences::mark();
|
||||
|
||||
/** @var UserGroup $userGroup */
|
||||
foreach ($repository->getAll() as $userGroup) {
|
||||
$this->recalculateForGroup($userGroup);
|
||||
@@ -87,8 +90,7 @@ class CorrectsPrimaryCurrencyAmounts extends Command
|
||||
$this->recalculateAccounts($userGroup);
|
||||
|
||||
// do a check with the group's currency so we can skip some stuff.
|
||||
Preferences::mark();
|
||||
$currency = app('amount')->getPrimaryCurrencyByUserGroup($userGroup);
|
||||
$currency = Amount::getPrimaryCurrencyByUserGroup($userGroup);
|
||||
|
||||
$this->recalculatePiggyBanks($userGroup, $currency);
|
||||
$this->recalculateBudgets($userGroup, $currency);
|
||||
|
@@ -32,6 +32,7 @@ use FireflyIII\Support\Cronjobs\BillWarningCronjob;
|
||||
use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob;
|
||||
use FireflyIII\Support\Cronjobs\RecurringCronjob;
|
||||
use FireflyIII\Support\Cronjobs\UpdateCheckCronjob;
|
||||
use FireflyIII\Support\Cronjobs\WebhookCronjob;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use InvalidArgumentException;
|
||||
@@ -50,6 +51,7 @@ class Cron extends Command
|
||||
{--create-recurring : Create recurring transactions. Other tasks will be skipped unless also requested.}
|
||||
{--create-auto-budgets : Create auto budgets. Other tasks will be skipped unless also requested.}
|
||||
{--send-bill-warnings : Send bill warnings. Other tasks will be skipped unless also requested.}
|
||||
{--send-webhook-messages : Sends any stray webhook messages (with a maximum of 5).}
|
||||
';
|
||||
|
||||
public function handle(): int
|
||||
@@ -58,7 +60,8 @@ class Cron extends Command
|
||||
&& !$this->option('create-recurring')
|
||||
&& !$this->option('create-auto-budgets')
|
||||
&& !$this->option('send-bill-warnings')
|
||||
&& !$this->option('check-version');
|
||||
&& !$this->option('check-version')
|
||||
&& !$this->option('send-webhook-messages');
|
||||
$date = null;
|
||||
|
||||
try {
|
||||
@@ -122,6 +125,16 @@ class Cron extends Command
|
||||
$this->friendlyError($e->getMessage());
|
||||
}
|
||||
}
|
||||
// Fire webhook messages cron job.
|
||||
if ($doAll || $this->option('send-webhook-messages')) {
|
||||
try {
|
||||
$this->webhookCronJob($force, $date);
|
||||
} catch (FireflyException $e) {
|
||||
app('log')->error($e->getMessage());
|
||||
app('log')->error($e->getTraceAsString());
|
||||
$this->friendlyError($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
$this->friendlyInfo('More feedback on the cron jobs can be found in the log files.');
|
||||
|
||||
@@ -239,4 +252,26 @@ class Cron extends Command
|
||||
$this->friendlyPositive(sprintf('"Send bill warnings" cron ran with success: %s', $autoBudget->message));
|
||||
}
|
||||
}
|
||||
|
||||
private function webhookCronJob(bool $force, ?Carbon $date): void
|
||||
{
|
||||
$webhook = new WebhookCronjob();
|
||||
$webhook->setForce($force);
|
||||
// set date in cron job:
|
||||
if ($date instanceof Carbon) {
|
||||
$webhook->setDate($date);
|
||||
}
|
||||
|
||||
$webhook->fire();
|
||||
|
||||
if ($webhook->jobErrored) {
|
||||
$this->friendlyError(sprintf('Error in "webhook" cron: %s', $webhook->message));
|
||||
}
|
||||
if ($webhook->jobFired) {
|
||||
$this->friendlyInfo(sprintf('"Webhook" cron fired: %s', $webhook->message));
|
||||
}
|
||||
if ($webhook->jobSucceeded) {
|
||||
$this->friendlyPositive(sprintf('"Webhook" cron ran with success: %s', $webhook->message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
20
app/Events/Model/Bill/WarnUserAboutBill.php
Normal file
20
app/Events/Model/Bill/WarnUserAboutBill.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events\Model\Bill;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\Models\Bill;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class WarnUserAboutBill.
|
||||
*/
|
||||
class WarnUserAboutBill extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(public Bill $bill, public string $field, public int $diff) {}
|
||||
}
|
17
app/Events/Model/Bill/WarnUserAboutOverdueSubscriptions.php
Normal file
17
app/Events/Model/Bill/WarnUserAboutOverdueSubscriptions.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Events\Model\Bill;
|
||||
|
||||
use FireflyIII\Events\Event;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class WarnUserAboutOverdueSubscriptions extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(public User $user, public array $overdue) {}
|
||||
|
||||
}
|
@@ -35,6 +35,6 @@ class UserGroupChangedPrimaryCurrency extends Event
|
||||
|
||||
public function __construct(public UserGroup $userGroup)
|
||||
{
|
||||
Log::debug('User group changed default currency.');
|
||||
Log::debug('User group changed primary currency.');
|
||||
}
|
||||
}
|
||||
|
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DestroyedTransactionGroup.php
|
||||
* Copyright (c) 2019 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\Events;
|
||||
|
||||
use FireflyIII\Models\Bill;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
/**
|
||||
* Class WarnUserAboutBill.
|
||||
*/
|
||||
class WarnUserAboutBill extends Event
|
||||
{
|
||||
use SerializesModels;
|
||||
|
||||
public function __construct(public Bill $bill, public string $field, public int $diff) {}
|
||||
}
|
@@ -32,7 +32,6 @@ use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\Webhook;
|
||||
use FireflyIII\Models\WebhookMessage;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
@@ -176,8 +175,8 @@ class StandardMessageGenerator implements MessageGeneratorInterface
|
||||
/** @var TransactionGroup $model */
|
||||
$accounts = $this->collectAccounts($model);
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setDate(null);
|
||||
$enrichment->setUser($model->user);
|
||||
$enrichment->setPrimaryCurrency(Amount::getPrimaryCurrencyByUserGroup($model->userGroup));
|
||||
$accounts = $enrichment->enrich($accounts);
|
||||
foreach ($accounts as $account) {
|
||||
$transformer = new AccountTransformer();
|
||||
|
@@ -24,48 +24,118 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\WarnUserAboutBill;
|
||||
use FireflyIII\Notifications\User\BillReminder;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Exception;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Notifications\User\BillReminder;
|
||||
use FireflyIII\Notifications\User\SubscriptionsOverdueReminder;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
|
||||
/**
|
||||
* Class BillEventHandler
|
||||
*/
|
||||
class BillEventHandler
|
||||
{
|
||||
public function warnAboutOverdueSubscriptions(WarnUserAboutOverdueSubscriptions $event): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
// make sure user does not get the warning twice.
|
||||
$overdue = $event->overdue;
|
||||
$user = $event->user;
|
||||
$toBeWarned = [];
|
||||
Log::debug(sprintf('%d bills to warn about.', count($overdue)));
|
||||
foreach ($overdue as $item) {
|
||||
/** @var Bill $bill */
|
||||
$bill = $item['bill'];
|
||||
$key = sprintf('bill_overdue_%s_%s', $bill->id, substr(hash('sha256', json_encode($item['dates']['pay_dates'], JSON_THROW_ON_ERROR)), 0, 10));
|
||||
$pref = Preferences::getForUser($bill->user, $key, false);
|
||||
if (true === $pref->data) {
|
||||
Log::debug(sprintf('User #%d has already been warned about overdue subscription #%d.', $bill->user->id, $bill->id));
|
||||
|
||||
continue;
|
||||
}
|
||||
$toBeWarned[] = $item;
|
||||
}
|
||||
unset($bill);
|
||||
Log::debug(sprintf('Now %d bills to warn about.', count($toBeWarned)));
|
||||
|
||||
/** @var bool $sendNotification */
|
||||
$sendNotification = Preferences::getForUser($user, 'notification_bill_reminder', true)->data;
|
||||
if (false === $sendNotification) {
|
||||
Log::debug('User has disabled bill reminders.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Will warn about %d overdue subscription(s).', count($toBeWarned)));
|
||||
if (0 === count($toBeWarned)) {
|
||||
Log::debug('No overdue subscriptions to warn about.');
|
||||
|
||||
return;
|
||||
}
|
||||
foreach ($toBeWarned as $item) {
|
||||
/** @var Bill $bill */
|
||||
$bill = $item['bill'];
|
||||
$key = sprintf('bill_overdue_%s_%s', $bill->id, substr(hash('sha256', json_encode($item['dates']['pay_dates'], JSON_THROW_ON_ERROR)), 0, 10));
|
||||
Preferences::setForUser($bill->user, $key, true);
|
||||
}
|
||||
Log::warning('should hit this ONCE');
|
||||
|
||||
try {
|
||||
Notification::send($user, new SubscriptionsOverdueReminder($toBeWarned));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function warnAboutBill(WarnUserAboutBill $event): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
$bill = $event->bill;
|
||||
$bill = $event->bill;
|
||||
|
||||
/** @var bool $preference */
|
||||
$preference = app('preferences')->getForUser($bill->user, 'notification_bill_reminder', true)->data;
|
||||
Preferences::getForUser($bill->user, 'notification_bill_reminder', true)->data;
|
||||
|
||||
if (true === $preference) {
|
||||
app('log')->debug('Bill reminder is true!');
|
||||
Log::debug('Bill reminder is true!');
|
||||
|
||||
try {
|
||||
Notification::send($bill->user, new BillReminder($bill, $event->field, $event->diff));
|
||||
} catch (Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
if (str_contains($message, 'Bcc')) {
|
||||
app('log')->warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
Log::warning('[Bcc] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
if (str_contains($message, 'RFC 2822')) {
|
||||
app('log')->warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
Log::warning('[RFC] Could not send notification. Please validate your email settings, use the .env.example file as a guide.');
|
||||
|
||||
return;
|
||||
}
|
||||
app('log')->error($e->getMessage());
|
||||
app('log')->error($e->getTraceAsString());
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (false === $preference) {
|
||||
app('log')->debug('User has disabled bill reminders.');
|
||||
}
|
||||
Log::debug('User has disabled bill reminders.');
|
||||
}
|
||||
}
|
||||
|
@@ -73,6 +73,7 @@ class PreferencesEventHandler
|
||||
$repository = app(PiggyBankRepositoryInterface::class);
|
||||
$repository->setUserGroup($userGroup);
|
||||
$piggyBanks = $repository->getPiggyBanks();
|
||||
Log::debug(sprintf('Resetting %d piggy bank(s).', $piggyBanks->count()));
|
||||
|
||||
/** @var PiggyBank $piggyBank */
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
@@ -104,6 +105,8 @@ class PreferencesEventHandler
|
||||
$repository->setUserGroup($userGroup);
|
||||
$set = $repository->getBudgets();
|
||||
|
||||
Log::debug(sprintf('Resetting %d budget(s).', $set->count()));
|
||||
|
||||
/** @var Budget $budget */
|
||||
foreach ($set as $budget) {
|
||||
foreach ($budget->autoBudgets as $autoBudget) {
|
||||
|
@@ -77,8 +77,8 @@ class NetWorth implements NetWorthInterface
|
||||
Log::debug(sprintf('Now in byAccounts("%s", "%s")', $ids, $date->format('Y-m-d H:i:s')));
|
||||
$primary = Amount::getPrimaryCurrency();
|
||||
$netWorth = [];
|
||||
Log::debug(sprintf('NetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
|
||||
$balances = Steam::finalAccountsBalance($accounts, $date);
|
||||
Log::debug(sprintf('NetWorth: accountsBalancesOptimized("%s")', $date->format('Y-m-d H:i:s')));
|
||||
$balances = Steam::accountsBalancesOptimized($accounts, $date, null, $convertToPrimary);
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
@@ -143,8 +143,8 @@ class NetWorth implements NetWorthInterface
|
||||
*/
|
||||
$accounts = $this->getAccounts();
|
||||
$return = [];
|
||||
Log::debug(sprintf('SumNetWorth: finalAccountsBalance("%s")', $date->format('Y-m-d H:i:s')));
|
||||
$balances = Steam::finalAccountsBalance($accounts, $date);
|
||||
Log::debug(sprintf('SumNetWorth: accountsBalancesOptimized("%s")', $date->format('Y-m-d H:i:s')));
|
||||
$balances = Steam::accountsBalancesOptimized($accounts, $date);
|
||||
foreach ($accounts as $account) {
|
||||
$currency = $this->accountRepository->getAccountCurrency($account);
|
||||
$balance = $balances[$account->id]['balance'] ?? '0';
|
||||
|
@@ -93,10 +93,10 @@ class IndexController extends Controller
|
||||
$start->subSecond();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
Log::debug(sprintf('inactive start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('inactive end: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||
Log::debug(sprintf('inactive start: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('inactive end: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$activities = Steam::getLastActivities($ids);
|
||||
|
||||
|
||||
@@ -170,10 +170,10 @@ class IndexController extends Controller
|
||||
$start->subSecond();
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
Log::debug(sprintf('index start: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('index end: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||
Log::debug(sprintf('index start: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('index end: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$activities = Steam::getLastActivities($ids);
|
||||
|
||||
|
||||
|
@@ -40,6 +40,7 @@ use Illuminate\Routing\Redirector;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
@@ -81,7 +82,9 @@ class ShowController extends Controller
|
||||
* */
|
||||
public function show(Request $request, Account $account, ?Carbon $start = null, ?Carbon $end = null)
|
||||
{
|
||||
|
||||
if (0 === $account->id) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
|
||||
|
||||
if (!$this->isEditableAccount($account)) {
|
||||
@@ -115,20 +118,27 @@ class ShowController extends Controller
|
||||
$chartUrl = route('chart.account.period', [$account->id, $start->format('Y-m-d'), $end->format('Y-m-d')]);
|
||||
$firstTransaction = $this->repository->oldestJournalDate($account) ?? $start;
|
||||
|
||||
Log::debug('Start period overview');
|
||||
Timer::start('period-overview');
|
||||
// go back max 3 years.
|
||||
$threeYearsAgo = clone $start;
|
||||
$threeYearsAgo->startOfYear()->subYears(3);
|
||||
if ($firstTransaction->lt($threeYearsAgo)) {
|
||||
$firstTransaction = clone $threeYearsAgo;
|
||||
}
|
||||
|
||||
Log::debug('Start period overview');
|
||||
$timer = Timer::getInstance();
|
||||
$timer->start('period-overview');
|
||||
$periods = $this->getAccountPeriodOverview($account, $firstTransaction, $end);
|
||||
|
||||
Log::debug('End period overview');
|
||||
Timer::stop('period-overview');
|
||||
$timer->stop('period-overview');
|
||||
|
||||
// if layout = v2, overrule the page title.
|
||||
if ('v1' !== config('view.layout')) {
|
||||
$subTitle = (string) trans('firefly.all_journals_for_account', ['name' => $account->name]);
|
||||
}
|
||||
Log::debug('Collect transactions');
|
||||
Timer::start('collection');
|
||||
$timer->start('collection');
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
@@ -136,6 +146,7 @@ class ShowController extends Controller
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setLimit($pageSize)
|
||||
->setPage($page)
|
||||
->withAttachmentInformation()
|
||||
->withAPIInformation()
|
||||
->setRange($start, $end)
|
||||
;
|
||||
@@ -146,7 +157,7 @@ class ShowController extends Controller
|
||||
|
||||
|
||||
Log::debug('End collect transactions');
|
||||
Timer::stop('collection');
|
||||
$timer->stop('collection');
|
||||
|
||||
// enrich data in arrays.
|
||||
|
||||
|
@@ -57,7 +57,7 @@ class IndexController extends Controller
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('title', (string)trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
@@ -79,7 +79,6 @@ class IndexController extends Controller
|
||||
$total = $collection->count();
|
||||
|
||||
|
||||
|
||||
$parameters = new ParameterBag();
|
||||
// sub one day from temp start so the last paid date is one day before it should be.
|
||||
$tempStart = clone $start;
|
||||
@@ -91,8 +90,6 @@ class IndexController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($tempStart);
|
||||
$enrichment->setEnd($end);
|
||||
$collection = $enrichment->enrich($collection);
|
||||
@@ -114,7 +111,7 @@ class IndexController extends Controller
|
||||
$bills = [
|
||||
0 => [ // the index is the order, not the ID.
|
||||
'object_group_id' => 0,
|
||||
'object_group_title' => (string) trans('firefly.default_group_title_name'),
|
||||
'object_group_title' => (string)trans('firefly.default_group_title_name'),
|
||||
'bills' => [],
|
||||
],
|
||||
];
|
||||
@@ -122,7 +119,7 @@ class IndexController extends Controller
|
||||
/** @var Bill $bill */
|
||||
foreach ($collection as $bill) {
|
||||
$array = $transformer->transform($bill);
|
||||
$groupOrder = (int) $array['object_group_order'];
|
||||
$groupOrder = (int)$array['object_group_order'];
|
||||
// make group array if necessary:
|
||||
$bills[$groupOrder] ??= [
|
||||
'object_group_id' => $array['object_group_id'],
|
||||
@@ -175,16 +172,28 @@ class IndexController extends Controller
|
||||
'currency_symbol' => $bill['currency_symbol'],
|
||||
'currency_decimal_places' => $bill['currency_decimal_places'],
|
||||
'avg' => '0',
|
||||
'total_left_to_pay' => '0',
|
||||
'period' => $range,
|
||||
'per_period' => '0',
|
||||
];
|
||||
|
||||
// only fill in avg when bill is active.
|
||||
if (null !== $bill['next_expected_match']) {
|
||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
||||
$avg = bcmul($avg, (string) count($bill['pay_dates']));
|
||||
$avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2');
|
||||
$avg = bcmul($avg, (string)count($bill['pay_dates']));
|
||||
$sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg);
|
||||
}
|
||||
// only fill in total_left_to_pay when bill is not yet paid.
|
||||
if (count($bill['paid_dates']) < count($bill['pay_dates'])) {
|
||||
$count = count($bill['pay_dates']) - count($bill['paid_dates']);
|
||||
if ($count > 0) {
|
||||
$avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2');
|
||||
$avg = bcmul($avg, (string)$count);
|
||||
$sums[$groupOrder][$currencyId]['total_left_to_pay'] = bcadd($sums[$groupOrder][$currencyId]['total_left_to_pay'], $avg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// fill in per period regardless:
|
||||
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
|
||||
}
|
||||
@@ -195,7 +204,7 @@ class IndexController extends Controller
|
||||
|
||||
private function amountPerPeriod(array $bill, string $range): string
|
||||
{
|
||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
||||
$avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2');
|
||||
|
||||
app('log')->debug(sprintf('Amount per period for bill #%d "%s"', $bill['id'], $bill['name']));
|
||||
app('log')->debug(sprintf('Average is %s', $avg));
|
||||
@@ -208,8 +217,8 @@ class IndexController extends Controller
|
||||
'weekly' => '52.17',
|
||||
'daily' => '365.24',
|
||||
];
|
||||
$yearAmount = bcmul($avg, bcdiv($multiplies[$bill['repeat_freq']], (string) ($bill['skip'] + 1)));
|
||||
app('log')->debug(sprintf('Amount per year is %s (%s * %s / %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']], (string) ($bill['skip'] + 1)));
|
||||
$yearAmount = bcmul($avg, bcdiv($multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1)));
|
||||
app('log')->debug(sprintf('Amount per year is %s (%s * %s / %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']], (string)($bill['skip'] + 1)));
|
||||
|
||||
// per period:
|
||||
$division = [
|
||||
@@ -260,8 +269,8 @@ class IndexController extends Controller
|
||||
'period' => $entry['period'],
|
||||
'per_period' => '0',
|
||||
];
|
||||
$totals[$currencyId]['avg'] = bcadd($totals[$currencyId]['avg'], (string) $entry['avg']);
|
||||
$totals[$currencyId]['per_period'] = bcadd($totals[$currencyId]['per_period'], (string) $entry['per_period']);
|
||||
$totals[$currencyId]['avg'] = bcadd($totals[$currencyId]['avg'], (string)$entry['avg']);
|
||||
$totals[$currencyId]['per_period'] = bcadd($totals[$currencyId]['per_period'], (string)$entry['per_period']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,8 +282,8 @@ class IndexController extends Controller
|
||||
*/
|
||||
public function setOrder(Request $request, Bill $bill): JsonResponse
|
||||
{
|
||||
$objectGroupTitle = (string) $request->get('objectGroupTitle');
|
||||
$newOrder = (int) $request->get('order');
|
||||
$objectGroupTitle = (string)$request->get('objectGroupTitle');
|
||||
$newOrder = (int)$request->get('order');
|
||||
$this->repository->setOrder($bill, $newOrder);
|
||||
if ('' !== $objectGroupTitle) {
|
||||
$this->repository->setObjectGroup($bill, $objectGroupTitle);
|
||||
|
@@ -149,10 +149,10 @@ class ShowController extends Controller
|
||||
$admin = auth()->user();
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setConvertToPrimary($this->convertToPrimary);
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
|
||||
/** @var Bill $bill */
|
||||
$bill = $enrichment->enrichSingle($bill);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
|
@@ -95,6 +95,7 @@ class EditController extends Controller
|
||||
$preFilled = [
|
||||
'active' => $hasOldInput ? (bool) $request->old('active') : $budget->active,
|
||||
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $this->primaryCurrency->id,
|
||||
'notes' => $this->repository->getNoteText($budget),
|
||||
];
|
||||
if ($autoBudget instanceof AutoBudget) {
|
||||
$amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount;
|
||||
|
@@ -35,6 +35,7 @@ use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use FireflyIII\Support\Http\Controllers\AugumentData;
|
||||
use FireflyIII\Support\Http\Controllers\ChartGeneration;
|
||||
@@ -78,6 +79,7 @@ class AccountController extends Controller
|
||||
|
||||
/**
|
||||
* Shows the balances for all the user's expense accounts (on the front page).
|
||||
* 2025-08-06 validated for multi (primary) currency
|
||||
*
|
||||
* This chart is (multi) currency aware.
|
||||
*/
|
||||
@@ -112,11 +114,11 @@ class AccountController extends Controller
|
||||
$accountNames = $this->extractNames($accounts);
|
||||
|
||||
// grab all balances
|
||||
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('expenseAccounts: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||
|
||||
Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('expenseAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
|
||||
Log::debug('Done collecting balances');
|
||||
// loop the accounts, then check for balance and currency info.
|
||||
foreach ($accounts as $account) {
|
||||
// Log::debug(sprintf('[a] Now in account #%d ("%s")', $account->id, $account->name));
|
||||
@@ -157,7 +159,7 @@ class AccountController extends Controller
|
||||
$tempData[] = [
|
||||
'name' => $accountNames[$account->id],
|
||||
'difference' => $diff,
|
||||
'diff_float' => (float) $diff, // intentional float
|
||||
'diff_float' => (float)$diff, // intentional float
|
||||
'currency_id' => $currencies[$searchCode]->id,
|
||||
];
|
||||
}
|
||||
@@ -182,7 +184,7 @@ class AccountController extends Controller
|
||||
foreach ($currencies as $currencyId => $currency) {
|
||||
$dataSet
|
||||
= [
|
||||
'label' => (string) trans('firefly.spent'),
|
||||
'label' => (string)trans('firefly.spent'),
|
||||
'type' => 'bar',
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_code' => $currency->code,
|
||||
@@ -195,7 +197,7 @@ class AccountController extends Controller
|
||||
foreach ($tempData as $entry) {
|
||||
$currencyId = $entry['currency_id'];
|
||||
$name = $entry['name'];
|
||||
$chartData[$currencyId]['entries'][$name] = (float) $entry['difference'];
|
||||
$chartData[$currencyId]['entries'][$name] = (float)$entry['difference'];
|
||||
}
|
||||
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
@@ -223,6 +225,7 @@ class AccountController extends Controller
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($this->convertToPrimary);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.account.expense-budget');
|
||||
if ($cache->has()) {
|
||||
@@ -231,7 +234,10 @@ class AccountController extends Controller
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setAccounts(new Collection([$account]))->setRange($start, $end)->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
$collector->setAccounts(new Collection([$account]))
|
||||
->setRange($start, $end)
|
||||
->withBudgetInformation()->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
|
||||
;
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$chartData = [];
|
||||
$result = [];
|
||||
@@ -239,19 +245,37 @@ class AccountController extends Controller
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$budgetId = (int) $journal['budget_id'];
|
||||
$budgetId = (int)$journal['budget_id'];
|
||||
$key = sprintf('%d-%d', $budgetId, $journal['currency_id']);
|
||||
$budgetIds[] = $budgetId;
|
||||
|
||||
// currency info:
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currencyName = $journal['currency_name'];
|
||||
$currencySymbol = $journal['currency_symbol'];
|
||||
$currencyCode = $journal['currency_code'];
|
||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||
$field = 'amount';
|
||||
if ($this->convertToPrimary && $this->primaryCurrency->id !== $currencyId) {
|
||||
$field = 'pc_amount';
|
||||
$currencyName = $this->primaryCurrency->name;
|
||||
$currencySymbol = $this->primaryCurrency->symbol;
|
||||
$currencyCode = $this->primaryCurrency->code;
|
||||
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
|
||||
|
||||
}
|
||||
|
||||
if (!array_key_exists($key, $result)) {
|
||||
$result[$key] = [
|
||||
'total' => '0',
|
||||
'budget_id' => $budgetId,
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
'total' => '0',
|
||||
'budget_id' => $budgetId,
|
||||
'currency_name' => $currencyName,
|
||||
'currency_symbol' => $currencySymbol,
|
||||
'currency_code' => $currencyCode,
|
||||
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||
];
|
||||
}
|
||||
$result[$key]['total'] = bcadd((string) $journal['amount'], $result[$key]['total']);
|
||||
$result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
|
||||
}
|
||||
|
||||
$names = $this->getBudgetNames($budgetIds);
|
||||
@@ -259,7 +283,7 @@ class AccountController extends Controller
|
||||
foreach ($result as $row) {
|
||||
$budgetId = $row['budget_id'];
|
||||
$name = $names[$budgetId];
|
||||
$label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
|
||||
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
|
||||
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
|
||||
}
|
||||
|
||||
@@ -289,6 +313,7 @@ class AccountController extends Controller
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty($this->convertToPrimary);
|
||||
$cache->addProperty('chart.account.expense-category');
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get());
|
||||
@@ -305,22 +330,39 @@ class AccountController extends Controller
|
||||
foreach ($journals as $journal) {
|
||||
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
|
||||
if (!array_key_exists($key, $result)) {
|
||||
$result[$key] = [
|
||||
'total' => '0',
|
||||
'category_id' => (int) $journal['category_id'],
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
|
||||
// currency info:
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currencyName = $journal['currency_name'];
|
||||
$currencySymbol = $journal['currency_symbol'];
|
||||
$currencyCode = $journal['currency_code'];
|
||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||
$field = 'amount';
|
||||
if ($this->convertToPrimary && $this->primaryCurrency->id !== $currencyId) {
|
||||
$field = 'pc_amount';
|
||||
$currencyName = $this->primaryCurrency->name;
|
||||
$currencySymbol = $this->primaryCurrency->symbol;
|
||||
$currencyCode = $this->primaryCurrency->code;
|
||||
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
|
||||
}
|
||||
|
||||
$result[$key] = [
|
||||
'total' => '0',
|
||||
'category_id' => (int)$journal['category_id'],
|
||||
'currency_name' => $currencyName,
|
||||
'currency_code' => $currencyCode,
|
||||
'currency_symbol' => $currencySymbol,
|
||||
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||
];
|
||||
}
|
||||
$result[$key]['total'] = bcadd((string) $journal['amount'], $result[$key]['total']);
|
||||
$result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
|
||||
}
|
||||
$names = $this->getCategoryNames(array_keys($result));
|
||||
|
||||
foreach ($result as $row) {
|
||||
$categoryId = $row['category_id'];
|
||||
$name = $names[$categoryId] ?? '(unknown)';
|
||||
$label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
|
||||
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
|
||||
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
|
||||
}
|
||||
|
||||
@@ -341,11 +383,11 @@ class AccountController extends Controller
|
||||
$end = clone session('end', today(config('app.timezone'))->endOfMonth());
|
||||
$defaultSet = $repository->getAccountsByType([AccountTypeEnum::DEFAULT->value, AccountTypeEnum::ASSET->value])->pluck('id')->toArray();
|
||||
// Log::debug('Default set is ', $defaultSet);
|
||||
$frontpage = app('preferences')->get('frontpageAccounts', $defaultSet);
|
||||
$frontpage = Preferences::get('frontpageAccounts', $defaultSet);
|
||||
$frontpageArray = !is_array($frontpage->data) ? [] : $frontpage->data;
|
||||
Log::debug('Frontpage preference set is ', $frontpageArray);
|
||||
if (0 === count($frontpageArray)) {
|
||||
app('preferences')->set('frontpageAccounts', $defaultSet);
|
||||
Preferences::set('frontpageAccounts', $defaultSet);
|
||||
Log::debug('frontpage set is empty!');
|
||||
}
|
||||
$accounts = $repository->getAccountsById($frontpageArray);
|
||||
@@ -375,6 +417,7 @@ class AccountController extends Controller
|
||||
$cache = new CacheProperties();
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($this->convertToPrimary);
|
||||
$cache->addProperty($end);
|
||||
$cache->addProperty('chart.account.income-category');
|
||||
if ($cache->has()) {
|
||||
@@ -394,22 +437,39 @@ class AccountController extends Controller
|
||||
foreach ($journals as $journal) {
|
||||
$key = sprintf('%d-%d', $journal['category_id'], $journal['currency_id']);
|
||||
if (!array_key_exists($key, $result)) {
|
||||
$result[$key] = [
|
||||
'total' => '0',
|
||||
'category_id' => $journal['category_id'],
|
||||
'currency_name' => $journal['currency_name'],
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
'currency_code' => $journal['currency_code'],
|
||||
|
||||
// currency info:
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currencyName = $journal['currency_name'];
|
||||
$currencySymbol = $journal['currency_symbol'];
|
||||
$currencyCode = $journal['currency_code'];
|
||||
$currencyDecimalPlaces = $journal['currency_decimal_places'];
|
||||
$field = 'amount';
|
||||
if ($this->convertToPrimary && $this->primaryCurrency->id !== $currencyId) {
|
||||
$field = 'pc_amount';
|
||||
$currencyName = $this->primaryCurrency->name;
|
||||
$currencySymbol = $this->primaryCurrency->symbol;
|
||||
$currencyCode = $this->primaryCurrency->code;
|
||||
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
|
||||
}
|
||||
|
||||
$result[$key] = [
|
||||
'total' => '0',
|
||||
'category_id' => $journal['category_id'],
|
||||
'currency_name' => $currencyName,
|
||||
'currency_code' => $currencyCode,
|
||||
'currency_symbol' => $currencySymbol,
|
||||
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||
];
|
||||
}
|
||||
$result[$key]['total'] = bcadd((string) $journal['amount'], $result[$key]['total']);
|
||||
$result[$key]['total'] = bcadd((string)$journal[$field], $result[$key]['total']);
|
||||
}
|
||||
|
||||
$names = $this->getCategoryNames(array_keys($result));
|
||||
foreach ($result as $row) {
|
||||
$categoryId = $row['category_id'];
|
||||
$name = $names[$categoryId] ?? '(unknown)';
|
||||
$label = (string) trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
|
||||
$label = (string)trans('firefly.name_in_currency', ['name' => $name, 'currency' => $row['currency_name']]);
|
||||
$chartData[$label] = ['amount' => $row['total'], 'currency_symbol' => $row['currency_symbol'], 'currency_code' => $row['currency_code']];
|
||||
}
|
||||
$data = $this->generator->multiCurrencyPieChart($chartData);
|
||||
@@ -450,7 +510,7 @@ class AccountController extends Controller
|
||||
// This period depends on the size of the chart
|
||||
$current = clone $start;
|
||||
$current = app('navigation')->endOfX($current, $step, null);
|
||||
$format = (string) trans('config.month_and_day_js', [], $locale);
|
||||
$format = (string)trans('config.month_and_day_js', [], $locale);
|
||||
$accountCurrency = $this->accountRepository->getAccountCurrency($account);
|
||||
|
||||
$range = Steam::finalAccountBalanceInRange($account, $start, $end, $this->convertToPrimary);
|
||||
@@ -512,7 +572,7 @@ class AccountController extends Controller
|
||||
foreach ($return as $key => $info) {
|
||||
if ('balance' !== $key && 'pc_balance' !== $key) {
|
||||
// assume it's a currency:
|
||||
$setCurrency = $this->currencyRepository->findByCode((string) $key);
|
||||
$setCurrency = $this->currencyRepository->findByCode((string)$key);
|
||||
$info['currency_symbol'] = $setCurrency->symbol;
|
||||
$info['currency_code'] = $setCurrency->code;
|
||||
$info['label'] = sprintf('%s (%s)', $account->name, $setCurrency->symbol);
|
||||
@@ -525,7 +585,7 @@ class AccountController extends Controller
|
||||
if ('pc_balance' === $key) {
|
||||
$info['currency_symbol'] = $this->primaryCurrency->symbol;
|
||||
$info['currency_code'] = $this->primaryCurrency->code;
|
||||
$info['label'] = sprintf('%s (%s) (%s)', $account->name, (string) trans('firefly.sum'), $this->primaryCurrency->symbol);
|
||||
$info['label'] = sprintf('%s (%s) (%s)', $account->name, (string)trans('firefly.sum'), $this->primaryCurrency->symbol);
|
||||
}
|
||||
$chartData[] = $info;
|
||||
}
|
||||
@@ -594,10 +654,10 @@ class AccountController extends Controller
|
||||
$accountNames = $this->extractNames($accounts);
|
||||
|
||||
// grab all balances
|
||||
Log::debug(sprintf('revAccounts: finalAccountsBalance("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('revAccounts: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::finalAccountsBalance($accounts, $start);
|
||||
$endBalances = Steam::finalAccountsBalance($accounts, $end);
|
||||
Log::debug(sprintf('revAccounts: accountsBalancesOptimized("%s")', $start->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('revAccounts: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startBalances = Steam::accountsBalancesOptimized($accounts, $start, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$endBalances = Steam::accountsBalancesOptimized($accounts, $end, $this->primaryCurrency, $this->convertToPrimary);
|
||||
|
||||
|
||||
// loop the accounts, then check for balance and currency info.
|
||||
@@ -640,7 +700,7 @@ class AccountController extends Controller
|
||||
$tempData[] = [
|
||||
'name' => $accountNames[$account->id],
|
||||
'difference' => $diff,
|
||||
'diff_float' => (float) $diff, // intentional float
|
||||
'diff_float' => (float)$diff, // intentional float
|
||||
'currency_id' => $currencies[$searchCode]->id,
|
||||
];
|
||||
}
|
||||
@@ -667,7 +727,7 @@ class AccountController extends Controller
|
||||
foreach ($currencies as $currencyId => $currency) {
|
||||
$dataSet
|
||||
= [
|
||||
'label' => (string) trans('firefly.earned'),
|
||||
'label' => (string)trans('firefly.earned'),
|
||||
'type' => 'bar',
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_code' => $currency->code,
|
||||
|
@@ -210,7 +210,6 @@ class CategoryReportController extends Controller
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection([$category]));
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection([$category]));
|
||||
$format = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
|
||||
|
||||
// loop expenses.
|
||||
foreach ($spent as $currency) {
|
||||
// add things to chart Data for each currency:
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
@@ -33,6 +34,7 @@ use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
use Illuminate\Support\Facades\Config;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\View;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@@ -141,6 +143,14 @@ abstract class Controller extends BaseController
|
||||
View::share('shownDemo', $shownDemo);
|
||||
View::share('current_route_name', $page);
|
||||
View::share('original_route_name', Route::currentRouteName());
|
||||
|
||||
// lottery to send any remaining webhooks:
|
||||
if (7 === random_int(1, 10)) {
|
||||
// trigger event to send them:
|
||||
Log::debug('send event RequestedSendWebhookMessages through lottery');
|
||||
event(new RequestedSendWebhookMessages());
|
||||
}
|
||||
|
||||
}
|
||||
View::share('darkMode', $darkMode);
|
||||
|
||||
|
@@ -157,6 +157,11 @@ class DebugController extends Controller
|
||||
return view('debug', compact('table', 'now', 'logContent'));
|
||||
}
|
||||
|
||||
public function apiTest()
|
||||
{
|
||||
return view('test.api-test');
|
||||
}
|
||||
|
||||
private function generateTable(): string
|
||||
{
|
||||
// system information:
|
||||
|
@@ -32,8 +32,10 @@ use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\ObjectGroup\OrganisesObjectGroups;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -114,6 +116,13 @@ class IndexController extends Controller
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
$piggyBanks = [];
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$collection = $enrichment->enrich($collection);
|
||||
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($collection as $piggy) {
|
||||
$array = $transformer->transform($piggy);
|
||||
@@ -148,7 +157,7 @@ class IndexController extends Controller
|
||||
// enrich each account.
|
||||
$enrichment = new AccountEnrichment();
|
||||
$enrichment->setUser(auth()->user());
|
||||
$enrichment->setPrimaryCurrency($this->primaryCurrency);
|
||||
$enrichment->setDate($end);
|
||||
$return = [];
|
||||
|
||||
/** @var PiggyBank $piggy */
|
||||
@@ -170,14 +179,6 @@ class IndexController extends Controller
|
||||
$return[$accountId]['target'] = '0';
|
||||
$return[$accountId]['to_save'] = '0';
|
||||
}
|
||||
|
||||
// calculate new interesting fields:
|
||||
// $return[$accountId]['left'] -= $array['current_amount'];
|
||||
// $return[$accountId]['saved'] += $array['current_amount'];
|
||||
// $return[$accountId]['target'] += $array['target_amount'];
|
||||
// $return[$accountId]['to_save'] += ($array['target_amount'] - $array['current_amount']);
|
||||
// $return['account_name'] = $account['name'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ class IndexController extends Controller
|
||||
// loop all accounts in this piggy bank subtract the current amount from "left to save" in the $accounts array.
|
||||
/** @var array $piggyAccount */
|
||||
foreach ($piggyBank['accounts'] as $piggyAccount) {
|
||||
$accountId = $piggyAccount['id'];
|
||||
$accountId = $piggyAccount['account_id'];
|
||||
if (array_key_exists($accountId, $accounts)) {
|
||||
$accounts[$accountId]['left'] = bcsub((string) $accounts[$accountId]['left'], (string) $piggyAccount['current_amount']);
|
||||
$accounts[$accountId]['saved'] = bcadd((string) $accounts[$accountId]['saved'], (string) $piggyAccount['current_amount']);
|
||||
|
@@ -29,7 +29,9 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
@@ -75,6 +77,13 @@ class ShowController extends Controller
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('end', $end);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($parameters);
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers;
|
||||
|
||||
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||
use JsonException;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\AccountTypeEnum;
|
||||
@@ -44,7 +45,6 @@ use Illuminate\View\View;
|
||||
|
||||
use function Safe\json_decode;
|
||||
use function Safe\file_get_contents;
|
||||
use function Safe\strtotime;
|
||||
|
||||
/**
|
||||
* Class PreferencesController.
|
||||
@@ -270,17 +270,19 @@ class PreferencesController extends Controller
|
||||
if ($convertToPrimary && !$this->convertToPrimary) {
|
||||
// set to true!
|
||||
Log::debug('User sets convertToPrimary to true.');
|
||||
Preferences::set('convert_to_primary', $convertToPrimary);
|
||||
Preferences::set('convert_to_primary', true);
|
||||
$singleton = PreferencesSingleton::getInstance();
|
||||
$singleton->resetPreferences();
|
||||
event(new UserGroupChangedPrimaryCurrency(auth()->user()->userGroup));
|
||||
}
|
||||
Preferences::set('convert_to_primary', $convertToPrimary);
|
||||
|
||||
// custom fiscal year
|
||||
$customFiscalYear = 1 === (int) $request->get('customFiscalYear');
|
||||
$string = strtotime((string) $request->get('fiscalYearStart'));
|
||||
if (false !== $string) {
|
||||
$fiscalYearStart = Carbon::createFromTimestamp($string)->format('m-d');
|
||||
Preferences::set('customFiscalYear', $customFiscalYear);
|
||||
Preferences::set('customFiscalYear', $customFiscalYear);
|
||||
$fiscalYearString = (string) $request->get('fiscalYearStart');
|
||||
if ('' !== $fiscalYearString) {
|
||||
$fiscalYearStart = Carbon::parse($fiscalYearString, config('app.timezone'))->format('m-d');
|
||||
Preferences::set('fiscalYearStart', $fiscalYearStart);
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,10 @@ use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\ExpandedForm;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -92,13 +95,20 @@ class EditController extends Controller
|
||||
throw new FireflyException('This recurring transaction has no meta-data. You will have to delete it and recreate it. Sorry!');
|
||||
}
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
|
||||
$array = $transformer->transform($recurrence);
|
||||
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
|
||||
$bills = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills());
|
||||
$budgets = ExpandedForm::makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
|
||||
$bills = ExpandedForm::makeSelectListWithEmpty($this->billRepository->getActiveBills());
|
||||
|
||||
/** @var RecurrenceRepetition $repetition */
|
||||
$repetition = $recurrence->recurrenceRepetitions()->first();
|
||||
|
@@ -29,7 +29,9 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
@@ -85,6 +87,13 @@ class IndexController extends Controller
|
||||
$total = $collection->count();
|
||||
$recurrences = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrences = $enrichment->enrich($recurrences);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
|
@@ -32,8 +32,10 @@ use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
@@ -80,6 +82,13 @@ class ShowController extends Controller
|
||||
{
|
||||
$repos = app(AttachmentRepositoryInterface::class);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Report;
|
||||
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use Throwable;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
@@ -290,11 +291,12 @@ class BudgetController extends Controller
|
||||
$cache->addProperty('budget-period-report');
|
||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
// return $cache->get();
|
||||
}
|
||||
|
||||
$periods = app('navigation')->listOfPeriods($start, $end);
|
||||
$keyFormat = app('navigation')->preferredCarbonFormat($start, $end);
|
||||
$periods = Navigation::listOfPeriods($start, $end);
|
||||
$keyFormat = Navigation::preferredCarbonFormat($start, $end);
|
||||
|
||||
// list expenses for budgets in account(s)
|
||||
$expenses = $this->opsRepository->listExpenses($start, $end, $accounts);
|
||||
|
||||
@@ -303,6 +305,17 @@ class BudgetController extends Controller
|
||||
foreach ($currency['budgets'] as $budget) {
|
||||
$count = 0;
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
// #10678
|
||||
// skip transactions between two asset / liability accounts.
|
||||
if (
|
||||
in_array($journal['source_account_type'], config('firefly.valid_currency_account_types'), true)
|
||||
&& in_array($journal['destination_account_type'], config('firefly.valid_currency_account_types'), true)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
++$count;
|
||||
$key = sprintf('%d-%d', $budget['id'], $currency['currency_id']);
|
||||
$dateKey = $journal['date']->format($keyFormat);
|
||||
|
@@ -188,16 +188,7 @@ class ReportController extends Controller
|
||||
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||
$end->endOfDay();
|
||||
|
||||
app('view')->share(
|
||||
'subTitle',
|
||||
trans(
|
||||
'firefly.report_default',
|
||||
[
|
||||
'start' => $start->isoFormat($this->monthAndDayFormat),
|
||||
'end' => $end->isoFormat($this->monthAndDayFormat),
|
||||
]
|
||||
)
|
||||
);
|
||||
app('view')->share('subTitle', trans('firefly.report_default', ['start' => $start->isoFormat($this->monthAndDayFormat), 'end' => $end->isoFormat($this->monthAndDayFormat)]));
|
||||
|
||||
$generator = ReportGeneratorFactory::reportGenerator('Standard', $start, $end);
|
||||
$generator->setAccounts($accounts);
|
||||
@@ -222,16 +213,7 @@ class ReportController extends Controller
|
||||
$start->endOfDay(); // end of day so the final balance is at the end of that day.
|
||||
$end->endOfDay();
|
||||
|
||||
app('view')->share(
|
||||
'subTitle',
|
||||
trans(
|
||||
'firefly.report_double',
|
||||
[
|
||||
'start' => $start->isoFormat($this->monthAndDayFormat),
|
||||
'end' => $end->isoFormat($this->monthAndDayFormat),
|
||||
]
|
||||
)
|
||||
);
|
||||
app('view')->share('subTitle', trans('firefly.report_double', ['start' => $start->isoFormat($this->monthAndDayFormat), 'end' => $end->isoFormat($this->monthAndDayFormat)]));
|
||||
|
||||
$generator = ReportGeneratorFactory::reportGenerator('Account', $start, $end);
|
||||
$generator->setAccounts($accounts);
|
||||
|
@@ -270,6 +270,7 @@ class CreateController extends Controller
|
||||
$data = $request->getRuleData();
|
||||
|
||||
$rule = $this->ruleRepos->store($data);
|
||||
session()->flash('success_url', route('rules.select-transactions', [$rule->id]));
|
||||
session()->flash('success', (string) trans('firefly.stored_new_rule', ['title' => $rule->title]));
|
||||
app('preferences')->mark();
|
||||
|
||||
|
@@ -252,6 +252,7 @@ class TagController extends Controller
|
||||
|
||||
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()
|
||||
->setTag($tag)->withBudgetInformation()->withCategoryInformation()
|
||||
->withAttachmentInformation()
|
||||
;
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath($path);
|
||||
@@ -283,6 +284,7 @@ class TagController extends Controller
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()
|
||||
->setTag($tag)->withBudgetInformation()->withCategoryInformation()
|
||||
->withAttachmentInformation()
|
||||
;
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath($path);
|
||||
|
@@ -25,16 +25,20 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Controllers\Transaction;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Repositories\AuditLogEntry\ALERepositoryInterface;
|
||||
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
@@ -57,7 +61,7 @@ class ShowController extends Controller
|
||||
$this->repository = app(TransactionGroupRepositoryInterface::class);
|
||||
$this->aleRepository = app(ALERepositoryInterface::class);
|
||||
|
||||
app('view')->share('title', (string) trans('firefly.transactions'));
|
||||
app('view')->share('title', (string)trans('firefly.transactions'));
|
||||
app('view')->share('mainTitleIcon', 'fa-exchange');
|
||||
|
||||
return $next($request);
|
||||
@@ -80,38 +84,62 @@ class ShowController extends Controller
|
||||
*/
|
||||
public function show(TransactionGroup $transactionGroup)
|
||||
{
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
|
||||
// use new group collector:
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($admin)->setTransactionGroup($transactionGroup)->withAPIInformation();
|
||||
|
||||
$selectedGroup = $collector->getGroups()->first();
|
||||
if (null === $selectedGroup) {
|
||||
throw new NotFoundHttpException();
|
||||
}
|
||||
|
||||
// enrich
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
|
||||
|
||||
|
||||
/** @var null|TransactionJournal $first */
|
||||
$first = $transactionGroup->transactionJournals()->first(['transaction_journals.*']);
|
||||
$splits = $transactionGroup->transactionJournals()->count();
|
||||
$splits = count($selectedGroup['transactions']);
|
||||
$keys = array_keys($selectedGroup['transactions']);
|
||||
$first = $selectedGroup['transactions'][array_shift($keys)];
|
||||
unset($keys);
|
||||
|
||||
if (null === $first) {
|
||||
throw new FireflyException('This transaction is broken :(.');
|
||||
}
|
||||
|
||||
$type = (string) trans(sprintf('firefly.%s', $first->transactionType->type));
|
||||
$title = 1 === $splits ? $first->description : $transactionGroup->title;
|
||||
$type = (string)trans(sprintf('firefly.%s', $first['transaction_type_type']));
|
||||
$title = 1 === $splits ? $first['description'] : $selectedGroup['title'];
|
||||
$subTitle = sprintf('%s: "%s"', $type, $title);
|
||||
|
||||
// enrich
|
||||
$enrichment = new TransactionGroupEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$selectedGroup = $enrichment->enrichSingle($selectedGroup);
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
$groupArray = $transformer->transformObject($transactionGroup);
|
||||
|
||||
// do some calculations:
|
||||
$amounts = $this->getAmounts($groupArray);
|
||||
$accounts = $this->getAccounts($groupArray);
|
||||
$amounts = $this->getAmounts($selectedGroup);
|
||||
$accounts = $this->getAccounts($selectedGroup);
|
||||
|
||||
foreach (array_keys($groupArray['transactions']) as $index) {
|
||||
$groupArray['transactions'][$index]['tags'] = $this->repository->getTagObjects(
|
||||
(int) $groupArray['transactions'][$index]['transaction_journal_id']
|
||||
);
|
||||
foreach (array_keys($selectedGroup['transactions']) as $index) {
|
||||
$selectedGroup['transactions'][$index]['tags'] = $this->repository->getTagObjects((int)$selectedGroup['transactions'][$index]['transaction_journal_id']);
|
||||
}
|
||||
|
||||
// get audit log entries:
|
||||
$groupLogEntries = $this->aleRepository->getForObject($transactionGroup);
|
||||
$logEntries = [];
|
||||
foreach ($transactionGroup->transactionJournals as $journal) {
|
||||
$logEntries[$journal->id] = $this->aleRepository->getForObject($journal);
|
||||
foreach ($selectedGroup['transactions'] as $journal) {
|
||||
$logEntries[$journal['transaction_journal_id']] = $this->aleRepository->getForId(TransactionJournal::class, $journal['transaction_journal_id']);
|
||||
}
|
||||
|
||||
$events = $this->repository->getPiggyEvents($transactionGroup);
|
||||
@@ -129,6 +157,7 @@ class ShowController extends Controller
|
||||
'groupLogEntries',
|
||||
'subTitle',
|
||||
'splits',
|
||||
'selectedGroup',
|
||||
'groupArray',
|
||||
'events',
|
||||
'attachments',
|
||||
@@ -142,34 +171,38 @@ class ShowController extends Controller
|
||||
{
|
||||
$amounts = [];
|
||||
foreach ($group['transactions'] as $transaction) {
|
||||
// add normal amount:
|
||||
$symbol = $transaction['currency_symbol'];
|
||||
if (!array_key_exists($symbol, $amounts)) {
|
||||
$amounts[$symbol] = [
|
||||
'amount' => '0',
|
||||
'symbol' => $symbol,
|
||||
'decimal_places' => $transaction['currency_decimal_places'],
|
||||
];
|
||||
}
|
||||
$amounts[$symbol]['amount'] = bcadd($amounts[$symbol]['amount'], (string) $transaction['amount']);
|
||||
if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount']
|
||||
&& 0 !== bccomp(
|
||||
'0',
|
||||
(string) $transaction['foreign_amount']
|
||||
)) {
|
||||
$amounts[$symbol] ??= [
|
||||
'amount' => '0',
|
||||
'symbol' => $symbol,
|
||||
'decimal_places' => $transaction['currency_decimal_places'],
|
||||
];
|
||||
$amounts[$symbol]['amount'] = bcadd($amounts[$symbol]['amount'], (string)$transaction['amount']);
|
||||
|
||||
// add foreign amount:
|
||||
if (null !== $transaction['foreign_amount'] && '' !== $transaction['foreign_amount'] && 0 !== bccomp('0', (string)$transaction['foreign_amount'])) {
|
||||
// same for foreign currency:
|
||||
$foreignSymbol = $transaction['foreign_currency_symbol'];
|
||||
if (!array_key_exists($foreignSymbol, $amounts)) {
|
||||
$amounts[$foreignSymbol] = [
|
||||
'amount' => '0',
|
||||
'symbol' => $foreignSymbol,
|
||||
'decimal_places' => $transaction['foreign_currency_decimal_places'],
|
||||
];
|
||||
}
|
||||
$amounts[$foreignSymbol]['amount'] = bcadd(
|
||||
$amounts[$foreignSymbol]['amount'],
|
||||
(string) $transaction['foreign_amount']
|
||||
);
|
||||
$amounts[$foreignSymbol] ??= [
|
||||
'amount' => '0',
|
||||
'symbol' => $foreignSymbol,
|
||||
'decimal_places' => $transaction['foreign_currency_decimal_places'],
|
||||
];
|
||||
$amounts[$foreignSymbol]['amount'] = bcadd($amounts[$foreignSymbol]['amount'], (string)$transaction['foreign_amount']);
|
||||
}
|
||||
// add primary currency amount
|
||||
if (null !== $transaction['pc_amount'] && $transaction['currency_id'] !== $this->primaryCurrency->id) {
|
||||
// same for foreign currency:
|
||||
$primarySymbol = $this->primaryCurrency->symbol;
|
||||
$amounts[$primarySymbol] ??= [
|
||||
'amount' => '0',
|
||||
'symbol' => $this->primaryCurrency->symbol,
|
||||
'decimal_places' => $this->primaryCurrency->decimal_places,
|
||||
];
|
||||
$amounts[$primarySymbol]['amount'] = bcadd($amounts[$primarySymbol]['amount'], (string)$transaction['pc_amount']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $amounts;
|
||||
@@ -184,16 +217,16 @@ class ShowController extends Controller
|
||||
|
||||
foreach ($group['transactions'] as $transaction) {
|
||||
$accounts['source'][] = [
|
||||
'type' => $transaction['source_type'],
|
||||
'id' => $transaction['source_id'],
|
||||
'name' => $transaction['source_name'],
|
||||
'iban' => $transaction['source_iban'],
|
||||
'type' => $transaction['source_account_type'],
|
||||
'id' => $transaction['source_account_id'],
|
||||
'name' => $transaction['source_account_name'],
|
||||
'iban' => $transaction['source_account_iban'],
|
||||
];
|
||||
$accounts['destination'][] = [
|
||||
'type' => $transaction['destination_type'],
|
||||
'id' => $transaction['destination_id'],
|
||||
'name' => $transaction['destination_name'],
|
||||
'iban' => $transaction['destination_iban'],
|
||||
'type' => $transaction['destination_account_type'],
|
||||
'id' => $transaction['destination_account_id'],
|
||||
'name' => $transaction['destination_account_name'],
|
||||
'iban' => $transaction['destination_account_iban'],
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -47,12 +47,13 @@ class BudgetFormUpdateRequest extends FormRequest
|
||||
public function getBudgetData(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->convertString('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'auto_budget_type' => $this->convertInteger('auto_budget_type'),
|
||||
'currency_id' => $this->convertInteger('auto_budget_currency_id'),
|
||||
'auto_budget_amount' => $this->convertString('auto_budget_amount'),
|
||||
'auto_budget_period' => $this->convertString('auto_budget_period'),
|
||||
'name' => $this->convertString('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'auto_budget_type' => $this->convertInteger('auto_budget_type'),
|
||||
'currency_id' => $this->convertInteger('auto_budget_currency_id'),
|
||||
'auto_budget_amount' => $this->convertString('auto_budget_amount'),
|
||||
'auto_budget_period' => $this->convertString('auto_budget_period'),
|
||||
'notes' => $this->stringWithNewlines('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -25,13 +25,18 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Jobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\SubscriptionEnrichment;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Foundation\Bus\Dispatchable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class WarnAboutBills
|
||||
@@ -63,7 +68,7 @@ class WarnAboutBills implements ShouldQueue
|
||||
|
||||
$this->force = false;
|
||||
|
||||
app('log')->debug(sprintf('Created new WarnAboutBills("%s")', $this->date->format('Y-m-d')));
|
||||
Log::debug(sprintf('Created new WarnAboutBills("%s")', $this->date->format('Y-m-d')));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,36 +76,42 @@ class WarnAboutBills implements ShouldQueue
|
||||
*/
|
||||
public function handle(): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now at start of WarnAboutBills() job for %s.', $this->date->format('D d M Y')));
|
||||
$bills = Bill::all();
|
||||
Log::debug(sprintf('Now at start of WarnAboutBills() job for %s.', $this->date->format('D d M Y')));
|
||||
foreach (User::all() as $user) {
|
||||
$bills = $user->bills()->where('active', true)->get();
|
||||
$overdue = [];
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
app('log')->debug(sprintf('Now checking bill #%d ("%s")', $bill->id, $bill->name));
|
||||
if ($this->hasDateFields($bill)) {
|
||||
if ($this->needsWarning($bill, 'end_date')) {
|
||||
$this->sendWarning($bill, 'end_date');
|
||||
/** @var Bill $bill */
|
||||
foreach ($bills as $bill) {
|
||||
Log::debug(sprintf('Now checking bill #%d ("%s")', $bill->id, $bill->name));
|
||||
$dates = $this->getDates($bill);
|
||||
if ($this->needsOverdueAlert($dates)) {
|
||||
$overdue[] = ['bill' => $bill, 'dates' => $dates];
|
||||
}
|
||||
if ($this->needsWarning($bill, 'extension_date')) {
|
||||
$this->sendWarning($bill, 'extension_date');
|
||||
if ($this->hasDateFields($bill)) {
|
||||
if ($this->needsWarning($bill, 'end_date')) {
|
||||
$this->sendWarning($bill, 'end_date');
|
||||
}
|
||||
if ($this->needsWarning($bill, 'extension_date')) {
|
||||
$this->sendWarning($bill, 'extension_date');
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->sendOverdueAlerts($user, $overdue);
|
||||
}
|
||||
app('log')->debug('Done with handle()');
|
||||
Log::debug('Done with handle()');
|
||||
|
||||
// clear cache:
|
||||
app('preferences')->mark();
|
||||
}
|
||||
|
||||
private function hasDateFields(Bill $bill): bool
|
||||
{
|
||||
if (false === $bill->active) {
|
||||
app('log')->debug('Bill is not active.');
|
||||
Log::debug('Bill is not active.');
|
||||
|
||||
return false;
|
||||
}
|
||||
if (null === $bill->end_date && null === $bill->extension_date) {
|
||||
app('log')->debug('Bill has no date fields.');
|
||||
Log::debug('Bill has no date fields.');
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -115,7 +126,7 @@ class WarnAboutBills implements ShouldQueue
|
||||
}
|
||||
$diff = $this->getDiff($bill, $field);
|
||||
$list = config('firefly.bill_reminder_periods');
|
||||
app('log')->debug(sprintf('Difference in days for field "%s" ("%s") is %d day(s)', $field, $bill->{$field}->format('Y-m-d'), $diff));
|
||||
Log::debug(sprintf('Difference in days for field "%s" ("%s") is %d day(s)', $field, $bill->{$field}->format('Y-m-d'), $diff));
|
||||
if (in_array($diff, $list, true)) {
|
||||
return true;
|
||||
}
|
||||
@@ -128,13 +139,13 @@ class WarnAboutBills implements ShouldQueue
|
||||
$today = clone $this->date;
|
||||
$carbon = clone $bill->{$field};
|
||||
|
||||
return (int) $today->diffInDays($carbon);
|
||||
return (int)$today->diffInDays($carbon);
|
||||
}
|
||||
|
||||
private function sendWarning(Bill $bill, string $field): void
|
||||
{
|
||||
$diff = $this->getDiff($bill, $field);
|
||||
app('log')->debug('Will now send warning!');
|
||||
Log::debug('Will now send warning!');
|
||||
event(new WarnUserAboutBill($bill, $field, $diff));
|
||||
}
|
||||
|
||||
@@ -149,4 +160,49 @@ class WarnAboutBills implements ShouldQueue
|
||||
{
|
||||
$this->force = $force;
|
||||
}
|
||||
|
||||
private function getDates(Bill $bill): array
|
||||
{
|
||||
$start = clone $this->date;
|
||||
$start = Navigation::startOfPeriod($start, $bill->repeat_freq);
|
||||
$end = clone $start;
|
||||
$end = Navigation::endOfPeriod($end, $bill->repeat_freq);
|
||||
$enrichment = new SubscriptionEnrichment();
|
||||
$enrichment->setUser($bill->user);
|
||||
$enrichment->setStart($start);
|
||||
$enrichment->setEnd($end);
|
||||
$single = $enrichment->enrichSingle($bill);
|
||||
|
||||
return [
|
||||
'pay_dates' => $single->meta['pay_dates'] ?? [],
|
||||
'paid_dates' => $single->meta['paid_dates'] ?? [],
|
||||
];
|
||||
}
|
||||
|
||||
private function needsOverdueAlert(array $dates): bool
|
||||
{
|
||||
$count = count($dates['pay_dates']) - count($dates['paid_dates']);
|
||||
if (0 === $count || 0 === count($dates['pay_dates'])) {
|
||||
return false;
|
||||
}
|
||||
// the earliest date in the list of pay dates must be 48hrs or more ago.
|
||||
$earliest = new Carbon($dates['pay_dates'][0]);
|
||||
$earliest->startOfDay();
|
||||
Log::debug(sprintf('Earliest expected pay date is %s', $earliest->toAtomString()));
|
||||
$diff = $earliest->diffInDays($this->date);
|
||||
Log::debug(sprintf('Difference in days is %s', $diff));
|
||||
if ($diff < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function sendOverdueAlerts(User $user, array $overdue): void
|
||||
{
|
||||
if (count($overdue) > 0) {
|
||||
Log::debug(sprintf('Will now send warning about overdue bill for user #%d.', $user->id));
|
||||
event(new WarnUserAboutOverdueSubscriptions($user, $overdue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
113
app/Notifications/User/SubscriptionsOverdueReminder.php
Normal file
113
app/Notifications/User/SubscriptionsOverdueReminder.php
Normal file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Notifications\User;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Notifications\ReturnsAvailableChannels;
|
||||
use FireflyIII\Notifications\ReturnsSettings;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Messages\SlackMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\Pushover\PushoverMessage;
|
||||
|
||||
class SubscriptionsOverdueReminder extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public function __construct(private array $overdue) {}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function toArray(User $notifiable): array
|
||||
{
|
||||
return [
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function toMail(User $notifiable): MailMessage
|
||||
{
|
||||
// format the data
|
||||
$info = [];
|
||||
$count = 0;
|
||||
foreach ($this->overdue as $item) {
|
||||
$current = [
|
||||
'bill' => $item['bill'],
|
||||
];
|
||||
$current['pay_dates'] = array_map(
|
||||
static function (string $date): string {
|
||||
return new Carbon($date)->isoFormat((string)trans('config.month_and_day_moment_js'));
|
||||
},
|
||||
$item['dates']['pay_dates']
|
||||
);
|
||||
$info[] = $current;
|
||||
++$count;
|
||||
}
|
||||
|
||||
return new MailMessage()
|
||||
->markdown('emails.subscriptions-overdue-warning', ['info' => $info, 'count' => $count])
|
||||
->subject($this->getSubject())
|
||||
;
|
||||
}
|
||||
|
||||
private function getSubject(): string
|
||||
{
|
||||
if (count($this->overdue) > 1) {
|
||||
return (string)trans('email.subscriptions_overdue_subject_multi', ['count' => count($this->overdue)]);
|
||||
}
|
||||
|
||||
return (string)trans('email.subscriptions_overdue_subject_single');
|
||||
}
|
||||
|
||||
public function toNtfy(User $notifiable): Message
|
||||
{
|
||||
$settings = ReturnsSettings::getSettings('ntfy', 'user', $notifiable);
|
||||
$message = new Message();
|
||||
$message->topic($settings['ntfy_topic']);
|
||||
$message->title($this->getSubject());
|
||||
$message->body((string)trans('email.bill_warning_please_action'));
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function toPushover(User $notifiable): PushoverMessage
|
||||
{
|
||||
return PushoverMessage::create((string)trans('email.bill_warning_please_action'))
|
||||
->title($this->getSubject())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function toSlack(User $notifiable): SlackMessage
|
||||
{
|
||||
$url = route('bills.index');
|
||||
|
||||
return new SlackMessage()
|
||||
->warning()
|
||||
->attachment(static function ($attachment) use ($url): void {
|
||||
$attachment->title((string)trans('firefly.visit_bills'), $url);
|
||||
})
|
||||
->content($this->getSubject())
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @SuppressWarnings("PHPMD.UnusedFormalParameter")
|
||||
*/
|
||||
public function via(User $notifiable): array
|
||||
{
|
||||
return ReturnsAvailableChannels::returnChannels('user', $notifiable);
|
||||
}
|
||||
}
|
@@ -27,6 +27,8 @@ use FireflyIII\Events\ActuallyLoggedIn;
|
||||
use FireflyIII\Events\Admin\InvitationCreated;
|
||||
use FireflyIII\Events\DestroyedTransactionGroup;
|
||||
use FireflyIII\Events\DetectedNewIPAddress;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutBill;
|
||||
use FireflyIII\Events\Model\Bill\WarnUserAboutOverdueSubscriptions;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Created;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Deleted;
|
||||
use FireflyIII\Events\Model\BudgetLimit\Updated;
|
||||
@@ -58,7 +60,6 @@ use FireflyIII\Events\TriggeredAuditLog;
|
||||
use FireflyIII\Events\UpdatedAccount;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Events\UserChangedEmail;
|
||||
use FireflyIII\Events\WarnUserAboutBill;
|
||||
use FireflyIII\Handlers\Observer\AccountObserver;
|
||||
use FireflyIII\Handlers\Observer\AttachmentObserver;
|
||||
use FireflyIII\Handlers\Observer\AutoBudgetObserver;
|
||||
@@ -114,150 +115,153 @@ class EventServiceProvider extends ServiceProvider
|
||||
protected $listen
|
||||
= [
|
||||
// is a User related event.
|
||||
RegisteredUser::class => [
|
||||
RegisteredUser::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationMail',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendAdminRegistrationNotification',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@attachUserRole',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@createGroupMembership',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@createExchangeRates',
|
||||
],
|
||||
UserAttemptedLogin::class => [
|
||||
UserAttemptedLogin::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendLoginAttemptNotification',
|
||||
],
|
||||
// is a User related event.
|
||||
Login::class => [
|
||||
Login::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@checkSingleUserIsAdmin',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@demoUserBackToEnglish',
|
||||
],
|
||||
ActuallyLoggedIn::class => [
|
||||
ActuallyLoggedIn::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@storeUserIPAddress',
|
||||
],
|
||||
DetectedNewIPAddress::class => [
|
||||
DetectedNewIPAddress::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@notifyNewIPAddress',
|
||||
],
|
||||
RequestedVersionCheckStatus::class => [
|
||||
RequestedVersionCheckStatus::class => [
|
||||
'FireflyIII\Handlers\Events\VersionCheckEventHandler@checkForUpdates',
|
||||
],
|
||||
RequestedReportOnJournals::class => [
|
||||
RequestedReportOnJournals::class => [
|
||||
'FireflyIII\Handlers\Events\AutomationHandler@reportJournals',
|
||||
],
|
||||
|
||||
// is a User related event.
|
||||
RequestedNewPassword::class => [
|
||||
RequestedNewPassword::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendNewPassword',
|
||||
],
|
||||
UserTestNotificationChannel::class => [
|
||||
UserTestNotificationChannel::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendTestNotification',
|
||||
],
|
||||
// is a User related event.
|
||||
UserChangedEmail::class => [
|
||||
UserChangedEmail::class => [
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeConfirmMail',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendEmailChangeUndoMail',
|
||||
],
|
||||
// admin related
|
||||
OwnerTestNotificationChannel::class => [
|
||||
OwnerTestNotificationChannel::class => [
|
||||
'FireflyIII\Handlers\Events\AdminEventHandler@sendTestNotification',
|
||||
],
|
||||
NewVersionAvailable::class => [
|
||||
NewVersionAvailable::class => [
|
||||
'FireflyIII\Handlers\Events\AdminEventHandler@sendNewVersion',
|
||||
],
|
||||
InvitationCreated::class => [
|
||||
InvitationCreated::class => [
|
||||
'FireflyIII\Handlers\Events\AdminEventHandler@sendInvitationNotification',
|
||||
'FireflyIII\Handlers\Events\UserEventHandler@sendRegistrationInvite',
|
||||
],
|
||||
UnknownUserAttemptedLogin::class => [
|
||||
UnknownUserAttemptedLogin::class => [
|
||||
'FireflyIII\Handlers\Events\AdminEventHandler@sendLoginAttemptNotification',
|
||||
],
|
||||
|
||||
// is a Transaction Journal related event.
|
||||
StoredTransactionGroup::class => [
|
||||
StoredTransactionGroup::class => [
|
||||
'FireflyIII\Handlers\Events\StoredGroupEventHandler@runAllHandlers',
|
||||
],
|
||||
// is a Transaction Journal related event.
|
||||
UpdatedTransactionGroup::class => [
|
||||
UpdatedTransactionGroup::class => [
|
||||
'FireflyIII\Handlers\Events\UpdatedGroupEventHandler@runAllHandlers',
|
||||
],
|
||||
DestroyedTransactionGroup::class => [
|
||||
DestroyedTransactionGroup::class => [
|
||||
'FireflyIII\Handlers\Events\DestroyedGroupEventHandler@runAllHandlers',
|
||||
],
|
||||
// API related events:
|
||||
AccessTokenCreated::class => [
|
||||
AccessTokenCreated::class => [
|
||||
'FireflyIII\Handlers\Events\APIEventHandler@accessTokenCreated',
|
||||
],
|
||||
|
||||
// Webhook related event:
|
||||
RequestedSendWebhookMessages::class => [
|
||||
RequestedSendWebhookMessages::class => [
|
||||
'FireflyIII\Handlers\Events\WebhookEventHandler@sendWebhookMessages',
|
||||
],
|
||||
|
||||
// account related events:
|
||||
StoredAccount::class => [
|
||||
StoredAccount::class => [
|
||||
'FireflyIII\Handlers\Events\StoredAccountEventHandler@recalculateCredit',
|
||||
],
|
||||
UpdatedAccount::class => [
|
||||
UpdatedAccount::class => [
|
||||
'FireflyIII\Handlers\Events\UpdatedAccountEventHandler@recalculateCredit',
|
||||
],
|
||||
|
||||
// bill related events:
|
||||
WarnUserAboutBill::class => [
|
||||
WarnUserAboutBill::class => [
|
||||
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutBill',
|
||||
],
|
||||
WarnUserAboutOverdueSubscriptions::class => [
|
||||
'FireflyIII\Handlers\Events\BillEventHandler@warnAboutOverdueSubscriptions',
|
||||
],
|
||||
|
||||
// audit log events:
|
||||
TriggeredAuditLog::class => [
|
||||
TriggeredAuditLog::class => [
|
||||
'FireflyIII\Handlers\Events\AuditEventHandler@storeAuditEvent',
|
||||
],
|
||||
// piggy bank related events:
|
||||
ChangedAmount::class => [
|
||||
ChangedAmount::class => [
|
||||
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changePiggyAmount',
|
||||
],
|
||||
ChangedName::class => [
|
||||
ChangedName::class => [
|
||||
'FireflyIII\Handlers\Events\Model\PiggyBankEventHandler@changedPiggyBankName',
|
||||
],
|
||||
|
||||
// budget related events: CRUD budget limit
|
||||
Created::class => [
|
||||
Created::class => [
|
||||
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@created',
|
||||
],
|
||||
Updated::class => [
|
||||
Updated::class => [
|
||||
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@updated',
|
||||
],
|
||||
Deleted::class => [
|
||||
Deleted::class => [
|
||||
'FireflyIII\Handlers\Events\Model\BudgetLimitHandler@deleted',
|
||||
],
|
||||
|
||||
// rule actions
|
||||
RuleActionFailedOnArray::class => [
|
||||
RuleActionFailedOnArray::class => [
|
||||
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnArray',
|
||||
],
|
||||
RuleActionFailedOnObject::class => [
|
||||
RuleActionFailedOnObject::class => [
|
||||
'FireflyIII\Handlers\Events\Model\RuleHandler@ruleActionFailedOnObject',
|
||||
],
|
||||
|
||||
// security related
|
||||
EnabledMFA::class => [
|
||||
EnabledMFA::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAEnabledMail',
|
||||
],
|
||||
DisabledMFA::class => [
|
||||
DisabledMFA::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFADisabledMail',
|
||||
],
|
||||
MFANewBackupCodes::class => [
|
||||
MFANewBackupCodes::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendNewMFABackupCodesMail',
|
||||
],
|
||||
MFAUsedBackupCode::class => [
|
||||
MFAUsedBackupCode::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendUsedBackupCodeMail',
|
||||
],
|
||||
MFABackupFewLeft::class => [
|
||||
MFABackupFewLeft::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupFewLeftMail',
|
||||
],
|
||||
MFABackupNoLeft::class => [
|
||||
MFABackupNoLeft::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendBackupNoLeftMail',
|
||||
],
|
||||
MFAManyFailedAttempts::class => [
|
||||
MFAManyFailedAttempts::class => [
|
||||
'FireflyIII\Handlers\Events\Security\MFAHandler@sendMFAFailedAttemptsMail',
|
||||
],
|
||||
// preferences
|
||||
UserGroupChangedPrimaryCurrency::class => [
|
||||
UserGroupChangedPrimaryCurrency::class => [
|
||||
'FireflyIII\Handlers\Events\PreferencesEventHandler@resetPrimaryCurrencyAmounts',
|
||||
],
|
||||
];
|
||||
|
@@ -562,7 +562,13 @@ class AccountRepository implements AccountRepositoryInterface, UserGroupInterfac
|
||||
'foreign_currencies.decimal_places as foreign_currency_decimal_places',
|
||||
|
||||
// fields
|
||||
'transaction_journals.date', 'transaction_types.type', 'transaction_journals.transaction_currency_id', 'transactions.amount'])
|
||||
'transaction_journals.date',
|
||||
'transaction_types.type',
|
||||
'transaction_journals.transaction_currency_id',
|
||||
'transactions.amount',
|
||||
'transactions.native_amount as pc_amount',
|
||||
'transactions.foreign_amount',
|
||||
])
|
||||
->toArray()
|
||||
;
|
||||
|
||||
|
@@ -50,10 +50,10 @@ class AccountTasker implements AccountTaskerInterface, UserGroupInterface
|
||||
$yesterday = clone $start;
|
||||
$yesterday->subDay()->endOfDay(); // exactly up until $start but NOT including.
|
||||
$end->endOfDay(); // needs to be end of day to be correct.
|
||||
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $yesterday->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('getAccountReport: finalAccountsBalance("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startSet = Steam::finalAccountsBalance($accounts, $yesterday);
|
||||
$endSet = Steam::finalAccountsBalance($accounts, $end);
|
||||
Log::debug(sprintf('getAccountReport: accountsBalancesOptimized("%s")', $yesterday->format('Y-m-d H:i:s')));
|
||||
Log::debug(sprintf('getAccountReport: accountsBalancesOptimized("%s")', $end->format('Y-m-d H:i:s')));
|
||||
$startSet = Steam::accountsBalancesOptimized($accounts, $yesterday);
|
||||
$endSet = Steam::accountsBalancesOptimized($accounts, $end);
|
||||
Log::debug('Start of accountreport');
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
|
@@ -52,4 +52,10 @@ class ALERepository implements ALERepositoryInterface
|
||||
|
||||
return $auditLogEntry;
|
||||
}
|
||||
|
||||
public function getForId(string $model, int $modelId): Collection
|
||||
{
|
||||
// all Models have an ID.
|
||||
return AuditLogEntry::where('auditable_id', $modelId)->where('auditable_type', $model)->get();
|
||||
}
|
||||
}
|
||||
|
@@ -46,5 +46,7 @@ interface ALERepositoryInterface
|
||||
{
|
||||
public function getForObject(Model $model): Collection;
|
||||
|
||||
public function getForId(string $model, int $modelId): Collection;
|
||||
|
||||
public function store(array $data): AuditLogEntry;
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Support\Collection;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Class NoBudgetRepository
|
||||
@@ -98,4 +99,23 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface, UserGroupInterf
|
||||
|
||||
return $summarizer->groupByCurrencyId($journals);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if ($currency instanceof TransactionCurrency) {
|
||||
$collector->setCurrency($currency);
|
||||
}
|
||||
$collector->withoutBudget();
|
||||
$collector->withBudgetInformation();
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
}
|
||||
|
@@ -49,4 +49,6 @@ interface NoBudgetRepositoryInterface
|
||||
public function getNoBudgetPeriodReport(Collection $accounts, Carbon $start, Carbon $end): array;
|
||||
|
||||
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array;
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?TransactionCurrency $currency = null): array;
|
||||
}
|
||||
|
@@ -39,6 +39,7 @@ use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* Class OperationsRepository
|
||||
@@ -57,17 +58,17 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
$total = '0';
|
||||
$count = 0;
|
||||
foreach ($budget->budgetlimits as $limit) {
|
||||
$diff = (int)$limit->start_date->diffInDays($limit->end_date, true);
|
||||
$diff = (int) $limit->start_date->diffInDays($limit->end_date, true);
|
||||
$diff = 0 === $diff ? 1 : $diff;
|
||||
$amount = $limit->amount;
|
||||
$perDay = bcdiv((string)$amount, (string)$diff);
|
||||
$perDay = bcdiv((string) $amount, (string) $diff);
|
||||
$total = bcadd($total, $perDay);
|
||||
++$count;
|
||||
app('log')->debug(sprintf('Found %d budget limits. Per day is %s, total is %s', $count, $perDay, $total));
|
||||
}
|
||||
$avg = $total;
|
||||
if ($count > 0) {
|
||||
$avg = bcdiv($total, (string)$count);
|
||||
$avg = bcdiv($total, (string) $count);
|
||||
}
|
||||
app('log')->debug(sprintf('%s / %d = %s = average.', $total, $count, $avg));
|
||||
|
||||
@@ -95,9 +96,9 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
// prep data array for currency:
|
||||
$budgetId = (int)$journal['budget_id'];
|
||||
$budgetId = (int) $journal['budget_id'];
|
||||
$budgetName = $journal['budget_name'];
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currencyId = (int) $journal['currency_id'];
|
||||
$key = sprintf('%d-%d', $budgetId, $currencyId);
|
||||
|
||||
$data[$key] ??= [
|
||||
@@ -112,7 +113,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
'entries' => [],
|
||||
];
|
||||
$date = $journal['date']->format($carbonFormat);
|
||||
$data[$key]['entries'][$date] = bcadd($data[$key]['entries'][$date] ?? '0', (string)$journal['amount']);
|
||||
$data[$key]['entries'][$date] = bcadd($data[$key]['entries'][$date] ?? '0', (string) $journal['amount']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
@@ -156,7 +157,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
|
||||
foreach ($journals as $journal) {
|
||||
$amount = app('steam')->negative($journal['amount']);
|
||||
$journalCurrencyId = (int)$journal['currency_id'];
|
||||
$journalCurrencyId = (int) $journal['currency_id'];
|
||||
if (false === $convertToPrimary) {
|
||||
$currencyId = $journalCurrencyId;
|
||||
$currencyName = $journal['currency_name'];
|
||||
@@ -169,8 +170,8 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
$amount = $converter->convert($currencies[$journalCurrencyId], $primaryCurrency, $journal['date'], $amount);
|
||||
}
|
||||
|
||||
$budgetId = (int)$journal['budget_id'];
|
||||
$budgetName = (string)$journal['budget_name'];
|
||||
$budgetId = (int) $journal['budget_id'];
|
||||
$budgetName = (string) $journal['budget_name'];
|
||||
|
||||
// catch "no budget" entries.
|
||||
if (0 === $budgetId) {
|
||||
@@ -196,13 +197,16 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
|
||||
// add journal to array:
|
||||
// only a subset of the fields.
|
||||
$journalId = (int)$journal['transaction_journal_id'];
|
||||
$journalId = (int) $journal['transaction_journal_id'];
|
||||
$array[$currencyId]['budgets'][$budgetId]['transaction_journals'][$journalId] = [
|
||||
'amount' => $amount,
|
||||
'destination_account_id' => $journal['destination_account_id'],
|
||||
'destination_account_name' => $journal['destination_account_name'],
|
||||
'destination_account_type' => $journal['destination_account_type'],
|
||||
'currency_id' => $journalCurrencyId,
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'source_account_name' => $journal['source_account_name'],
|
||||
'source_account_type' => $journal['source_account_type'],
|
||||
'category_name' => $journal['category_name'],
|
||||
'description' => $journal['description'],
|
||||
'transaction_group_id' => $journal['transaction_group_id'],
|
||||
@@ -282,4 +286,77 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
|
||||
return $summarizer->groupByCurrencyId($journals, 'negative', false);
|
||||
}
|
||||
|
||||
public function sumCollectedExpenses(array $expenses, Carbon $start, Carbon $end, TransactionCurrency $transactionCurrency, bool $convertToPrimary = false): array
|
||||
{
|
||||
Log::debug(sprintf('Start of %s.', __METHOD__));
|
||||
$summarizer = new TransactionSummarizer($this->user);
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static function (array $expense) use ($start, $end, $transactionCurrency): bool {
|
||||
return $expense['date']->between($start, $end) && $expense['currency_id'] === $transactionCurrency->id;
|
||||
});
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
|
||||
}
|
||||
|
||||
public function sumCollectedExpensesByBudget(array $expenses, Budget $budget, bool $convertToPrimary = false): array
|
||||
{
|
||||
Log::debug(sprintf('Start of %s.', __METHOD__));
|
||||
$summarizer = new TransactionSummarizer($this->user);
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static function (array $expense) use ($budget): bool {
|
||||
return $expense['budget_id'] === $budget->id;
|
||||
});
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null, ?TransactionCurrency $currency = null): array
|
||||
{
|
||||
Log::debug(sprintf('Start of %s(date, date, array, array, "%s").', __METHOD__, $currency?->code));
|
||||
// this collector excludes all transfers TO liabilities (which are also withdrawals)
|
||||
// because those expenses only become expenses once they move from the liability to the friend.
|
||||
// 2024-12-24 disable the exclusion for now.
|
||||
|
||||
$repository = app(AccountRepositoryInterface::class);
|
||||
$repository->setUser($this->user);
|
||||
$subset = $repository->getAccountsByType(config('firefly.valid_liabilities'));
|
||||
$selection = new Collection();
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($subset as $account) {
|
||||
if ('credit' === $repository->getMetaValue($account, 'liability_direction')) {
|
||||
$selection->push($account);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)
|
||||
->setRange($start, $end)
|
||||
// ->excludeDestinationAccounts($selection)
|
||||
->setTypes([TransactionTypeEnum::WITHDRAWAL->value])
|
||||
;
|
||||
|
||||
if ($accounts instanceof Collection) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$budgets instanceof Collection) {
|
||||
$budgets = $this->getBudgets();
|
||||
}
|
||||
if ($currency instanceof TransactionCurrency) {
|
||||
Log::debug(sprintf('Limit to normal currency %s', $currency->code));
|
||||
$collector->setNormalCurrency($currency);
|
||||
}
|
||||
if ($budgets->count() > 0) {
|
||||
$collector->setBudgets($budgets);
|
||||
}
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
}
|
||||
|
@@ -24,8 +24,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Repositories\Budget;
|
||||
|
||||
use Deprecated;
|
||||
use Carbon\Carbon;
|
||||
use Deprecated;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
@@ -73,4 +73,10 @@ interface OperationsRepositoryInterface
|
||||
?TransactionCurrency $currency = null,
|
||||
bool $convertToPrimary = false
|
||||
): array;
|
||||
|
||||
public function sumCollectedExpenses(array $expenses, Carbon $start, Carbon $end, TransactionCurrency $transactionCurrency, bool $convertToPrimary = false): array;
|
||||
|
||||
public function sumCollectedExpensesByBudget(array $expenses, Budget $budget, bool $convertToPrimary = false): array;
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null, ?TransactionCurrency $currency = null): array;
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Repositories\Category;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||
@@ -444,4 +445,74 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$categories instanceof Collection || 0 === $categories->count()) {
|
||||
$categories = $this->getCategories();
|
||||
}
|
||||
$collector->setCategories($categories);
|
||||
$collector->withCategoryInformation();
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
|
||||
public function collectIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)
|
||||
->setTypes([TransactionTypeEnum::DEPOSIT->value])
|
||||
;
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$categories instanceof Collection || 0 === $categories->count()) {
|
||||
$categories = $this->getCategories();
|
||||
}
|
||||
$collector->setCategories($categories);
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
|
||||
public function collectTransfers(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)
|
||||
->setTypes([TransactionTypeEnum::TRANSFER->value])
|
||||
;
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$categories instanceof Collection || 0 === $categories->count()) {
|
||||
$categories = $this->getCategories();
|
||||
}
|
||||
$collector->setCategories($categories);
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
|
||||
public function sumCollectedTransactionsByCategory(array $expenses, Category $category, string $method, bool $convertToPrimary = false): array
|
||||
{
|
||||
Log::debug(sprintf('Start of %s.', __METHOD__));
|
||||
$summarizer = new TransactionSummarizer($this->user);
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static function (array $expense) use ($category): bool {
|
||||
return $expense['category_id'] === $category->id;
|
||||
});
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, $method, false);
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
@@ -78,6 +79,14 @@ interface OperationsRepositoryInterface
|
||||
*/
|
||||
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function collectIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function collectTransfers(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function sumCollectedTransactionsByCategory(array $expenses, Category $category, string $method, bool $convertToPrimary = false): array;
|
||||
|
||||
/**
|
||||
* Sum of income journals in period for a set of categories, grouped per currency. Amounts are always positive.
|
||||
*/
|
||||
|
@@ -131,7 +131,7 @@ class PiggyBankRepository implements PiggyBankRepositoryInterface, UserGroupInte
|
||||
/**
|
||||
* Get current amount saved in piggy bank.
|
||||
*/
|
||||
public function getCurrentPrimaryAmount(PiggyBank $piggyBank, ?Account $account = null): string
|
||||
public function getCurrentPrimaryCurrencyAmount(PiggyBank $piggyBank, ?Account $account = null): string
|
||||
{
|
||||
$sum = '0';
|
||||
foreach ($piggyBank->accounts as $current) {
|
||||
|
@@ -80,7 +80,7 @@ interface PiggyBankRepositoryInterface
|
||||
*/
|
||||
public function getCurrentAmount(PiggyBank $piggyBank, ?Account $account = null): string;
|
||||
|
||||
public function getCurrentPrimaryAmount(PiggyBank $piggyBank, ?Account $account = null): string;
|
||||
public function getCurrentPrimaryCurrencyAmount(PiggyBank $piggyBank, ?Account $account = null): string;
|
||||
|
||||
/**
|
||||
* Get all events.
|
||||
|
@@ -32,6 +32,7 @@ use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use JsonException;
|
||||
|
||||
use function Safe\json_encode;
|
||||
@@ -65,9 +66,9 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
try {
|
||||
$signature = $signatureGenerator->generate($this->message);
|
||||
} catch (FireflyException $e) {
|
||||
app('log')->error('Did not send message because of a Firefly III Exception.');
|
||||
app('log')->error($e->getMessage());
|
||||
app('log')->error($e->getTraceAsString());
|
||||
Log::error('Did not send message because of a Firefly III Exception.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$attempt = new WebhookAttempt();
|
||||
$attempt->webhookMessage()->associate($this->message);
|
||||
$attempt->status_code = 0;
|
||||
@@ -80,14 +81,14 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
return;
|
||||
}
|
||||
|
||||
app('log')->debug(sprintf('Trying to send webhook message #%d', $this->message->id));
|
||||
Log::debug(sprintf('Trying to send webhook message #%d', $this->message->id));
|
||||
|
||||
try {
|
||||
$json = json_encode($this->message->message, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
app('log')->error('Did not send message because of a JSON error.');
|
||||
app('log')->error($e->getMessage());
|
||||
app('log')->error($e->getTraceAsString());
|
||||
Log::error('Did not send message because of a JSON error.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
$attempt = new WebhookAttempt();
|
||||
$attempt->webhookMessage()->associate($this->message);
|
||||
$attempt->status_code = 0;
|
||||
@@ -115,9 +116,9 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
try {
|
||||
$res = $client->request('POST', $this->message->webhook->url, $options);
|
||||
} catch (ConnectException|RequestException $e) {
|
||||
app('log')->error('The webhook could NOT be submitted but Firefly III caught the error below.');
|
||||
app('log')->error($e->getMessage());
|
||||
app('log')->error($e->getTraceAsString());
|
||||
Log::error('The webhook could NOT be submitted but Firefly III caught the error below.');
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
$logs = sprintf("%s\n%s", $e->getMessage(), $e->getTraceAsString());
|
||||
|
||||
@@ -130,9 +131,9 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
$attempt->status_code = 0;
|
||||
if (method_exists($e, 'hasResponse') && method_exists($e, 'getResponse')) {
|
||||
$attempt->status_code = $e->hasResponse() ? $e->getResponse()->getStatusCode() : 0;
|
||||
app('log')->error(sprintf('The status code of the error response is: %d', $attempt->status_code));
|
||||
Log::error(sprintf('The status code of the error response is: %d', $attempt->status_code));
|
||||
$body = (string) ($e->hasResponse() ? $e->getResponse()->getBody() : '');
|
||||
app('log')->error(sprintf('The body of the error response is: %s', $body));
|
||||
Log::error(sprintf('The body of the error response is: %s', $body));
|
||||
}
|
||||
$attempt->logs = $logs;
|
||||
$attempt->save();
|
||||
@@ -142,9 +143,9 @@ class StandardWebhookSender implements WebhookSenderInterface
|
||||
$this->message->sent = true;
|
||||
$this->message->save();
|
||||
|
||||
app('log')->debug(sprintf('Webhook message #%d was sent. Status code %d', $this->message->id, $res->getStatusCode()));
|
||||
app('log')->debug(sprintf('Webhook request body size: %d bytes', strlen($json)));
|
||||
app('log')->debug(sprintf('Response body: %s', $res->getBody()));
|
||||
Log::debug(sprintf('Webhook message #%d was sent. Status code %d', $this->message->id, $res->getStatusCode()));
|
||||
Log::debug(sprintf('Webhook request body size: %d bytes', strlen($json)));
|
||||
Log::debug(sprintf('Response body: %s', $res->getBody()));
|
||||
}
|
||||
|
||||
public function setMessage(WebhookMessage $message): void
|
||||
|
@@ -29,9 +29,9 @@ use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Singleton\PreferencesSingleton;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use NumberFormatter;
|
||||
|
||||
/**
|
||||
@@ -116,11 +116,28 @@ class Amount
|
||||
|
||||
public function convertToPrimary(?User $user = null): bool
|
||||
{
|
||||
$instance = PreferencesSingleton::getInstance();
|
||||
if (!$user instanceof User) {
|
||||
return true === Preferences::get('convert_to_primary', false)->data && true === config('cer.enabled');
|
||||
$pref = $instance->getPreference('convert_to_primary_no_user');
|
||||
if (null === $pref) {
|
||||
$res = true === Preferences::get('convert_to_primary', false)->data && true === config('cer.enabled');
|
||||
$instance->setPreference('convert_to_primary_no_user', $res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
return $pref;
|
||||
}
|
||||
$key = sprintf('convert_to_primary_%d', $user->id);
|
||||
$pref = $instance->getPreference($key);
|
||||
if (null === $pref) {
|
||||
$res = true === Preferences::getForUser($user, 'convert_to_primary', false)->data && true === config('cer.enabled');
|
||||
$instance->setPreference($key, $res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
return true === Preferences::getForUser($user, 'convert_to_primary', false)->data && true === config('cer.enabled');
|
||||
return $pref;
|
||||
}
|
||||
|
||||
public function getPrimaryCurrency(): TransactionCurrency
|
||||
|
@@ -28,6 +28,7 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Jobs\CreateAutoBudgetLimits;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class AutoBudgetCronjob
|
||||
@@ -42,22 +43,22 @@ class AutoBudgetCronjob extends AbstractCronjob
|
||||
$diff = Carbon::now()->getTimestamp() - $lastTime;
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
if (0 === $lastTime) {
|
||||
app('log')->info('Auto budget cron-job has never fired before.');
|
||||
Log::info('Auto budget cron-job has never fired before.');
|
||||
}
|
||||
// less than half a day ago:
|
||||
if ($lastTime > 0 && $diff <= 43200) {
|
||||
app('log')->info(sprintf('It has been %s since the auto budget cron-job has fired.', $diffForHumans));
|
||||
Log::info(sprintf('It has been %s since the auto budget cron-job has fired.', $diffForHumans));
|
||||
if (false === $this->force) {
|
||||
app('log')->info('The auto budget cron-job will not fire now.');
|
||||
Log::info('The auto budget cron-job will not fire now.');
|
||||
$this->message = sprintf('It has been %s since the auto budget cron-job has fired. It will not fire now.', $diffForHumans);
|
||||
|
||||
return;
|
||||
}
|
||||
app('log')->info('Execution of the auto budget cron-job has been FORCED.');
|
||||
Log::info('Execution of the auto budget cron-job has been FORCED.');
|
||||
}
|
||||
|
||||
if ($lastTime > 0 && $diff > 43200) {
|
||||
app('log')->info(sprintf('It has been %s since the auto budget cron-job has fired. It will fire now!', $diffForHumans));
|
||||
Log::info(sprintf('It has been %s since the auto budget cron-job has fired. It will fire now!', $diffForHumans));
|
||||
}
|
||||
|
||||
$this->fireAutoBudget();
|
||||
@@ -66,7 +67,7 @@ class AutoBudgetCronjob extends AbstractCronjob
|
||||
|
||||
private function fireAutoBudget(): void
|
||||
{
|
||||
app('log')->info(sprintf('Will now fire auto budget cron job task for date "%s".', $this->date->format('Y-m-d')));
|
||||
Log::info(sprintf('Will now fire auto budget cron job task for date "%s".', $this->date->format('Y-m-d')));
|
||||
|
||||
/** @var CreateAutoBudgetLimits $job */
|
||||
$job = app(CreateAutoBudgetLimits::class, [$this->date]);
|
||||
@@ -80,6 +81,6 @@ class AutoBudgetCronjob extends AbstractCronjob
|
||||
$this->message = 'Auto-budget cron job fired successfully.';
|
||||
|
||||
FireflyConfig::set('last_ab_job', (int) $this->date->format('U'));
|
||||
app('log')->info('Done with auto budget cron job task.');
|
||||
Log::info('Done with auto budget cron job task.');
|
||||
}
|
||||
}
|
||||
|
@@ -28,6 +28,8 @@ use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Jobs\WarnAboutBills;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class BillWarningCronjob
|
||||
@@ -39,22 +41,22 @@ class BillWarningCronjob extends AbstractCronjob
|
||||
*/
|
||||
public function fire(): void
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
/** @var Configuration $config */
|
||||
$config = app('fireflyconfig')->get('last_bw_job', 0);
|
||||
$config = FireflyConfig::get('last_bw_job', 0);
|
||||
$lastTime = (int) $config->data;
|
||||
$diff = Carbon::now()->getTimestamp() - $lastTime;
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
|
||||
if (0 === $lastTime) {
|
||||
app('log')->info('The bill notification cron-job has never fired before.');
|
||||
Log::info('The bill notification cron-job has never fired before.');
|
||||
}
|
||||
// less than half a day ago:
|
||||
if ($lastTime > 0 && $diff <= 43200) {
|
||||
app('log')->info(sprintf('It has been %s since the bill notification cron-job has fired.', $diffForHumans));
|
||||
Log::info(sprintf('It has been %s since the bill notification cron-job has fired.', $diffForHumans));
|
||||
if (false === $this->force) {
|
||||
app('log')->info('The cron-job will not fire now.');
|
||||
Log::info('The cron-job will not fire now.');
|
||||
$this->message = sprintf('It has been %s since the bill notification cron-job has fired. It will not fire now.', $diffForHumans);
|
||||
$this->jobFired = false;
|
||||
$this->jobErrored = false;
|
||||
@@ -63,11 +65,11 @@ class BillWarningCronjob extends AbstractCronjob
|
||||
return;
|
||||
}
|
||||
|
||||
app('log')->info('Execution of the bill notification cron-job has been FORCED.');
|
||||
Log::info('Execution of the bill notification cron-job has been FORCED.');
|
||||
}
|
||||
|
||||
if ($lastTime > 0 && $diff > 43200) {
|
||||
app('log')->info(sprintf('It has been %s since the bill notification cron-job has fired. It will fire now!', $diffForHumans));
|
||||
Log::info(sprintf('It has been %s since the bill notification cron-job has fired. It will fire now!', $diffForHumans));
|
||||
}
|
||||
|
||||
$this->fireWarnings();
|
||||
@@ -77,7 +79,7 @@ class BillWarningCronjob extends AbstractCronjob
|
||||
|
||||
private function fireWarnings(): void
|
||||
{
|
||||
app('log')->info(sprintf('Will now fire bill notification job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
|
||||
Log::info(sprintf('Will now fire bill notification job task for date "%s".', $this->date->format('Y-m-d H:i:s')));
|
||||
|
||||
/** @var WarnAboutBills $job */
|
||||
$job = app(WarnAboutBills::class);
|
||||
@@ -91,8 +93,8 @@ class BillWarningCronjob extends AbstractCronjob
|
||||
$this->jobSucceeded = true;
|
||||
$this->message = 'Bill notification cron job fired successfully.';
|
||||
|
||||
app('fireflyconfig')->set('last_bw_job', (int) $this->date->format('U'));
|
||||
app('log')->info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
|
||||
app('log')->info('Done with bill notification cron job task.');
|
||||
FireflyConfig::set('last_bw_job', (int) $this->date->format('U'));
|
||||
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
|
||||
Log::info('Done with bill notification cron job task.');
|
||||
}
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Support\Cronjobs;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Jobs\DownloadExchangeRates;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -37,7 +38,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
|
||||
public function fire(): void
|
||||
{
|
||||
/** @var Configuration $config */
|
||||
$config = app('fireflyconfig')->get('last_cer_job', 0);
|
||||
$config = FireflyConfig::get('last_cer_job', 0);
|
||||
$lastTime = (int) $config->data;
|
||||
$diff = Carbon::now()->getTimestamp() - $lastTime;
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
@@ -80,7 +81,7 @@ class ExchangeRatesCronjob extends AbstractCronjob
|
||||
$this->jobSucceeded = true;
|
||||
$this->message = 'Exchange rates cron job fired successfully.';
|
||||
|
||||
app('fireflyconfig')->set('last_cer_job', (int) $this->date->format('U'));
|
||||
FireflyConfig::set('last_cer_job', (int) $this->date->format('U'));
|
||||
Log::info('Done with exchange rates job task.');
|
||||
}
|
||||
}
|
||||
|
@@ -41,7 +41,7 @@ class UpdateCheckCronjob extends AbstractCronjob
|
||||
Log::debug('Now in checkForUpdates()');
|
||||
|
||||
// should not check for updates:
|
||||
$permission = app('fireflyconfig')->get('permission_update_check', -1);
|
||||
$permission = FireflyConfig::get('permission_update_check', -1);
|
||||
$value = (int) $permission->data;
|
||||
if (1 !== $value) {
|
||||
Log::debug('Update check is not enabled.');
|
||||
|
97
app/Support/Cronjobs/WebhookCronjob.php
Normal file
97
app/Support/Cronjobs/WebhookCronjob.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* RecurringCronjob.php
|
||||
* Copyright (c) 2019 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\Support\Cronjobs;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Events\RequestedSendWebhookMessages;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Configuration;
|
||||
use FireflyIII\Support\Facades\FireflyConfig;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class WebhookCronjob
|
||||
*/
|
||||
class WebhookCronjob extends AbstractCronjob
|
||||
{
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function fire(): void
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
|
||||
/** @var Configuration $config */
|
||||
$config = FireflyConfig::get('last_webhook_job', 0);
|
||||
$lastTime = (int) $config->data;
|
||||
$diff = Carbon::now()->getTimestamp() - $lastTime;
|
||||
$diffForHumans = today(config('app.timezone'))->diffForHumans(Carbon::createFromTimestamp($lastTime), null, true);
|
||||
|
||||
if (0 === $lastTime) {
|
||||
Log::info('The webhook cron-job has never fired before.');
|
||||
}
|
||||
// less than ten minutes ago.
|
||||
if ($lastTime > 0 && $diff <= 600) {
|
||||
Log::info(sprintf('It has been %s since the webhook cron-job has fired.', $diffForHumans));
|
||||
if (false === $this->force) {
|
||||
Log::info('The cron-job will not fire now.');
|
||||
$this->message = sprintf('It has been %s since the webhook cron-job has fired. It will not fire now.', $diffForHumans);
|
||||
$this->jobFired = false;
|
||||
$this->jobErrored = false;
|
||||
$this->jobSucceeded = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Log::info('Execution of the webhook cron-job has been FORCED.');
|
||||
}
|
||||
|
||||
if ($lastTime > 0 && $diff > 600) {
|
||||
Log::info(sprintf('It has been %s since the webhook cron-job has fired. It will fire now!', $diffForHumans));
|
||||
}
|
||||
|
||||
$this->fireWebhookmessages();
|
||||
|
||||
app('preferences')->mark();
|
||||
}
|
||||
|
||||
private function fireWebhookmessages(): void
|
||||
{
|
||||
Log::info(sprintf('Will now send webhook messages for date "%s".', $this->date->format('Y-m-d H:i:s')));
|
||||
|
||||
Log::debug('send event RequestedSendWebhookMessages through cron job.');
|
||||
event(new RequestedSendWebhookMessages());
|
||||
|
||||
// get stuff from job:
|
||||
$this->jobFired = true;
|
||||
$this->jobErrored = false;
|
||||
$this->jobSucceeded = true;
|
||||
$this->message = 'Send webhook messages cron job fired successfully.';
|
||||
|
||||
FireflyConfig::set('last_webhook_job', (int) $this->date->format('U'));
|
||||
Log::info(sprintf('Marked the last time this job has run as "%s" (%d)', $this->date->format('Y-m-d H:i:s'), (int) $this->date->format('U')));
|
||||
Log::info('Done with webhook cron job task.');
|
||||
}
|
||||
}
|
@@ -28,19 +28,34 @@ use Illuminate\Support\Facades\Log;
|
||||
|
||||
class Timer
|
||||
{
|
||||
private static array $times = [];
|
||||
private array $times = [];
|
||||
private static ?Timer $instance = null;
|
||||
|
||||
public static function start(string $title): void
|
||||
private function __construct()
|
||||
{
|
||||
self::$times[$title] = microtime(true);
|
||||
// Private constructor to prevent direct instantiation.
|
||||
}
|
||||
|
||||
public static function stop(string $title): void
|
||||
public static function getInstance(): self
|
||||
{
|
||||
$start = self::$times[$title] ?? 0;
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function start(string $title): void
|
||||
{
|
||||
$this->times[$title] = microtime(true);
|
||||
}
|
||||
|
||||
public function stop(string $title): void
|
||||
{
|
||||
$start = $this->times[$title] ?? 0;
|
||||
$end = microtime(true);
|
||||
$diff = $end - $start;
|
||||
unset(self::$times[$title]);
|
||||
unset($this->times[$title]);
|
||||
Log::debug(sprintf('Timer "%s" took %f seconds', $title, $diff));
|
||||
}
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ trait ChartGeneration
|
||||
/** @var AccountRepositoryInterface $accountRepos */
|
||||
$accountRepos = app(AccountRepositoryInterface::class);
|
||||
|
||||
$default = app('amount')->getPrimaryCurrency();
|
||||
$primary = app('amount')->getPrimaryCurrency();
|
||||
$chartData = [];
|
||||
|
||||
Log::debug(sprintf('Start of accountBalanceChart(list, %s, %s)', $start->format('Y-m-d H:i:s'), $end->format('Y-m-d H:i:s')));
|
||||
@@ -75,10 +75,10 @@ trait ChartGeneration
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
Log::debug(sprintf('Now at account #%d ("%s)', $account->id, $account->name));
|
||||
$currency = $accountRepos->getAccountCurrency($account) ?? $default;
|
||||
$usePrimary = $convertToPrimary && $default->id !== $currency->id;
|
||||
$currency = $accountRepos->getAccountCurrency($account) ?? $primary;
|
||||
$usePrimary = $convertToPrimary && $primary->id !== $currency->id;
|
||||
$field = $convertToPrimary ? 'pc_balance' : 'balance';
|
||||
$currency = $usePrimary ? $default : $currency;
|
||||
$currency = $usePrimary ? $primary : $currency;
|
||||
Log::debug(sprintf('Will use field %s', $field));
|
||||
$currentSet = [
|
||||
'label' => $account->name,
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Support\Cronjobs\AutoBudgetCronjob;
|
||||
use FireflyIII\Support\Cronjobs\BillWarningCronjob;
|
||||
use FireflyIII\Support\Cronjobs\ExchangeRatesCronjob;
|
||||
use FireflyIII\Support\Cronjobs\RecurringCronjob;
|
||||
use FireflyIII\Support\Cronjobs\WebhookCronjob;
|
||||
|
||||
/**
|
||||
* Trait CronRunner
|
||||
@@ -62,6 +63,32 @@ trait CronRunner
|
||||
];
|
||||
}
|
||||
|
||||
protected function webhookCronJob(bool $force, Carbon $date): array
|
||||
{
|
||||
/** @var WebhookCronjob $webhook */
|
||||
$webhook = app(WebhookCronjob::class);
|
||||
$webhook->setForce($force);
|
||||
$webhook->setDate($date);
|
||||
|
||||
try {
|
||||
$webhook->fire();
|
||||
} catch (FireflyException $e) {
|
||||
return [
|
||||
'job_fired' => false,
|
||||
'job_succeeded' => false,
|
||||
'job_errored' => true,
|
||||
'message' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'job_fired' => $webhook->jobFired,
|
||||
'job_succeeded' => $webhook->jobSucceeded,
|
||||
'job_errored' => $webhook->jobErrored,
|
||||
'message' => $webhook->message,
|
||||
];
|
||||
}
|
||||
|
||||
protected function exchangeRatesCronJob(bool $force, Carbon $date): array
|
||||
{
|
||||
/** @var ExchangeRatesCronjob $exchangeRates */
|
||||
|
@@ -35,6 +35,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
use FireflyIII\Support\Debug\Timer;
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
@@ -79,9 +80,10 @@ trait PeriodOverview
|
||||
protected function getAccountPeriodOverview(Account $account, Carbon $start, Carbon $end): array
|
||||
{
|
||||
Log::debug('Now in getAccountPeriodOverview()');
|
||||
Timer::start('account-period-total');
|
||||
$timer = Timer::getInstance();
|
||||
$timer->start('account-period-total');
|
||||
$this->accountRepository = app(AccountRepositoryInterface::class);
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$range = Navigation::getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for cache
|
||||
@@ -91,32 +93,30 @@ trait PeriodOverview
|
||||
$cache->addProperty('account-show-period-entries');
|
||||
$cache->addProperty($account->id);
|
||||
if ($cache->has()) {
|
||||
Log::debug('Return CACHED in getAccountPeriodOverview()');
|
||||
|
||||
return $cache->get();
|
||||
}
|
||||
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
$spent = [];
|
||||
$earned = [];
|
||||
$transferredAway = [];
|
||||
$transferredIn = [];
|
||||
|
||||
// run a custom query because doing this with the collector is MEGA slow.
|
||||
$timer->start('account-period-collect');
|
||||
$transactions = $this->accountRepository->periodCollection($account, $start, $end);
|
||||
|
||||
$timer->stop('account-period-collect');
|
||||
// loop dates
|
||||
Log::debug(sprintf('Count of loops: %d', count($dates)));
|
||||
$loops = 0;
|
||||
// stop after 10 loops for memory reasons.
|
||||
$timer->start('account-period-loop');
|
||||
foreach ($dates as $currentDate) {
|
||||
$title = app('navigation')->periodShow($currentDate['start'], $currentDate['period']);
|
||||
if ($loops < 10) {
|
||||
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
|
||||
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
|
||||
[$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']);
|
||||
[$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']);
|
||||
}
|
||||
$title = Navigation::periodShow($currentDate['start'], $currentDate['period']);
|
||||
[$transactions, $spent] = $this->filterTransactionsByType(TransactionTypeEnum::WITHDRAWAL, $transactions, $currentDate['start'], $currentDate['end']);
|
||||
[$transactions, $earned] = $this->filterTransactionsByType(TransactionTypeEnum::DEPOSIT, $transactions, $currentDate['start'], $currentDate['end']);
|
||||
[$transactions, $transferredAway] = $this->filterTransfers('away', $transactions, $currentDate['start'], $currentDate['end']);
|
||||
[$transactions, $transferredIn] = $this->filterTransfers('in', $transactions, $currentDate['start'], $currentDate['end']);
|
||||
$entries[]
|
||||
= [
|
||||
'title' => $title,
|
||||
@@ -129,8 +129,9 @@ trait PeriodOverview
|
||||
];
|
||||
++$loops;
|
||||
}
|
||||
$timer->stop('account-period-loop');
|
||||
$cache->store($entries);
|
||||
Timer::stop('account-period-total');
|
||||
$timer->stop('account-period-total');
|
||||
Log::debug('End of getAccountPeriodOverview()');
|
||||
|
||||
return $entries;
|
||||
@@ -138,7 +139,8 @@ trait PeriodOverview
|
||||
|
||||
private function filterTransactionsByType(TransactionTypeEnum $type, array $transactions, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$result = [];
|
||||
$result = [];
|
||||
$filtered = [];
|
||||
|
||||
/**
|
||||
* @var int $index
|
||||
@@ -146,38 +148,46 @@ trait PeriodOverview
|
||||
*/
|
||||
foreach ($transactions as $index => $item) {
|
||||
$date = Carbon::parse($item['date']);
|
||||
if ($item['type'] === $type->value && $date >= $start && $date <= $end) {
|
||||
$fits = $item['type'] === $type->value && $date >= $start && $date <= $end;
|
||||
if ($fits) {
|
||||
$result[] = $item;
|
||||
unset($transactions[$index]);
|
||||
}
|
||||
if (!$fits) {
|
||||
$filtered[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return [$transactions, $result];
|
||||
return [$filtered, $result];
|
||||
}
|
||||
|
||||
private function filterTransfers(string $direction, array $transactions, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$result = [];
|
||||
$result = [];
|
||||
$filtered = [];
|
||||
|
||||
/**
|
||||
* @var int $index
|
||||
* @var array $item
|
||||
*/
|
||||
foreach ($transactions as $index => $item) {
|
||||
$date = Carbon::parse($item['date']);
|
||||
$date = Carbon::parse($item['date']);
|
||||
if ($date >= $start && $date <= $end) {
|
||||
if ('away' === $direction && -1 === bccomp((string) $item['amount'], '0')) {
|
||||
if ('away' === $direction && -1 === bccomp((string)$item['amount'], '0')) {
|
||||
$result[] = $item;
|
||||
unset($transactions[$index]);
|
||||
|
||||
continue;
|
||||
}
|
||||
if ('in' === $direction && 1 === bccomp((string) $item['amount'], '0')) {
|
||||
if ('in' === $direction && 1 === bccomp((string)$item['amount'], '0')) {
|
||||
$result[] = $item;
|
||||
unset($transactions[$index]);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$filtered[] = $item;
|
||||
}
|
||||
|
||||
return [$transactions, $result];
|
||||
return [$filtered, $result];
|
||||
}
|
||||
|
||||
private function groupByCurrency(array $journals): array
|
||||
@@ -186,7 +196,7 @@ trait PeriodOverview
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
$currencyId = (int) $journal['currency_id'];
|
||||
$currencyId = (int)$journal['currency_id'];
|
||||
$currencyCode = $journal['currency_code'];
|
||||
$currencyName = $journal['currency_name'];
|
||||
$currencySymbol = $journal['currency_symbol'];
|
||||
@@ -203,7 +213,7 @@ trait PeriodOverview
|
||||
$currencyDecimalPlaces = $this->primaryCurrency->decimal_places;
|
||||
}
|
||||
if ($this->convertToPrimary && $currencyId !== $this->primaryCurrency->id && $foreignCurrencyId === $this->primaryCurrency->id) {
|
||||
$currencyId = (int) $foreignCurrencyId;
|
||||
$currencyId = (int)$foreignCurrencyId;
|
||||
$currencyCode = $journal['foreign_currency_code'];
|
||||
$currencyName = $journal['foreign_currency_name'];
|
||||
$currencySymbol = $journal['foreign_currency_symbol'];
|
||||
@@ -235,7 +245,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getCategoryPeriodOverview(Category $category, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$range = Navigation::getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for entries with their amounts.
|
||||
@@ -251,7 +261,7 @@ trait PeriodOverview
|
||||
}
|
||||
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
|
||||
// collect all expenses in this period:
|
||||
@@ -281,7 +291,7 @@ trait PeriodOverview
|
||||
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
||||
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
|
||||
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
|
||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
|
||||
$entries[]
|
||||
= [
|
||||
'transactions' => 0,
|
||||
@@ -327,7 +337,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getNoBudgetPeriodOverview(Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$range = Navigation::getViewRange(true);
|
||||
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
@@ -342,7 +352,7 @@ trait PeriodOverview
|
||||
}
|
||||
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
|
||||
// get all expenses without a budget.
|
||||
@@ -353,7 +363,7 @@ trait PeriodOverview
|
||||
|
||||
foreach ($dates as $currentDate) {
|
||||
$set = $this->filterJournalsByDate($journals, $currentDate['start'], $currentDate['end']);
|
||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
|
||||
$entries[]
|
||||
= [
|
||||
'title' => $title,
|
||||
@@ -380,17 +390,17 @@ trait PeriodOverview
|
||||
protected function getNoCategoryPeriodOverview(Carbon $theDate): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in getNoCategoryPeriodOverview(%s)', $theDate->format('Y-m-d')));
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$range = Navigation::getViewRange(true);
|
||||
$first = $this->journalRepos->firstNull();
|
||||
$start = null === $first ? new Carbon() : $first->date;
|
||||
$end = clone $theDate;
|
||||
$end = app('navigation')->endOfPeriod($end, $range);
|
||||
$end = Navigation::endOfPeriod($end, $range);
|
||||
|
||||
app('log')->debug(sprintf('Start for getNoCategoryPeriodOverview() is %s', $start->format('Y-m-d')));
|
||||
app('log')->debug(sprintf('End for getNoCategoryPeriodOverview() is %s', $end->format('Y-m-d')));
|
||||
|
||||
// properties for cache
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
|
||||
// collect all expenses in this period:
|
||||
@@ -422,7 +432,7 @@ trait PeriodOverview
|
||||
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
||||
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
|
||||
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
|
||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
|
||||
$entries[]
|
||||
= [
|
||||
'title' => $title,
|
||||
@@ -445,7 +455,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getTagPeriodOverview(Tag $tag, Carbon $start, Carbon $end): array // period overview for tags.
|
||||
{
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$range = Navigation::getViewRange(true);
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
// properties for cache
|
||||
@@ -459,7 +469,7 @@ trait PeriodOverview
|
||||
}
|
||||
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
|
||||
// collect all expenses in this period:
|
||||
@@ -495,7 +505,7 @@ trait PeriodOverview
|
||||
$spent = $this->filterJournalsByDate($spentSet, $currentDate['start'], $currentDate['end']);
|
||||
$earned = $this->filterJournalsByDate($earnedSet, $currentDate['start'], $currentDate['end']);
|
||||
$transferred = $this->filterJournalsByDate($transferSet, $currentDate['start'], $currentDate['end']);
|
||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
|
||||
$entries[]
|
||||
= [
|
||||
'transactions' => 0,
|
||||
@@ -540,7 +550,7 @@ trait PeriodOverview
|
||||
*/
|
||||
protected function getTransactionPeriodOverview(string $transactionType, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$range = app('navigation')->getViewRange(true);
|
||||
$range = Navigation::getViewRange(true);
|
||||
$types = config(sprintf('firefly.transactionTypesByType.%s', $transactionType));
|
||||
[$start, $end] = $end < $start ? [$end, $start] : [$start, $end];
|
||||
|
||||
@@ -555,7 +565,7 @@ trait PeriodOverview
|
||||
}
|
||||
|
||||
/** @var array $dates */
|
||||
$dates = app('navigation')->blockPeriods($start, $end, $range);
|
||||
$dates = Navigation::blockPeriods($start, $end, $range);
|
||||
$entries = [];
|
||||
$spent = [];
|
||||
$earned = [];
|
||||
@@ -567,7 +577,7 @@ trait PeriodOverview
|
||||
$loops = 0;
|
||||
|
||||
foreach ($dates as $currentDate) {
|
||||
$title = app('navigation')->periodShow($currentDate['end'], $currentDate['period']);
|
||||
$title = Navigation::periodShow($currentDate['end'], $currentDate['period']);
|
||||
|
||||
if ($loops < 10) {
|
||||
// set to correct array
|
||||
@@ -582,14 +592,14 @@ trait PeriodOverview
|
||||
}
|
||||
}
|
||||
$entries[]
|
||||
= [
|
||||
'title' => $title,
|
||||
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||
'spent' => $this->groupByCurrency($spent),
|
||||
'earned' => $this->groupByCurrency($earned),
|
||||
'transferred' => $this->groupByCurrency($transferred),
|
||||
];
|
||||
= [
|
||||
'title' => $title,
|
||||
'route' => route('transactions.index', [$transactionType, $currentDate['start']->format('Y-m-d'), $currentDate['end']->format('Y-m-d')]),
|
||||
'total_transactions' => count($spent) + count($earned) + count($transferred),
|
||||
'spent' => $this->groupByCurrency($spent),
|
||||
'earned' => $this->groupByCurrency($earned),
|
||||
'transferred' => $this->groupByCurrency($transferred),
|
||||
];
|
||||
++$loops;
|
||||
}
|
||||
|
||||
@@ -605,7 +615,7 @@ trait PeriodOverview
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
if ($account->id === (int) $journal['source_account_id']) {
|
||||
if ($account->id === (int)$journal['source_account_id']) {
|
||||
$return[] = $journal;
|
||||
}
|
||||
}
|
||||
@@ -622,7 +632,7 @@ trait PeriodOverview
|
||||
|
||||
/** @var array $journal */
|
||||
foreach ($journals as $journal) {
|
||||
if ($account->id === (int) $journal['destination_account_id']) {
|
||||
if ($account->id === (int)$journal['destination_account_id']) {
|
||||
$return[] = $journal;
|
||||
}
|
||||
}
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
@@ -32,12 +33,16 @@ use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Location;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
@@ -48,35 +53,32 @@ use Override;
|
||||
*/
|
||||
class AccountEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private array $accountIds;
|
||||
private array $accountTypeIds;
|
||||
private array $accountTypes;
|
||||
private array $ids = [];
|
||||
private array $accountTypeIds = [];
|
||||
private array $accountTypes = [];
|
||||
private Collection $collection;
|
||||
private array $currencies;
|
||||
private array $locations;
|
||||
private array $meta;
|
||||
private array $currencies = [];
|
||||
private array $locations = [];
|
||||
private array $meta = [];
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private array $notes;
|
||||
private array $openingBalances;
|
||||
private array $notes = [];
|
||||
private array $openingBalances = [];
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private array $lastActivities;
|
||||
private array $lastActivities = [];
|
||||
private ?Carbon $date = null;
|
||||
private bool $convertToPrimary;
|
||||
private array $balances = [];
|
||||
private array $objectGroups = [];
|
||||
private array $mappedObjects = [];
|
||||
|
||||
/**
|
||||
* TODO The account enricher must do conversion from and to the primary currency.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->accountIds = [];
|
||||
$this->openingBalances = [];
|
||||
$this->currencies = [];
|
||||
$this->accountTypeIds = [];
|
||||
$this->accountTypes = [];
|
||||
$this->meta = [];
|
||||
$this->notes = [];
|
||||
$this->lastActivities = [];
|
||||
$this->locations = [];
|
||||
// $this->repository = app(AccountRepositoryInterface::class);
|
||||
// $this->currencyRepository = app(CurrencyRepositoryInterface::class);
|
||||
// $this->start = null;
|
||||
// $this->end = null;
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
@@ -99,26 +101,28 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
// prep local fields
|
||||
$this->collection = $collection;
|
||||
$this->collectAccountIds();
|
||||
$this->collectIds();
|
||||
$this->getAccountTypes();
|
||||
$this->collectMetaData();
|
||||
$this->collectNotes();
|
||||
$this->collectLastActivities();
|
||||
$this->collectLocations();
|
||||
$this->collectOpeningBalances();
|
||||
$this->collectObjectGroups();
|
||||
$this->collectBalances();
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
private function collectAccountIds(): void
|
||||
private function collectIds(): void
|
||||
{
|
||||
/** @var Account $account */
|
||||
foreach ($this->collection as $account) {
|
||||
$this->accountIds[] = (int) $account->id;
|
||||
$this->accountTypeIds[] = (int) $account->account_type_id;
|
||||
$this->ids[] = (int)$account->id;
|
||||
$this->accountTypeIds[] = (int)$account->account_type_id;
|
||||
}
|
||||
$this->accountIds = array_unique($this->accountIds);
|
||||
$this->ids = array_unique($this->ids);
|
||||
$this->accountTypeIds = array_unique($this->accountTypeIds);
|
||||
}
|
||||
|
||||
@@ -128,27 +132,29 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
/** @var AccountType $type */
|
||||
foreach ($types as $type) {
|
||||
$this->accountTypes[(int) $type->id] = $type->type;
|
||||
$this->accountTypes[(int)$type->id] = $type->type;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectMetaData(): void
|
||||
{
|
||||
$set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'BIC', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
|
||||
->whereIn('account_id', $this->accountIds)
|
||||
->whereIn('account_id', $this->ids)
|
||||
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray()
|
||||
;
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($set as $entry) {
|
||||
$this->meta[(int) $entry['account_id']][$entry['name']] = (string) $entry['data'];
|
||||
$this->meta[(int)$entry['account_id']][$entry['name']] = (string)$entry['data'];
|
||||
if ('currency_id' === $entry['name']) {
|
||||
$this->currencies[(int) $entry['data']] = true;
|
||||
$this->currencies[(int)$entry['data']] = true;
|
||||
}
|
||||
}
|
||||
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int) $currency->id] = $currency;
|
||||
if (count($this->currencies) > 0) {
|
||||
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int)$currency->id] = $currency;
|
||||
}
|
||||
}
|
||||
$this->currencies[0] = $this->primaryCurrency;
|
||||
foreach ($this->currencies as $id => $currency) {
|
||||
@@ -160,28 +166,28 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->accountIds)
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int) $note['noteable_id']] = (string) $note['text'];
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function collectLocations(): void
|
||||
{
|
||||
$locations = Location::query()->whereIn('locatable_id', $this->accountIds)
|
||||
$locations = Location::query()->whereIn('locatable_id', $this->ids)
|
||||
->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray()
|
||||
;
|
||||
foreach ($locations as $location) {
|
||||
$this->locations[(int) $location['locatable_id']]
|
||||
$this->locations[(int)$location['locatable_id']]
|
||||
= [
|
||||
'latitude' => (float) $location['latitude'],
|
||||
'longitude' => (float) $location['longitude'],
|
||||
'zoom_level' => (int) $location['zoom_level'],
|
||||
'latitude' => (float)$location['latitude'],
|
||||
'longitude' => (float)$location['longitude'],
|
||||
'zoom_level' => (int)$location['zoom_level'],
|
||||
];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations)));
|
||||
@@ -201,12 +207,12 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
;
|
||||
$journals = $collector->getExtractedJournals();
|
||||
foreach ($journals as $journal) {
|
||||
$this->openingBalances[(int) $journal['source_account_id']]
|
||||
$this->openingBalances[(int)$journal['source_account_id']]
|
||||
= [
|
||||
'amount' => Steam::negative($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
];
|
||||
$this->openingBalances[(int) $journal['destination_account_id']]
|
||||
$this->openingBalances[(int)$journal['destination_account_id']]
|
||||
= [
|
||||
'amount' => Steam::positive($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
@@ -227,64 +233,160 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$accountTypes = $this->accountTypes;
|
||||
$meta = $this->meta;
|
||||
$currencies = $this->currencies;
|
||||
$notes = $this->notes;
|
||||
$openingBalances = $this->openingBalances;
|
||||
$locations = $this->locations;
|
||||
$lastActivities = $this->lastActivities;
|
||||
$this->collection = $this->collection->map(function (Account $item) use ($accountTypes, $meta, $currencies, $notes, $openingBalances, $locations, $lastActivities) {
|
||||
$item->full_account_type = $accountTypes[(int) $item->account_type_id] ?? null;
|
||||
$accountMeta = [
|
||||
'currency' => null,
|
||||
'location' => [
|
||||
$this->collection = $this->collection->map(function (Account $item) {
|
||||
$id = (int)$item->id;
|
||||
$item->full_account_type = $this->accountTypes[(int)$item->account_type_id] ?? null;
|
||||
$meta = [
|
||||
'currency' => null,
|
||||
'location' => [
|
||||
'latitude' => null,
|
||||
'longitude' => null,
|
||||
'zoom_level' => null,
|
||||
],
|
||||
'object_group_id' => null,
|
||||
'object_group_order' => null,
|
||||
'object_group_title' => null,
|
||||
'opening_balance_date' => null,
|
||||
'opening_balance_amount' => null,
|
||||
'account_number' => null,
|
||||
'notes' => $notes[$id] ?? null,
|
||||
'last_activity' => $this->lastActivities[$id] ?? null,
|
||||
];
|
||||
if (array_key_exists((int) $item->id, $meta)) {
|
||||
foreach ($meta[(int) $item->id] as $name => $value) {
|
||||
$accountMeta[$name] = $value;
|
||||
}
|
||||
}
|
||||
// also add currency, if present.
|
||||
if (array_key_exists('currency_id', $accountMeta)) {
|
||||
$currencyId = (int) $accountMeta['currency_id'];
|
||||
$accountMeta['currency'] = $currencies[$currencyId];
|
||||
}
|
||||
|
||||
// if notes, add notes.
|
||||
if (array_key_exists($item->id, $notes)) {
|
||||
$accountMeta['notes'] = $notes[$item->id];
|
||||
}
|
||||
// if opening balance, add opening balance
|
||||
if (array_key_exists($item->id, $openingBalances)) {
|
||||
$accountMeta['opening_balance_date'] = $openingBalances[$item->id]['date'];
|
||||
$accountMeta['opening_balance_amount'] = $openingBalances[$item->id]['amount'];
|
||||
// add object group if available
|
||||
if (array_key_exists($id, $this->mappedObjects)) {
|
||||
$key = $this->mappedObjects[$id];
|
||||
$meta['object_group_id'] = $this->objectGroups[$key]['id'];
|
||||
$meta['object_group_title'] = $this->objectGroups[$key]['title'];
|
||||
$meta['object_group_order'] = $this->objectGroups[$key]['order'];
|
||||
}
|
||||
|
||||
// if location, add location:
|
||||
if (array_key_exists($item->id, $locations)) {
|
||||
$accountMeta['location'] = $locations[$item->id];
|
||||
if (array_key_exists($id, $this->locations)) {
|
||||
$meta['location'] = $this->locations[$id];
|
||||
}
|
||||
if (array_key_exists($item->id, $lastActivities)) {
|
||||
$accountMeta['last_activity'] = $lastActivities[$item->id];
|
||||
if (array_key_exists($id, $this->meta)) {
|
||||
foreach ($this->meta[$id] as $name => $value) {
|
||||
$meta[$name] = $value;
|
||||
}
|
||||
}
|
||||
$item->meta = $accountMeta;
|
||||
// also add currency, if present.
|
||||
if (array_key_exists('currency_id', $meta)) {
|
||||
$currencyId = (int)$meta['currency_id'];
|
||||
$meta['currency'] = $this->currencies[$currencyId];
|
||||
}
|
||||
|
||||
if (array_key_exists($id, $this->openingBalances)) {
|
||||
$meta['opening_balance_date'] = $this->openingBalances[$id]['date'];
|
||||
$meta['opening_balance_amount'] = $this->openingBalances[$id]['amount'];
|
||||
}
|
||||
|
||||
// add balances
|
||||
// get currencies:
|
||||
$currency = $this->primaryCurrency; // assume primary currency
|
||||
if (null !== $meta['currency']) {
|
||||
$currency = $meta['currency'];
|
||||
}
|
||||
|
||||
// get the current balance:
|
||||
$date = $this->getDate();
|
||||
// $finalBalance = Steam::finalAccountBalance($item, $date, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$finalBalance = $this->balances[$id];
|
||||
Log::debug(sprintf('Call finalAccountBalance(%s) with date/time "%s"', var_export($this->convertToPrimary, true), $date->toIso8601String()), $finalBalance);
|
||||
|
||||
// collect current balances:
|
||||
$currentBalance = Steam::bcround($finalBalance[$currency->code] ?? '0', $currency->decimal_places);
|
||||
$openingBalance = Steam::bcround($meta['opening_balance_amount'] ?? '0', $currency->decimal_places);
|
||||
$virtualBalance = Steam::bcround($account->virtual_balance ?? '0', $currency->decimal_places);
|
||||
$debtAmount = $meta['current_debt'] ?? null;
|
||||
|
||||
// set some pc_ default values to NULL:
|
||||
$pcCurrentBalance = null;
|
||||
$pcOpeningBalance = null;
|
||||
$pcVirtualBalance = null;
|
||||
$pcDebtAmount = null;
|
||||
|
||||
// convert to primary currency if needed:
|
||||
if ($this->convertToPrimary && $currency->id !== $this->primaryCurrency->id) {
|
||||
Log::debug(sprintf('Convert to primary, from %s to %s', $currency->code, $this->primaryCurrency->code));
|
||||
$converter = new ExchangeRateConverter();
|
||||
$pcCurrentBalance = $converter->convert($currency, $this->primaryCurrency, $date, $currentBalance);
|
||||
$pcOpeningBalance = $converter->convert($currency, $this->primaryCurrency, $date, $openingBalance);
|
||||
$pcVirtualBalance = $converter->convert($currency, $this->primaryCurrency, $date, $virtualBalance);
|
||||
$pcDebtAmount = null === $debtAmount ? null : $converter->convert($currency, $this->primaryCurrency, $date, $debtAmount);
|
||||
}
|
||||
if ($this->convertToPrimary && $currency->id === $this->primaryCurrency->id) {
|
||||
$pcCurrentBalance = $currentBalance;
|
||||
$pcOpeningBalance = $openingBalance;
|
||||
$pcVirtualBalance = $virtualBalance;
|
||||
$pcDebtAmount = $debtAmount;
|
||||
}
|
||||
|
||||
// set opening balance(s) to NULL if the date is null
|
||||
if (null === $meta['opening_balance_date']) {
|
||||
$openingBalance = null;
|
||||
$pcOpeningBalance = null;
|
||||
}
|
||||
$meta['balances'] = [
|
||||
'current_balance' => $currentBalance,
|
||||
'pc_current_balance' => $pcCurrentBalance,
|
||||
'opening_balance' => $openingBalance,
|
||||
'pc_opening_balance' => $pcOpeningBalance,
|
||||
'virtual_balance' => $virtualBalance,
|
||||
'pc_virtual_balance' => $pcVirtualBalance,
|
||||
'debt_amount' => $debtAmount,
|
||||
'pc_debt_amount' => $pcDebtAmount,
|
||||
];
|
||||
// end add balances
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
public function setPrimaryCurrency(TransactionCurrency $primary): void
|
||||
{
|
||||
$this->primaryCurrency = $primary;
|
||||
}
|
||||
|
||||
private function collectLastActivities(): void
|
||||
{
|
||||
$this->lastActivities = Steam::getLastActivities($this->accountIds);
|
||||
$this->lastActivities = Steam::getLastActivities($this->ids);
|
||||
}
|
||||
|
||||
private function collectBalances(): void
|
||||
{
|
||||
$this->balances = Steam::accountsBalancesOptimized($this->collection, $this->getDate(), $this->primaryCurrency, $this->convertToPrimary);
|
||||
}
|
||||
|
||||
private function collectObjectGroups(): void
|
||||
{
|
||||
$set = DB::table('object_groupables')
|
||||
->whereIn('object_groupable_id', $this->ids)
|
||||
->where('object_groupable_type', Account::class)
|
||||
->get(['object_groupable_id', 'object_group_id'])
|
||||
;
|
||||
|
||||
$ids = array_unique($set->pluck('object_group_id')->toArray());
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
|
||||
}
|
||||
|
||||
$groups = ObjectGroup::whereIn('id', $ids)->get(['id', 'title', 'order'])->toArray();
|
||||
foreach ($groups as $group) {
|
||||
$group['id'] = (int)$group['id'];
|
||||
$group['order'] = (int)$group['order'];
|
||||
$this->objectGroups[(int)$group['id']] = $group;
|
||||
}
|
||||
}
|
||||
|
||||
public function setDate(?Carbon $date): void
|
||||
{
|
||||
$this->date = $date;
|
||||
}
|
||||
|
||||
public function getDate(): Carbon
|
||||
{
|
||||
if (null === $this->date) {
|
||||
return today();
|
||||
}
|
||||
|
||||
return $this->date;
|
||||
}
|
||||
}
|
||||
|
179
app/Support/JsonApi/Enrichments/AvailableBudgetEnrichment.php
Normal file
179
app/Support/JsonApi/Enrichments/AvailableBudgetEnrichment.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* AvailableBudgetEnrichment.php
|
||||
* Copyright (c) 2025 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\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\NoBudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private bool $convertToPrimary;
|
||||
private array $ids = [];
|
||||
private array $currencyIds = [];
|
||||
private array $currencies = [];
|
||||
private Collection $collection;
|
||||
private array $spentInBudgets = [];
|
||||
private array $spentOutsideBudgets = [];
|
||||
private array $pcSpentInBudgets = [];
|
||||
private array $pcSpentOutsideBudgets = [];
|
||||
private readonly NoBudgetRepositoryInterface $noBudgetRepository;
|
||||
private readonly OperationsRepositoryInterface $opsRepository;
|
||||
private readonly BudgetRepositoryInterface $repository;
|
||||
|
||||
|
||||
private ?Carbon $start = null;
|
||||
private ?Carbon $end = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
$this->noBudgetRepository = app(NoBudgetRepositoryInterface::class);
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function enrich(Collection $collection): Collection
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectCurrencies();
|
||||
$this->collectSpentInfo();
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function enrichSingle(array|Model $model): array|Model
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
$collection = new Collection([$model]);
|
||||
$collection = $this->enrich($collection);
|
||||
|
||||
return $collection->first();
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->setUserGroup($user->userGroup);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function setUserGroup(UserGroup $userGroup): void
|
||||
{
|
||||
$this->userGroup = $userGroup;
|
||||
$this->noBudgetRepository->setUserGroup($userGroup);
|
||||
$this->opsRepository->setUserGroup($userGroup);
|
||||
$this->repository->setUserGroup($userGroup);
|
||||
}
|
||||
|
||||
private function collectIds(): void
|
||||
{
|
||||
/** @var AvailableBudget $availableBudget */
|
||||
foreach ($this->collection as $availableBudget) {
|
||||
$this->ids[] = (int)$availableBudget->id;
|
||||
$this->currencyIds[(int)$availableBudget->id] = (int)$availableBudget->transaction_currency_id;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
}
|
||||
|
||||
private function collectSpentInfo(): void
|
||||
{
|
||||
$start = $this->collection->min('start_date');
|
||||
$end = $this->collection->max('end_date');
|
||||
$allActive = $this->repository->getActiveBudgets();
|
||||
$spentInBudgets = $this->opsRepository->collectExpenses($start, $end, null, $allActive, null);
|
||||
$spentOutsideBudgets = $this->noBudgetRepository->collectExpenses($start, $end, null, null, null);
|
||||
foreach ($this->collection as $availableBudget) {
|
||||
$id = (int)$availableBudget->id;
|
||||
$currencyId = $this->currencyIds[$id];
|
||||
$currency = $this->currencies[$currencyId];
|
||||
$filteredSpentInBudgets = $this->opsRepository->sumCollectedExpenses($spentInBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, false);
|
||||
$filteredSpentOutsideBudgets = $this->opsRepository->sumCollectedExpenses($spentOutsideBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, false);
|
||||
$this->spentInBudgets[$id] = array_values($filteredSpentInBudgets);
|
||||
$this->spentOutsideBudgets[$id] = array_values($filteredSpentOutsideBudgets);
|
||||
|
||||
if (true === $this->convertToPrimary) {
|
||||
$pcFilteredSpentInBudgets = $this->opsRepository->sumCollectedExpenses($spentInBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, true);
|
||||
$pcFilteredSpentOutsideBudgets = $this->opsRepository->sumCollectedExpenses($spentOutsideBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, true);
|
||||
$this->pcSpentInBudgets[$id] = array_values($pcFilteredSpentInBudgets);
|
||||
$this->pcSpentOutsideBudgets[$id] = array_values($pcFilteredSpentOutsideBudgets);
|
||||
}
|
||||
|
||||
|
||||
// filter arrays on date.
|
||||
// send them to sumCollection thing.
|
||||
// save.
|
||||
}
|
||||
|
||||
// first collect, then filter and append.
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (AvailableBudget $item) {
|
||||
$id = (int)$item->id;
|
||||
$currencyId = $this->currencyIds[$id];
|
||||
$currency = $this->currencies[$currencyId];
|
||||
$meta = [
|
||||
'currency' => $currency,
|
||||
'spent_in_budgets' => $this->spentInBudgets[$id] ?? [],
|
||||
'pc_spent_in_budgets' => $this->pcSpentInBudgets[$id] ?? [],
|
||||
'spent_outside_budgets' => $this->spentOutsideBudgets[$id] ?? [],
|
||||
'pc_spent_outside_budgets' => $this->pcSpentOutsideBudgets[$id] ?? [],
|
||||
];
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
private function collectCurrencies(): void
|
||||
{
|
||||
$ids = array_unique(array_values($this->currencyIds));
|
||||
$set = TransactionCurrency::whereIn('id', $ids)->get();
|
||||
foreach ($set as $currency) {
|
||||
$this->currencies[(int)$currency->id] = $currency;
|
||||
}
|
||||
}
|
||||
}
|
198
app/Support/JsonApi/Enrichments/BudgetEnrichment.php
Normal file
198
app/Support/JsonApi/Enrichments/BudgetEnrichment.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BudgetEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private Collection $collection;
|
||||
private bool $convertToPrimary;
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private array $ids = [];
|
||||
private array $notes = [];
|
||||
private array $autoBudgets = [];
|
||||
private array $currencies = [];
|
||||
private ?Carbon $start = null;
|
||||
private ?Carbon $end = null;
|
||||
private array $spent = [];
|
||||
private array $pcSpent = [];
|
||||
private array $objectGroups = [];
|
||||
private array $mappedObjects = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
|
||||
public function enrich(Collection $collection): Collection
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectNotes();
|
||||
$this->collectAutoBudgets();
|
||||
$this->collectExpenses();
|
||||
$this->collectObjectGroups();
|
||||
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function enrichSingle(array|Model $model): array|Model
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
$collection = new Collection([$model]);
|
||||
$collection = $this->enrich($collection);
|
||||
|
||||
return $collection->first();
|
||||
}
|
||||
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->setUserGroup($user->userGroup);
|
||||
}
|
||||
|
||||
public function setUserGroup(UserGroup $userGroup): void
|
||||
{
|
||||
$this->userGroup = $userGroup;
|
||||
}
|
||||
|
||||
private function collectIds(): void
|
||||
{
|
||||
/** @var Budget $budget */
|
||||
foreach ($this->collection as $budget) {
|
||||
$this->ids[] = (int)$budget->id;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
}
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Budget::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (Budget $item) {
|
||||
$id = (int)$item->id;
|
||||
$meta = [
|
||||
'object_group_id' => null,
|
||||
'object_group_order' => null,
|
||||
'object_group_title' => null,
|
||||
'notes' => $this->notes[$id] ?? null,
|
||||
'currency' => $this->currencies[$id] ?? null,
|
||||
'auto_budget' => $this->autoBudgets[$id] ?? null,
|
||||
'spent' => $this->spent[$id] ?? null,
|
||||
'pc_spent' => $this->pcSpent[$id] ?? null,
|
||||
];
|
||||
|
||||
// add object group if available
|
||||
if (array_key_exists($id, $this->mappedObjects)) {
|
||||
$key = $this->mappedObjects[$id];
|
||||
$meta['object_group_id'] = $this->objectGroups[$key]['id'];
|
||||
$meta['object_group_title'] = $this->objectGroups[$key]['title'];
|
||||
$meta['object_group_order'] = $this->objectGroups[$key]['order'];
|
||||
}
|
||||
|
||||
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
private function collectAutoBudgets(): void
|
||||
{
|
||||
$set = AutoBudget::whereIn('budget_id', $this->ids)->with(['transactionCurrency'])->get();
|
||||
|
||||
/** @var AutoBudget $autoBudget */
|
||||
foreach ($set as $autoBudget) {
|
||||
$budgetId = (int)$autoBudget->budget_id;
|
||||
$this->currencies[$budgetId] = $autoBudget->transactionCurrency;
|
||||
$this->autoBudgets[$budgetId] = [
|
||||
'type' => (int)$autoBudget->auto_budget_type,
|
||||
'period' => $autoBudget->period,
|
||||
'amount' => $autoBudget->amount,
|
||||
'pc_amount' => $autoBudget->native_amount,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private function collectExpenses(): void
|
||||
{
|
||||
if (null !== $this->start && null !== $this->end) {
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$opsRepository->setUser($this->user);
|
||||
$opsRepository->setUserGroup($this->userGroup);
|
||||
// $spent = $this->beautify();
|
||||
// $set = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]))
|
||||
$expenses = $opsRepository->collectExpenses($this->start, $this->end, null, $this->collection, null);
|
||||
foreach ($this->collection as $item) {
|
||||
$id = (int)$item->id;
|
||||
$this->spent[$id] = array_values($opsRepository->sumCollectedExpensesByBudget($expenses, $item, false));
|
||||
$this->pcSpent[$id] = array_values($opsRepository->sumCollectedExpensesByBudget($expenses, $item, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setEnd(?Carbon $end): void
|
||||
{
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
public function setStart(?Carbon $start): void
|
||||
{
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
private function collectObjectGroups(): void
|
||||
{
|
||||
$set = DB::table('object_groupables')
|
||||
->whereIn('object_groupable_id', $this->ids)
|
||||
->where('object_groupable_type', Budget::class)
|
||||
->get(['object_groupable_id', 'object_group_id'])
|
||||
;
|
||||
|
||||
$ids = array_unique($set->pluck('object_group_id')->toArray());
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
|
||||
}
|
||||
|
||||
$groups = ObjectGroup::whereIn('id', $ids)->get(['id', 'title', 'order'])->toArray();
|
||||
foreach ($groups as $group) {
|
||||
$group['id'] = (int)$group['id'];
|
||||
$group['order'] = (int)$group['order'];
|
||||
$this->objectGroups[(int)$group['id']] = $group;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user