Merge branch 'release/v6.0.27'

This commit is contained in:
James Cole
2023-10-15 13:30:40 +02:00
242 changed files with 2543 additions and 1667 deletions

View File

@@ -8,16 +8,16 @@
"packages": [
{
"name": "composer/pcre",
"version": "3.1.0",
"version": "3.1.1",
"source": {
"type": "git",
"url": "https://github.com/composer/pcre.git",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2"
"reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
"reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2",
"url": "https://api.github.com/repos/composer/pcre/zipball/00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"reference": "00104306927c7a0919b4ced2aaa6782c1e61a3c9",
"shasum": ""
},
"require": {
@@ -59,7 +59,7 @@
],
"support": {
"issues": "https://github.com/composer/pcre/issues",
"source": "https://github.com/composer/pcre/tree/3.1.0"
"source": "https://github.com/composer/pcre/tree/3.1.1"
},
"funding": [
{
@@ -75,7 +75,7 @@
"type": "tidelift"
}
],
"time": "2022-11-17T09:50:14+00:00"
"time": "2023-10-11T07:11:09+00:00"
},
{
"name": "composer/semver",
@@ -226,16 +226,16 @@
},
{
"name": "friendsofphp/php-cs-fixer",
"version": "v3.28.0",
"version": "v3.35.1",
"source": {
"type": "git",
"url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git",
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff"
"reference": "ec1ccc264994b6764882669973ca435cf05bab08"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/113e09fea3d2306319ffaa2423fe3de768b28cff",
"reference": "113e09fea3d2306319ffaa2423fe3de768b28cff",
"url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ec1ccc264994b6764882669973ca435cf05bab08",
"reference": "ec1ccc264994b6764882669973ca435cf05bab08",
"shasum": ""
},
"require": {
@@ -268,8 +268,6 @@
"phpspec/prophecy": "^1.16",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"phpunitgoodpractices/polyfill": "^1.6",
"phpunitgoodpractices/traits": "^1.9.2",
"symfony/phpunit-bridge": "^6.2.3",
"symfony/yaml": "^5.4 || ^6.0"
},
@@ -309,7 +307,7 @@
],
"support": {
"issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues",
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.28.0"
"source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.35.1"
},
"funding": [
{
@@ -317,7 +315,7 @@
"type": "github"
}
],
"time": "2023-09-22T20:43:40+00:00"
"time": "2023-10-12T13:47:26+00:00"
},
{
"name": "psr/container",
@@ -917,16 +915,16 @@
},
{
"name": "symfony/finder",
"version": "v6.3.3",
"version": "v6.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e"
"reference": "a1b31d88c0e998168ca7792f222cbecee47428c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/9915db259f67d21eefee768c1abcf1cc61b1fc9e",
"reference": "9915db259f67d21eefee768c1abcf1cc61b1fc9e",
"url": "https://api.github.com/repos/symfony/finder/zipball/a1b31d88c0e998168ca7792f222cbecee47428c4",
"reference": "a1b31d88c0e998168ca7792f222cbecee47428c4",
"shasum": ""
},
"require": {
@@ -961,7 +959,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v6.3.3"
"source": "https://github.com/symfony/finder/tree/v6.3.5"
},
"funding": [
{
@@ -977,7 +975,7 @@
"type": "tidelift"
}
],
"time": "2023-07-31T08:31:44+00:00"
"time": "2023-09-26T12:56:25+00:00"
},
{
"name": "symfony/options-resolver",
@@ -1745,16 +1743,16 @@
},
{
"name": "symfony/string",
"version": "v6.3.2",
"version": "v6.3.5",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "53d1a83225002635bca3482fcbf963001313fb68"
"reference": "13d76d0fb049051ed12a04bef4f9de8715bea339"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/53d1a83225002635bca3482fcbf963001313fb68",
"reference": "53d1a83225002635bca3482fcbf963001313fb68",
"url": "https://api.github.com/repos/symfony/string/zipball/13d76d0fb049051ed12a04bef4f9de8715bea339",
"reference": "13d76d0fb049051ed12a04bef4f9de8715bea339",
"shasum": ""
},
"require": {
@@ -1811,7 +1809,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.3.2"
"source": "https://github.com/symfony/string/tree/v6.3.5"
},
"funding": [
{
@@ -1827,7 +1825,7 @@
"type": "tidelift"
}
],
"time": "2023-07-05T08:41:27+00:00"
"time": "2023-09-18T10:38:32+00:00"
}
],
"packages-dev": [],

View File

@@ -82,7 +82,8 @@ class AccountController extends Controller
$date = $data['date'] ?? today(config('app.timezone'));
$return = [];
$result = $this->repository->searchAccount((string)$query, $types, $data['limit']);
$result = $this->repository->searchAccount((string)$query, $types, $this->parameters->get('limit'));
// TODO this code is duplicated in the V2 Autocomplete controller, which means this code is due to be deprecated.
$defaultCurrency = app('amount')->getDefaultCurrency();

View File

@@ -58,7 +58,6 @@ class BillController extends Controller
/**
* Documentation for this endpoint is at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/autocomplete/getBillsAC
* TODO expand API to add active field.
*
* @param AutocompleteRequest $request
*
@@ -67,7 +66,7 @@ class BillController extends Controller
public function bills(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchBill($data['query'], $data['limit']);
$result = $this->repository->searchBill($data['query'], $this->parameters->get('limit'));
$filtered = $result->map(
static function (Bill $item) {
return [

View File

@@ -66,7 +66,7 @@ class BudgetController extends Controller
public function budgets(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchBudget($data['query'], $data['limit']);
$result = $this->repository->searchBudget($data['query'], $this->parameters->get('limit'));
$filtered = $result->map(
static function (Budget $item) {
return [

View File

@@ -66,7 +66,7 @@ class CategoryController extends Controller
public function categories(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchCategory($data['query'], $data['limit']);
$result = $this->repository->searchCategory($data['query'], $this->parameters->get('limit'));
$filtered = $result->map(
static function (Category $item) {
return [

View File

@@ -66,7 +66,7 @@ class CurrencyController extends Controller
public function currencies(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$collection = $this->repository->searchCurrency($data['query'], $data['limit']);
$collection = $this->repository->searchCurrency($data['query'], $this->parameters->get('limit'));
$result = [];
/** @var TransactionCurrency $currency */
@@ -95,7 +95,7 @@ class CurrencyController extends Controller
public function currenciesWithCode(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$collection = $this->repository->searchCurrency($data['query'], $data['limit']);
$collection = $this->repository->searchCurrency($data['query'], $this->parameters->get('limit'));
$result = [];
/** @var TransactionCurrency $currency */

View File

@@ -67,7 +67,7 @@ class ObjectGroupController extends Controller
{
$data = $request->getData();
$return = [];
$result = $this->repository->search($data['query'], $data['limit']);
$result = $this->repository->search($data['query'], $this->parameters->get('limit'));
/** @var ObjectGroup $objectGroup */
foreach ($result as $objectGroup) {

View File

@@ -70,7 +70,7 @@ class PiggyBankController extends Controller
public function piggyBanks(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $data['limit']);
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
$defaultCurrency = app('amount')->getDefaultCurrency();
$response = [];
@@ -105,7 +105,7 @@ class PiggyBankController extends Controller
public function piggyBanksWithBalance(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $data['limit']);
$piggies = $this->piggyRepository->searchPiggyBank($data['query'], $this->parameters->get('limit'));
$defaultCurrency = app('amount')->getDefaultCurrency();
$response = [];
/** @var PiggyBank $piggy */

View File

@@ -64,7 +64,7 @@ class RecurrenceController extends Controller
public function recurring(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$recurrences = $this->repository->searchRecurrence($data['query'], $data['limit']);
$recurrences = $this->repository->searchRecurrence($data['query'], $this->parameters->get('limit'));
$response = [];
/** @var Recurrence $recurrence */

View File

@@ -63,7 +63,7 @@ class RuleController extends Controller
public function rules(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$rules = $this->repository->searchRule($data['query'], $data['limit']);
$rules = $this->repository->searchRule($data['query'], $this->parameters->get('limit'));
$response = [];
/** @var Rule $rule */

View File

@@ -63,7 +63,7 @@ class RuleGroupController extends Controller
public function ruleGroups(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$groups = $this->repository->searchRuleGroup($data['query'], $data['limit']);
$groups = $this->repository->searchRuleGroup($data['query'], $this->parameters->get('limit'));
$response = [];
/** @var RuleGroup $group */

View File

@@ -67,7 +67,7 @@ class TagController extends Controller
{
$data = $request->getData();
$result = $this->repository->searchTags($data['query'], $data['limit']);
$result = $this->repository->searchTags($data['query'], $this->parameters->get('limit'));
$array = [];
/** @var Tag $tag */
foreach ($result as $tag) {

View File

@@ -71,7 +71,7 @@ class TransactionController extends Controller
public function transactions(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']);
$result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit'));
// limit and unique
$filtered = $result->unique('description');
@@ -113,7 +113,7 @@ class TransactionController extends Controller
}
}
if (!is_numeric($data['query'])) {
$result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']);
$result = $this->repository->searchJournalDescriptions($data['query'], $this->parameters->get('limit'));
}
// limit and unique

View File

@@ -62,7 +62,7 @@ class TransactionTypeController extends Controller
public function transactionTypes(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$types = $this->repository->searchTypes($data['query'], $data['limit']);
$types = $this->repository->searchTypes($data['query'], $this->parameters->get('limit'));
$array = [];
/** @var TransactionType $type */

View File

@@ -61,9 +61,9 @@ abstract class Controller extends BaseController
{
// get global parameters
$this->allowedSort = config('firefly.allowed_sort_parameters');
$this->parameters = $this->getParameters();
$this->middleware(
function ($request, $next) {
$this->parameters = $this->getParameters();
if (auth()->check()) {
$language = app('steam')->getLanguage();
app()->setLocale($language);
@@ -137,6 +137,11 @@ abstract class Controller extends BaseController
if (null !== $value) {
$bag->set($integer, (int)$value);
}
if (null === $value && 'limit' === $integer && auth()->check()) {
// set default for user:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}
}
// sort fields:

View File

@@ -81,7 +81,7 @@ class ListController extends Controller
public function attachments(Account $account): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttachments($account);
$count = $collection->count();
@@ -116,7 +116,7 @@ class ListController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->getPiggyBanks($account);
@@ -152,15 +152,9 @@ class ListController extends Controller
*/
public function transactions(Request $request, Account $account): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
// user can overrule page size with limit parameter.
$limit = $this->parameters->get('limit');
if (null !== $limit && $limit > 0) {
$pageSize = $limit;
}
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = $this->getManager();
/** @var User $admin */
@@ -172,8 +166,11 @@ class ListController extends Controller
$collector->setUser($admin)->setAccounts(new Collection([$account]))
->withAPIInformation()->setLimit($pageSize)->setPage($this->parameters->get('page'))->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();

View File

@@ -84,7 +84,7 @@ class ShowController extends Controller
// types to get, page size:
$types = $this->mapAccountTypes($this->parameters->get('type'));
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of accounts. Count it and split it.
$this->repository->resetAccountOrder();

View File

@@ -123,7 +123,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of attachments. Count it and split it.
$collection = $this->repository->get();

View File

@@ -76,7 +76,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');

View File

@@ -80,7 +80,7 @@ class ListController extends Controller
public function attachments(Bill $bill): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttachments($bill);
$count = $collection->count();
@@ -116,7 +116,7 @@ class ListController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->getRulesForBill($bill);
@@ -151,7 +151,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, Bill $bill): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -177,9 +177,11 @@ class ListController extends Controller
// set types of transactions to return.
->setTypes($types);
// do parameter stuff on new group collector.
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
// get paginator.

View File

@@ -73,7 +73,7 @@ class ShowController extends Controller
$this->repository->correctOrder();
$bills = $this->repository->getBills();
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$count = $bills->count();
$bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));

View File

@@ -82,7 +82,7 @@ class ListController extends Controller
public function attachments(Budget $budget): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttachments($budget);
$count = $collection->count();
@@ -116,7 +116,7 @@ class ListController extends Controller
public function budgetLimits(Budget $budget): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$this->parameters->set('budget_id', $budget->id);
$collection = $this->blRepository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end'));
$count = $collection->count();
@@ -148,13 +148,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, Budget $budget): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// user can overrule page size with limit parameter.
$limit = $this->parameters->get('limit');
if (null !== $limit && $limit > 0) {
$pageSize = $limit;
}
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -181,8 +175,11 @@ class ListController extends Controller
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
@@ -211,13 +208,7 @@ class ListController extends Controller
*/
public function withoutBudget(Request $request): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// user can overrule page size with limit parameter.
$limit = $this->parameters->get('limit');
if (null !== $limit && $limit > 0) {
$pageSize = $limit;
}
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -244,8 +235,11 @@ class ListController extends Controller
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();

View File

@@ -77,7 +77,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->getBudgets();

View File

@@ -80,7 +80,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, Budget $budget, BudgetLimit $budgetLimit): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);

View File

@@ -85,7 +85,7 @@ class ShowController extends Controller
{
$manager = $this->getManager();
$manager->parseIncludes('budget');
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->blRepository->getBudgetLimits($budget, $this->parameters->get('start'), $this->parameters->get('end'));
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
@@ -117,7 +117,7 @@ class ShowController extends Controller
{
$manager = $this->getManager();
$manager->parseIncludes('budget');
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->blRepository->getAllBudgetLimits($this->parameters->get('start'), $this->parameters->get('end'));
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -77,7 +77,7 @@ class ListController extends Controller
public function attachments(Category $category): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttachments($category);
$count = $collection->count();
@@ -112,7 +112,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, Category $category): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -138,8 +138,11 @@ class ListController extends Controller
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();

View File

@@ -73,7 +73,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->getCategories();

View File

@@ -77,7 +77,7 @@ class ListController extends Controller
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getBills($objectGroup);
$count = $collection->count();
@@ -114,7 +114,7 @@ class ListController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getPiggyBanks($objectGroup);

View File

@@ -79,7 +79,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$this->repository->resetOrder();
$collection = $this->repository->get();

View File

@@ -71,7 +71,7 @@ class ListController extends Controller
public function attachments(PiggyBank $piggyBank): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttachments($piggyBank);
$count = $collection->count();
@@ -105,7 +105,7 @@ class ListController extends Controller
public function piggyBankEvents(PiggyBank $piggyBank): JsonResponse
{
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$manager = $this->getManager();
$collection = $this->repository->getEvents($piggyBank);

View File

@@ -72,7 +72,7 @@ class ShowController extends Controller
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->getPiggyBanks();

View File

@@ -77,7 +77,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, Recurrence $recurrence): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -105,9 +105,13 @@ class ListController extends Controller
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();

View File

@@ -73,7 +73,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->get();

View File

@@ -77,7 +77,7 @@ class ShowController extends Controller
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->ruleRepository->getAll();

View File

@@ -75,7 +75,7 @@ class ListController extends Controller
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->ruleGroupRepository->getRules($group);

View File

@@ -75,7 +75,7 @@ class ShowController extends Controller
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of rule groups. Count it and split it.
$collection = $this->ruleGroupRepository->get();

View File

@@ -80,7 +80,7 @@ class ListController extends Controller
public function attachments(Tag $tag): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttachments($tag);
$count = $collection->count();
@@ -114,7 +114,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, Tag $tag): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -139,8 +139,11 @@ class ListController extends Controller
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.tags.transactions', [$tag->id]) . $this->buildParams());

View File

@@ -76,7 +76,7 @@ class ShowController extends Controller
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
$collection = $this->repository->get();

View File

@@ -78,7 +78,7 @@ class ListController extends Controller
public function attachments(TransactionGroup $transactionGroup): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = new Collection();
foreach ($transactionGroup->transactionJournals as $transactionJournal) {
$collection = $this->journalAPIRepository->getAttachments($transactionJournal)->merge($collection);
@@ -114,7 +114,7 @@ class ListController extends Controller
{
$manager = $this->getManager();
$collection = new Collection();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
foreach ($transactionGroup->transactionJournals as $transactionJournal) {
$collection = $this->journalAPIRepository->getPiggyBankEvents($transactionJournal)->merge($collection);
}
@@ -152,7 +152,7 @@ class ListController extends Controller
{
$manager = $this->getManager();
$collection = $this->journalAPIRepository->getJournalLinks($transactionJournal);
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$count = $collection->count();
$journalLinks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -58,7 +58,7 @@ class ShowController extends Controller
*/
public function index(Request $request): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);

View File

@@ -106,7 +106,7 @@ class ListController extends Controller
// types to get, page size:
$types = $this->mapAccountTypes($this->parameters->get('type'));
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of accounts. Count it and split it.
/** @var AccountRepositoryInterface $accountRepository */
@@ -153,7 +153,7 @@ class ListController extends Controller
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of available budgets. Count it and split it.
/** @var AvailableBudgetRepositoryInterface $abRepository */
@@ -193,7 +193,7 @@ class ListController extends Controller
/** @var BillRepositoryInterface $billRepos */
$billRepos = app(BillRepositoryInterface::class);
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$unfiltered = $billRepos->getBills();
// filter and paginate list:
@@ -236,7 +236,7 @@ class ListController extends Controller
$blRepository = app(BudgetLimitRepositoryInterface::class);
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $blRepository->getAllBudgetLimitsByCurrency($currency, $this->parameters->get('start'), $this->parameters->get('end'));
$count = $collection->count();
$budgetLimits = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
@@ -268,7 +268,7 @@ class ListController extends Controller
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
/** @var RecurringRepositoryInterface $recurringRepos */
@@ -319,7 +319,7 @@ class ListController extends Controller
public function rules(TransactionCurrency $currency): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of budgets. Count it and split it.
/** @var RuleRepositoryInterface $ruleRepos */
@@ -371,7 +371,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, TransactionCurrency $currency): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -396,8 +396,11 @@ class ListController extends Controller
->setPage($this->parameters->get('page'))
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.currencies.transactions', [$currency->code]) . $this->buildParams());

View File

@@ -78,7 +78,7 @@ class ShowController extends Controller
*/
public function index(): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAll();
$count = $collection->count();
// slice them:

View File

@@ -85,7 +85,7 @@ class ShowController extends Controller
$name = $request->get('name');
// types to get, page size:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$linkType = $this->repository->findByName($name);
// get list of transaction links. Count it and split it.

View File

@@ -78,7 +78,7 @@ class ListController extends Controller
*/
public function transactions(Request $request, LinkType $linkType): JsonResponse
{
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
@@ -106,8 +106,11 @@ class ListController extends Controller
->setPage($this->parameters->get('page'))
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
if (null !== $this->parameters->get('start')) {
$collector->setStart($this->parameters->get('start'));
}
if (null !== $this->parameters->get('end')) {
$collector->setEnd($this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());

View File

@@ -78,7 +78,7 @@ class ShowController extends Controller
{
// create some objects:
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
// get list of accounts. Count it and split it.
$collection = $this->repository->get();

View File

@@ -53,8 +53,7 @@ class TransactionController extends Controller
$manager = $this->getManager();
$fullQuery = (string)$request->get('query');
$page = 0 === (int)$request->get('page') ? 1 : (int)$request->get('page');
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = 0 === (int)$request->get('limit') ? $pageSize : (int)$request->get('limit');
$pageSize = $this->parameters->get('limit');
$searcher->parseQuery($fullQuery);
$searcher->setPage($page);
$searcher->setLimit($pageSize);

View File

@@ -236,6 +236,7 @@ class BasicController extends Controller
*/
private function getBillInformation(Carbon $start, Carbon $end): array
{
app('log')->debug(sprintf('Now in getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
/*
* Since both this method and the chart use the exact same data, we can suffice
* with calling the one method in the bill repository that will get this amount.
@@ -281,7 +282,7 @@ class BasicController extends Controller
'sub_title' => '',
];
}
app('log')->debug(sprintf('Done with getBillInformation("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d-')));
return $return;
}

View File

@@ -101,7 +101,7 @@ class UserController extends Controller
public function index(): JsonResponse
{
// user preferences
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$manager = $this->getManager();
// build collection

View File

@@ -58,7 +58,7 @@ class PreferencesController extends Controller
$collection = app('preferences')->all();
$manager = $this->getManager();
$count = $collection->count();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$preferences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:

View File

@@ -76,7 +76,7 @@ class AttemptController extends Controller
}
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getAttempts($message);
$count = $collection->count();
$attempts = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -70,7 +70,7 @@ class MessageController extends Controller
public function index(Webhook $webhook): JsonResponse
{
$manager = $this->getManager();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$collection = $this->repository->getMessages($webhook);
$count = $collection->count();

View File

@@ -74,7 +74,7 @@ class ShowController extends Controller
{
$manager = $this->getManager();
$collection = $this->repository->all();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$count = $collection->count();
$webhooks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);

View File

@@ -46,8 +46,6 @@ class AutocompleteRequest extends FormRequest
if ('' !== $types) {
$array = explode(',', $types);
}
$limit = $this->convertInteger('limit');
$limit = 0 === $limit ? 10 : $limit;
// remove 'initial balance' from allowed types. its internal
$array = array_diff($array, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION]);
@@ -56,7 +54,6 @@ class AutocompleteRequest extends FormRequest
'types' => $array,
'query' => $this->convertString('query'),
'date' => $this->getCarbonDate('date'),
'limit' => $limit,
];
}
@@ -66,7 +63,6 @@ class AutocompleteRequest extends FormRequest
public function rules(): array
{
return [
'limit' => 'min:0|max:1337',
];
}
}

View File

@@ -32,7 +32,7 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use http\Env\Response;
use Illuminate\Http\JsonResponse;
/**
@@ -41,7 +41,6 @@ use Illuminate\Http\JsonResponse;
class AccountController extends Controller
{
use AccountFilter;
use ValidatesUserGroupTrait;
private AdminAccountRepositoryInterface $adminRepository;
private array $balanceTypes;
@@ -86,15 +85,14 @@ class AccountController extends Controller
*/
public function accounts(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $this->parameters->get('date') ?? today(config('app.timezone'));
$return = [];
$data = $request->getData();
$types = $data['types'];
$query = $data['query'];
$date = $this->parameters->get('date') ?? today(config('app.timezone'));
$result = $this->adminRepository->searchAccount((string)$query, $types, $data['limit']);
$defaultCurrency = app('amount')->getDefaultCurrency();
$allItems = [];
/** @var Account $account */
foreach ($result as $account) {
$nameWithBalance = $account->name;
@@ -104,11 +102,17 @@ class AccountController extends Controller
$balance = app('steam')->balance($account, $date);
$nameWithBalance = sprintf('%s (%s)', $account->name, app('amount')->formatAnything($currency, $balance, false));
}
$return[] = [
$type = (string)trans(sprintf('firefly.%s', $account->accountType->type));
$groupedResult[$type] = $groupedResult[$type] ?? [
'group ' => $type,
'items' => [],
];
$allItems[] = [
'id' => (string)$account->id,
'value' => (string)$account->id,
'name' => $account->name,
'name_with_balance' => $nameWithBalance,
'label' => $nameWithBalance,
'type' => $account->accountType->type,
'currency_id' => (string)$currency->id,
'currency_name' => $currency->name,
@@ -118,10 +122,9 @@ class AccountController extends Controller
];
}
// custom order.
usort(
$return,
function ($a, $b) {
$allItems,
function (array $a, array $b): int {
$order = [AccountType::ASSET, AccountType::REVENUE, AccountType::EXPENSE];
$pos_a = array_search($a['type'], $order, true);
$pos_b = array_search($b['type'], $order, true);
@@ -129,7 +132,6 @@ class AccountController extends Controller
return $pos_a - $pos_b;
}
);
return response()->json($return);
return response()->json($allItems);
}
}

View File

@@ -0,0 +1,94 @@
<?php
/*
* TransactionController.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V2\Controllers\Autocomplete;
use FireflyIII\Api\V2\Controllers\Controller;
use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepositoryInterface;
use Illuminate\Http\JsonResponse;
/**
* Class TransactionController
*/
class TransactionController extends Controller
{
private JournalRepositoryInterface $repository;
/**
* AccountController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
$this->repository = app(JournalRepositoryInterface::class);
$userGroup = $this->validateUserGroup($request);
if (null !== $userGroup) {
$this->repository->setUserGroup($userGroup);
}
return $next($request);
}
);
}
/**
* Documentation for this endpoint:
* TODO list of checks
* 1. use dates from ParameterBag
* 2. Request validates dates
* 3. Request includes user_group_id
* 4. Endpoint is documented.
* 5. Collector uses user_group_id
*
*
* @return JsonResponse
*/
public function transactionDescriptions(AutocompleteRequest $request): JsonResponse
{
$data = $request->getData();
$result = $this->repository->searchJournalDescriptions($data['query'], $data['limit']);
// limit and unique
$filtered = $result->unique('description');
$array = [];
/** @var TransactionJournal $journal */
foreach ($filtered as $journal) {
$array[] = [
'id' => (string)$journal->id,
'transaction_group_id' => (string)$journal->transaction_group_id,
'name' => $journal->description,
'description' => $journal->description,
];
}
return response()->json($array);
}
}

View File

@@ -27,6 +27,7 @@ namespace FireflyIII\Api\V2\Controllers;
use Carbon\Carbon;
use Carbon\Exceptions\InvalidDateException;
use Carbon\Exceptions\InvalidFormatException;
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
use FireflyIII\Transformers\V2\AbstractTransformer;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Pagination\LengthAwarePaginator;
@@ -48,8 +49,9 @@ use Symfony\Component\HttpFoundation\ParameterBag;
*/
class Controller extends BaseController
{
use ValidatesUserGroupTrait;
protected const CONTENT_TYPE = 'application/vnd.api+json';
protected int $pageSize;
protected ParameterBag $parameters;
/**
@@ -57,11 +59,14 @@ class Controller extends BaseController
*/
public function __construct()
{
$this->parameters = $this->getParameters();
$this->pageSize = 50;
if (auth()->check()) {
$this->pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
}
$this->middleware(
function ($request, $next) {
$this->parameters = $this->getParameters();
return $next($request);
}
);
}
/**
@@ -73,6 +78,7 @@ class Controller extends BaseController
private function getParameters(): ParameterBag
{
$bag = new ParameterBag();
$bag->set('limit', 50);
try {
$page = (int)request()->get('page');
} catch (ContainerExceptionInterface | NotFoundExceptionInterface $e) {
@@ -129,6 +135,11 @@ class Controller extends BaseController
if (null !== $value) {
$bag->set($integer, (int)$value);
}
if (null === $value && 'limit' === $integer && auth()->check()) {
// set default for user:
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$bag->set($integer, $pageSize);
}
}
// sort fields:

View File

@@ -74,7 +74,7 @@ class ShowController extends Controller
{
$this->repository->correctOrder();
$bills = $this->repository->getBills();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$count = $bills->count();
$bills = $bills->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($bills, $count, $pageSize, $this->parameters->get('page'));

View File

@@ -64,9 +64,9 @@ class ListController extends Controller
exit;
$collection = $this->repository->getActiveBudgets();
$total = $collection->count();
$collection->slice($this->pageSize * $this->parameters->get('page'), $this->pageSize);
$collection->slice($this->pageXSize * $this->parameters->get('page'), $this->pXageSize);
$paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($collection, $total, $this->pagXeSize, $this->parameters->get('page'));
$transformer = new BudgetTransformer();
return response()

View File

@@ -57,12 +57,13 @@ class ListController extends Controller
*/
public function index(DateRequest $request, Budget $budget): JsonResponse
{
$pageSize = $this->parameters->get('limit');
$dates = $request->getAll();
$collection = $this->repository->getBudgetLimits($budget, $dates['start'], $dates['end']);
$total = $collection->count();
$collection->slice($this->pageSize * $this->parameters->get('page'), $this->pageSize);
$collection->slice($pageSize * $this->parameters->get('page'), $pageSize);
$paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($collection, $total, $pageSize, $this->parameters->get('page'));
$transformer = new BudgetLimitTransformer();
return response()

View File

@@ -70,7 +70,7 @@ class ShowController extends Controller
public function index(Request $request): JsonResponse
{
$piggies = $this->repository->getPiggyBanks();
$pageSize = (int)app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$pageSize = $this->parameters->get('limit');
$count = $piggies->count();
$piggies = $piggies->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($piggies, $count, $pageSize, $this->parameters->get('page'));

View File

@@ -52,30 +52,28 @@ class AccountController extends Controller
public function list(ListRequest $request, Account $account): JsonResponse
{
// collect transactions:
$limit = $request->getLimit();
$page = $request->getPage();
$page = max($page, 1);
if ($limit > 0 && $limit <= $this->pageSize) {
$this->pageSize = $limit;
}
$page = $request->getPage();
$page = max($page, 1);
$pageSize = $this->parameters->get('limit');
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))
->withAPIInformation()
->setLimit($this->pageSize)
->setLimit($pageSize)
->setPage($page)
->setTypes($request->getTransactionTypes());
$start = $request->getStartDate();
$end = $request->getEndDate();
if (null !== $start) {
app('log')->debug(sprintf('Set start date to %s', $start->toIso8601String()));
$collector->setStart($start);
}
if (null !== $end) {
$collector->setEnd($start);
app('log')->debug(sprintf('Set end date to %s', $start->toIso8601String()));
$collector->setEnd($end);
}
$paginator = $collector->getPaginatedGroups();
@@ -83,7 +81,7 @@ class AccountController extends Controller
sprintf(
'%s?%s',
route('api.v2.accounts.transactions', [$account->id]),
$request->buildParams()
$request->buildParams($pageSize)
)
);

View File

@@ -42,20 +42,16 @@ class TransactionController extends Controller
public function list(ListRequest $request): JsonResponse
{
// collect transactions:
$limit = $request->getLimit();
$page = $request->getPage();
$page = max($page, 1);
if ($limit > 0 && $limit <= $this->pageSize) {
$this->pageSize = $limit;
}
$pageSize = $this->parameters->get('limit');
$page = $request->getPage();
$page = max($page, 1);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUserGroup(auth()->user()->userGroup)
->withAPIInformation()
->setLimit($this->pageSize)
->setLimit($pageSize)
->setPage($page)
->setTypes($request->getTransactionTypes());
@@ -72,11 +68,12 @@ class TransactionController extends Controller
// exit;
$paginator = $collector->getPaginatedGroups();
$params = $request->buildParams($pageSize);
$paginator->setPath(
sprintf(
'%s?%s',
route('api.v2.transactions.list'),
$request->buildParams()
$params
)
);

View File

@@ -64,6 +64,7 @@ class ShowController extends Controller
public function index(Request $request): JsonResponse
{
$collection = new Collection();
$pageSize = $this->parameters->get('limit');
// if the user has the system owner role, get all. Otherwise, get only the users' groups.
if (!auth()->user()->hasRole('owner')) {
$collection = $this->repository->get();
@@ -72,9 +73,9 @@ class ShowController extends Controller
$collection = $this->repository->getAll();
}
$count = $collection->count();
$userGroups = $collection->slice(($this->parameters->get('page') - 1) * $this->pageSize, $this->pageSize);
$userGroups = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
$paginator = new LengthAwarePaginator($userGroups, $count, $this->pageSize, $this->parameters->get('page'));
$paginator = new LengthAwarePaginator($userGroups, $count, $pageSize, $this->parameters->get('page'));
$transformer = new UserGroupTransformer();
$transformer->setParameters($this->parameters); // give params to transformer

View File

@@ -28,6 +28,7 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\User;
use FireflyIII\Validation\Administration\ValidatesAdministrationAccess;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
@@ -38,6 +39,7 @@ class AutocompleteRequest extends FormRequest
{
use ConvertsDataTypes;
use ChecksLogin;
protected array $acceptedRoles = [UserRoleEnum::MANAGE_TRANSACTIONS];
/**
@@ -75,21 +77,4 @@ class AutocompleteRequest extends FormRequest
'limit' => 'min:0|max:1337',
];
}
/**
* Configure the validator instance with special rules for after the basic validation rules.
*
* @param Validator $validator
*
* @return void
*/
public function withValidator(Validator $validator): void
{
$validator->after(
function (Validator $validator) {
// validate if the account can access this administration
$this->validateAdministration($validator, [UserRoleEnum::MANAGE_TRANSACTIONS]);
}
);
}
}

View File

@@ -43,10 +43,11 @@ class ListRequest extends FormRequest
/**
* @return string
*/
public function buildParams(): string
public function buildParams(int $pageSize): string
{
$array = [
'page' => $this->getPage(),
'page' => $this->getPage(),
'limit' => $pageSize,
];
$start = $this->getStartDate();
@@ -55,9 +56,6 @@ class ListRequest extends FormRequest
$array['start'] = $start->format('Y-m-d');
$array['end'] = $end->format('Y-m-d');
}
if (0 !== $this->getLimit()) {
$array['limit'] = $this->getLimit();
}
return http_build_query($array);
}
@@ -86,14 +84,6 @@ class ListRequest extends FormRequest
return $this->getCarbonDate('end');
}
/**
* @return int
*/
public function getLimit(): int
{
return $this->convertInteger('limit');
}
/**
* @return array
*/

View File

@@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Console\Commands\Correction;
use FireflyIII\Console\Commands\ShowsFriendlyMessages;
use FireflyIII\Enums\AccountTypeEnum;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Factory\AccountFactory;
use FireflyIII\Models\AccountType;
@@ -31,7 +32,8 @@ use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\JoinClause;
use JsonException;
/**
@@ -51,22 +53,78 @@ class FixAccountTypes extends Command
* Execute the console command.
*
* @return int
* @throws FireflyException
* @throws FireflyException|JsonException
*/
public function handle(): int
{
$this->stupidLaravel();
$this->factory = app(AccountFactory::class);
$this->expected = config('firefly.source_dests');
$journals = TransactionJournal::with(['TransactionType', 'transactions', 'transactions.account', 'transactions.account.accounttype'])->get();
foreach ($journals as $journal) {
$this->inspectJournal($journal);
$expected = config('firefly.source_dests');
$query = TransactionJournal::leftJoin('transaction_types', 'transaction_journals.transaction_type_id', '=', 'transaction_types.id')
->leftJoin(
'transactions as source',
static function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'source.transaction_journal_id')->where('source.amount', '<', 0);
}
)
->leftJoin(
'transactions as destination',
static function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'destination.transaction_journal_id')->where('destination.amount', '>', 0);
}
)
->leftJoin('accounts as source_account', 'source.account_id', '=', 'source_account.id')
->leftJoin('accounts as destination_account', 'destination.account_id', '=', 'destination_account.id')
->leftJoin('account_types as source_account_type', 'source_account.account_type_id', '=', 'source_account_type.id')
->leftJoin('account_types as destination_account_type', 'destination_account.account_type_id', '=', 'destination_account_type.id');
// list all valid combinations, those are allowed. So we select those which are broken.
$query->where(function (Builder $q) use ($expected) {
foreach ($expected as $transactionType => $info) {
foreach ($info as $source => $destinations) {
foreach ($destinations as $destination) {
$q->whereNot(function (Builder $q1) use ($transactionType, $source, $destination) {
$q1->where('transaction_types.type', $transactionType);
$q1->where('source_account_type.type', $source);
$q1->where('destination_account_type.type', $destination);
});
}
}
}
});
$resultSet = $query->get(
[
'transaction_journals.id',
//'transaction_type_id as type_id',
'transaction_types.type as journal_type',
//'source.id as source_transaction_id',
//'source_account.id as source_account_id',
//'source_account_type.id as source_account_type_id',
'source_account_type.type as source_account_type',
//'destination.id as destination_transaction_id',
//'destination_account.id as destination_account_id',
//'destination_account_type.id as destination_account_type_id',
'destination_account_type.type as destination_account_type',
]
);
if ($resultSet->count() > 0) {
$this->friendlyLine(sprintf('Found %d journals that need to be fixed.', $resultSet->count()));
foreach ($resultSet as $entry) {
app('log')->debug(sprintf('Now fixing journal #%d', $entry->id));
$journal = TransactionJournal::find((int)$entry->id);
if (null !== $journal) {
$this->inspectJournal($journal);
}
}
}
if (0 === $this->count) {
$this->friendlyPositive('All account types are OK');
}
if (0 !== $this->count) {
Log::debug(sprintf('%d journals had to be fixed.', $this->count));
app('log')->debug(sprintf('%d journals had to be fixed.', $this->count));
$this->friendlyInfo(sprintf('Acted on %d transaction(s)', $this->count));
}
@@ -74,11 +132,7 @@ class FixAccountTypes extends Command
}
/**
* Laravel will execute ALL __construct() methods for ALL commands whenever a SINGLE command is
* executed. This leads to noticeable slow-downs and class calls. To prevent this, this method should
* be called from the handle method instead of using the constructor to initialize the command.
*
* @return void
*/
private function stupidLaravel(): void
{
@@ -93,9 +147,10 @@ class FixAccountTypes extends Command
*/
private function inspectJournal(TransactionJournal $journal): void
{
app('log')->debug(sprintf('Now inspecting journal #%d', $journal->id));
$transactions = $journal->transactions()->count();
if (2 !== $transactions) {
Log::debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
app('log')->debug(sprintf('Journal has %d transactions, so can\'t fix.', $transactions));
$this->friendlyError(sprintf('Cannot inspect transaction journal #%d because it has %d transaction(s) instead of 2.', $journal->id, $transactions));
return;
@@ -109,20 +164,20 @@ class FixAccountTypes extends Command
$destAccountType = $destAccount->accountType->type;
if (!array_key_exists($type, $this->expected)) {
Log::info(sprintf('No source/destination info for transaction type %s.', $type));
app('log')->info(sprintf('No source/destination info for transaction type %s.', $type));
$this->friendlyError(sprintf('No source/destination info for transaction type %s.', $type));
return;
}
if (!array_key_exists($sourceAccountType, $this->expected[$type])) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
app('log')->debug(sprintf('[a] Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
return;
}
$expectedTypes = $this->expected[$type][$sourceAccountType];
if (!in_array($destAccountType, $expectedTypes, true)) {
Log::debug(sprintf('Going to fix journal #%d', $journal->id));
app('log')->debug(sprintf('[b] Going to fix journal #%d', $journal->id));
$this->fixJournal($journal, $type, $sourceTransaction, $destTransaction);
}
}
@@ -158,10 +213,11 @@ class FixAccountTypes extends Command
*/
private function fixJournal(TransactionJournal $journal, string $type, Transaction $source, Transaction $dest): void
{
app('log')->debug(sprintf('Going to fix journal #%d', $journal->id));
$this->count++;
// variables:
$combination = sprintf('%s%s%s', $type, $source->account->accountType->type, $dest->account->accountType->type);
app('log')->debug(sprintf('Combination is "%s"', $combination));
switch ($combination) {
case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::ASSET, AccountType::LOAN):
case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::ASSET, AccountType::DEBT):
@@ -172,10 +228,10 @@ class FixAccountTypes extends Command
$journal->save();
$message = sprintf('Converted transaction #%d from a transfer to a withdrawal.', $journal->id);
$this->friendlyInfo($message);
Log::debug($message);
app('log')->debug($message);
// check it again:
$this->inspectJournal($journal);
break;
return;
case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::LOAN, AccountType::ASSET):
case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::DEBT, AccountType::ASSET):
case sprintf('%s%s%s', TransactionType::TRANSFER, AccountType::MORTGAGE, AccountType::ASSET):
@@ -185,11 +241,11 @@ class FixAccountTypes extends Command
$journal->save();
$message = sprintf('Converted transaction #%d from a transfer to a deposit.', $journal->id);
$this->friendlyInfo($message);
Log::debug($message);
app('log')->debug($message);
// check it again:
$this->inspectJournal($journal);
break;
return;
case sprintf('%s%s%s', TransactionType::WITHDRAWAL, AccountType::ASSET, AccountType::REVENUE):
// withdrawals with a revenue account as destination instead of an expense account.
$this->factory->setUser($journal->user);
@@ -206,9 +262,9 @@ class FixAccountTypes extends Command
$result->name
);
$this->friendlyWarning($message);
Log::debug($message);
app('log')->debug($message);
$this->inspectJournal($journal);
break;
return;
case sprintf('%s%s%s', TransactionType::DEPOSIT, AccountType::EXPENSE, AccountType::ASSET):
// deposits with an expense account as source instead of a revenue account.
// find revenue account.
@@ -226,19 +282,61 @@ class FixAccountTypes extends Command
$result->name
);
$this->friendlyWarning($message);
Log::debug($message);
app('log')->debug($message);
$this->inspectJournal($journal);
break;
default:
$message = sprintf('The source account of %s #%d cannot be of type "%s".', $type, $journal->id, $source->account->accountType->type);
$this->friendlyError($message);
Log::debug($message);
return;
}
app('log')->debug(sprintf('Fallback to fix transaction journal #%d of type "%s".', $journal->id, $type));
$message = sprintf('The destination account of %s #%d cannot be of type "%s".', $type, $journal->id, $dest->account->accountType->type);
$this->friendlyError($message);
Log::debug($message);
// transaction has no valid source.
$validSources = array_keys($this->expected[$type]);
if (!in_array($source->account->accountType->type, $validSources, true)) {
app('log')->debug('Journal has no valid source.');
// perhaps we can create the account of type we need:
break;
if (in_array(AccountTypeEnum::REVENUE->value, $validSources, true)) {
app('log')->debug(sprintf('An account of type "%s" could be a valid source.', AccountTypeEnum::REVENUE->value));
$this->factory->setUser($journal->user);
$newSource = $this->factory->findOrCreate($source->account->name, AccountTypeEnum::REVENUE->value);
$source->account()->associate($newSource);
$source->save();
$this->friendlyPositive(sprintf('Firefly III gave transaction #%d a new source %s: #%d ("%s").', $journal->transaction_group_id, AccountTypeEnum::REVENUE->value, $newSource->id, $newSource->name));
app('log')->debug(sprintf('Associated account #%d with transaction #%d', $newSource->id, $source->id));
$this->inspectJournal($journal);
return;
}
if (!in_array(AccountTypeEnum::REVENUE->value, $validSources, true)) {
app('log')->debug('This transaction type has no source we can create. Just give error.');
$message = sprintf('The source account of %s #%d cannot be of type "%s". Firefly III cannot fix this. You may have to remove the transaction yourself.', $type, $journal->id, $source->account->accountType->type);
$this->friendlyError($message);
app('log')->debug($message);
}
}
// transaction has no valid destination:
$sourceType = $source->account->accountType->type;
$validDestinations = $this->expected[$type][$sourceType] ?? [];
if (!in_array($dest->account->accountType->type, $validDestinations, true)) {
app('log')->debug('Journal has no valid destination (perhaps because the source is also broken).');
// perhaps we can create the account of type we need:
if (in_array(AccountTypeEnum::EXPENSE->value, $validDestinations, true)) {
app('log')->debug(sprintf('An account of type "%s" could be a valid destination.', AccountTypeEnum::EXPENSE->value));
$this->factory->setUser($journal->user);
$newDestination = $this->factory->findOrCreate($dest->account->name, AccountTypeEnum::EXPENSE->value);
$dest->account()->associate($newDestination);
$dest->save();
$this->friendlyPositive(sprintf('Firefly III gave transaction #%d a new destination %s: #%d ("%s").', $journal->transaction_group_id, AccountTypeEnum::EXPENSE->value, $newDestination->id, $newDestination->name));
app('log')->debug(sprintf('Associated account #%d with transaction #%d', $newDestination->id, $source->id));
$this->inspectJournal($journal);
return;
}
if (!in_array(AccountTypeEnum::EXPENSE->value, $validSources, true)) {
app('log')->debug('This transaction type has no destination we can create. Just give error.');
$message = sprintf('The destination account of %s #%d cannot be of type "%s". Firefly III cannot fix this. You may have to remove the transaction yourself.', $type, $journal->id, $dest->account->accountType->type);
$this->friendlyError($message);
app('log')->debug($message);
return;
}
}
}
}

View File

@@ -31,7 +31,6 @@ use Illuminate\Console\Command;
/**
* Class CorrectionSkeleton
* TODO DONT FORGET TO ADD THIS TO THE DOCKER BUILD
*/
class TriggerCreditCalculation extends Command
{

View File

@@ -159,6 +159,7 @@ class ShowController extends Controller
$object = $manager->createData($resource)->toArray();
$object['data']['currency'] = $bill->transactionCurrency;
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setBill($bill)->setLimit($pageSize)->setPage($page)->withBudgetInformation()

View File

@@ -213,7 +213,7 @@ class ShowController extends Controller
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)->withAccountInformation()
->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation()->withCategoryInformation();
$groups = $collector->getPaginatedGroups();
$groups->setPath(route('budgets.show', [$budget->id, $budgetLimit->id]));
$groups->setPath(route('budgets.show.limit', [$budget->id, $budgetLimit->id]));
/** @var Carbon $start */
$start = session('first', today(config('app.timezone'))->startOfYear());
$end = today(config('app.timezone'));

View File

@@ -472,6 +472,7 @@ class AccountController extends Controller
*/
private function periodByCurrency(Carbon $start, Carbon $end, Account $account, TransactionCurrency $currency): array
{
app('log')->debug(sprintf('Now in periodByCurrency("%s", "%s", %s, "%s")', $start->format('Y-m-d'), $end->format('Y-m-d'), $account->id, $currency->code));
$locale = app('steam')->getLocale();
$step = $this->calculateStep($start, $end);
$result = [
@@ -481,6 +482,13 @@ class AccountController extends Controller
];
$entries = [];
$current = clone $start;
app('log')->debug(sprintf('Step is %s', $step));
// fix for issue https://github.com/firefly-iii/firefly-iii/issues/8041
// have to make sure this chart is always based on the balance at the END of the period.
// This period depends on the size of the chart
$current = app('navigation')->endOfX($current, $step, null);
app('log')->debug(sprintf('$current date is %s', $current->format('Y-m-d')));
if ('1D' === $step) {
// per day the entire period, balance for every day.
$format = (string)trans('config.month_and_day_js', [], $locale);
@@ -497,10 +505,13 @@ class AccountController extends Controller
}
if ('1W' === $step || '1M' === $step || '1Y' === $step) {
while ($end >= $current) {
app('log')->debug(sprintf('Current is: %s', $current->format('Y-m-d')));
$balance = (float)app('steam')->balance($account, $current, $currency);
$label = app('navigation')->periodShow($current, $step);
$entries[$label] = $balance;
$current = app('navigation')->addPeriod($current, $step, 0);
// here too, to fix #8041, the data is corrected to the end of the period.
$current = app('navigation')->endOfX($current, $step, null);
}
}
$result['entries'] = $entries;

View File

@@ -23,9 +23,9 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use DB;
use Exception;
use FireflyConfig;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Models\AccountType;
@@ -229,8 +229,17 @@ class DebugController extends Controller
{
$userGuard = config('auth.defaults.guard');
$config = app('fireflyconfig')->get('last_rt_job', 0);
$lastTime = (int)$config->data;
$lastCronjob = 'never';
$lastCronjobAgo = 'never';
if ($lastTime > 0) {
$carbon = Carbon::createFromTimestamp($lastTime);
$lastCronjob = $carbon->format('Y-m-d H:i:s');
$lastCronjobAgo = $carbon->locale('en')->diffForHumans();
}
return [
'tz' => env('TZ'),
'debug' => var_export(config('app.debug'), true),
'audit_log_channel' => envNonEmpty('AUDIT_LOG_CHANNEL', '(empty)'),
'default_language' => (string)config('firefly.default_language'),
@@ -238,6 +247,13 @@ class DebugController extends Controller
'remote_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_header') : 'N/A',
'remote_mail_header' => $userGuard === 'remote_user_guard' ? config('auth.guard_email') : 'N/A',
'stateful_domains' => join(', ', config('sanctum.stateful')),
// the dates for the cron job are based on the recurring cron job's times.
// any of the cron jobs will do, they always run at the same time.
// but this job is the oldest, so the biggest chance it ran once
'last_cronjob' => $lastCronjob,
'last_cronjob_ago' => $lastCronjobAgo,
];
}
@@ -288,40 +304,40 @@ class DebugController extends Controller
// has liabilities
if ($user->accounts()->accountTypeIn([AccountType::DEBT, AccountType::LOAN, AccountType::MORTGAGE])->count() > 0) {
$flags[] = ':credit_card:';
$flags[] = '<span title="Has liabilities">:credit_card:</span>';
}
// has piggies
if ($user->piggyBanks()->count() > 0) {
$flags[] = ':pig:';
$flags[] = '<span title="Has piggy banks">:pig:</span>';
}
// has stored reconciliations
$type = TransactionType::whereType(TransactionType::RECONCILIATION)->first();
if ($user->transactionJournals()->where('transaction_type_id', $type->id)->count()) {
$flags[] = ':ledger:';
$flags[] = '<span title="Has reconciled">:ledger:</span>';
}
// has used importer?
// has rules
if ($user->rules()->count() > 0) {
$flags[] = ':wrench:';
$flags[] = '<span title="Has rules">:wrench:</span>';
}
// has recurring transactions
if ($user->recurrences()->count() > 0) {
$flags[] = ':clock130:';
$flags[] = '<span title="Has recurring transactions">:clock130:</span>';
}
// has groups
if ($user->objectGroups()->count() > 0) {
$flags[] = ':bookmark_tabs:';
$flags[] = '<span title="Has object groups">:bookmark_tabs:</span>';
}
// uses bills
if ($user->bills()->count() > 0) {
$flags[] = ':email:';
$flags[] = '<span title="Has subscriptions">:email:</span>';
}
return join(' ', $flags);
}

View File

@@ -98,7 +98,9 @@ class CreateController extends Controller
$operators = $search->getOperators()->toArray();
if ('' !== $words) {
session()->flash('warning', trans('firefly.rule_from_search_words', ['string' => $words]));
$operators[] = ['type' => 'description_contains', 'value' => $words];
$operators[] = [
'type' => 'description_contains',
'value' => $words];
}
$oldTriggers = $this->parseFromOperators($operators);
}

View File

@@ -63,6 +63,9 @@ use Illuminate\Support\Carbon;
* @method static Builder|CurrencyExchangeRate whereUserRate($value)
* @property int|null $user_group_id
* @method static Builder|CurrencyExchangeRate whereUserGroupId($value)
* @method static Builder|CurrencyExchangeRate onlyTrashed()
* @method static Builder|CurrencyExchangeRate withTrashed()
* @method static Builder|CurrencyExchangeRate withoutTrashed()
* @mixin Eloquent
*/
class CurrencyExchangeRate extends Model

View File

@@ -117,6 +117,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property int $the_count
* @property int|null $user_group_id
* @method static EloquentBuilder|TransactionJournal whereUserGroupId($value)
* @property-read Collection<int, \FireflyIII\Models\AuditLogEntry> $auditLogEntries
* @property-read int|null $audit_log_entries_count
* @mixin Eloquent
*/
class TransactionJournal extends Model

View File

@@ -65,6 +65,26 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
* @property-read int|null $piggy_banks_count
* @property-read Collection<int, TransactionJournal> $transactionJournals
* @property-read int|null $transaction_journals_count
* @property-read Collection<int, \FireflyIII\Models\Attachment> $attachments
* @property-read int|null $attachments_count
* @property-read Collection<int, \FireflyIII\Models\Category> $categories
* @property-read int|null $categories_count
* @property-read Collection<int, \FireflyIII\Models\CurrencyExchangeRate> $currencyExchangeRates
* @property-read int|null $currency_exchange_rates_count
* @property-read Collection<int, \FireflyIII\Models\ObjectGroup> $objectGroups
* @property-read int|null $object_groups_count
* @property-read Collection<int, \FireflyIII\Models\Recurrence> $recurrences
* @property-read int|null $recurrences_count
* @property-read Collection<int, \FireflyIII\Models\RuleGroup> $ruleGroups
* @property-read int|null $rule_groups_count
* @property-read Collection<int, \FireflyIII\Models\Rule> $rules
* @property-read int|null $rules_count
* @property-read Collection<int, \FireflyIII\Models\Tag> $tags
* @property-read int|null $tags_count
* @property-read Collection<int, \FireflyIII\Models\TransactionGroup> $transactionGroups
* @property-read int|null $transaction_groups_count
* @property-read Collection<int, \FireflyIII\Models\Webhook> $webhooks
* @property-read int|null $webhooks_count
* @mixin Eloquent
*/
class UserGroup extends Model

View File

@@ -227,7 +227,6 @@ class EventServiceProvider extends ServiceProvider
*/
private function registerObservers(): void
{
app('log')->debug('Register observers');
Attachment::observe(new AttachmentObserver());
PiggyBank::observe(new PiggyBankObserver());
Account::observe(new AccountObserver());

View File

@@ -31,6 +31,8 @@ use FireflyIII\Repositories\Journal\JournalCLIRepository;
use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepository;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepository as GroupJournalRepository;
use FireflyIII\Repositories\UserGroups\Journal\JournalRepositoryInterface as GroupJournalRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepository;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use Illuminate\Foundation\Application;
@@ -76,6 +78,19 @@ class JournalServiceProvider extends ServiceProvider
}
);
$this->app->bind(
GroupJournalRepositoryInterface::class,
static function (Application $app) {
/** @var GroupJournalRepositoryInterface $repository */
$repository = app(GroupJournalRepository::class);
if ($app->auth->check()) { // @phpstan-ignore-line (phpstan does not understand the reference to auth)
$repository->setUser(auth()->user());
}
return $repository;
}
);
// also bind new API repository
$this->app->bind(
JournalAPIRepositoryInterface::class,

View File

@@ -665,13 +665,17 @@ class BillRepository implements BillRepositoryInterface
*/
public function sumUnpaidInRange(Carbon $start, Carbon $end): array
{
app('log')->debug(sprintf('Now in sumUnpaidInRange("%s", "%s")', $start->format('Y-m-d'), $end->format('Y-m-d')));
$bills = $this->getActiveBills();
$return = [];
/** @var Bill $bill */
foreach ($bills as $bill) {
app('log')->debug(sprintf('Processing bill #%d ("%s")', $bill->id, $bill->name));
$dates = $this->getPayDatesInRange($bill, $start, $end);
$count = $bill->transactionJournals()->after($start)->before($end)->count();
$total = $dates->count() - $count;
app('log')->debug(sprintf('Pay dates: %d, count: %d, left: %d', $dates->count(), $count, $total));
app('log')->debug('dates', $dates->toArray());
if ($total > 0) {
$currency = $bill->transactionCurrency;

View File

@@ -245,7 +245,7 @@ class JournalRepository implements JournalRepositoryInterface
{
$query = $this->user->transactionJournals()
->orderBy('date', 'DESC');
if ('' !== $query) {
if ('' !== $search) {
$query->where('description', 'LIKE', sprintf('%%%s%%', $search));
}

View File

@@ -0,0 +1,49 @@
<?php
/*
* JournalRepository.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Journal;
use FireflyIII\Support\Repositories\UserGroup\UserGroupTrait;
use Illuminate\Support\Collection;
/**
* Class JournalRepository
*/
class JournalRepository implements JournalRepositoryInterface
{
use UserGroupTrait;
/**
* @inheritDoc
*/
public function searchJournalDescriptions(string $search, int $limit): Collection
{
$query = $this->userGroup->transactionJournals()
->orderBy('date', 'DESC');
if ('' !== $search) {
$query->where('description', 'LIKE', sprintf('%%%s%%', $search));
}
return $query->take($limit)->get();
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* JournalRepositoryInterface.php
* Copyright (c) 2023 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\UserGroups\Journal;
use Illuminate\Support\Collection;
/**
* Interface JournalRepositoryInterface
*/
interface JournalRepositoryInterface
{
/**
* Search in journal descriptions.
*
* @param string $search
* @param int $limit
*
* @return Collection
*/
public function searchJournalDescriptions(string $search, int $limit): Collection;
}

View File

@@ -100,9 +100,11 @@ class AccountDestroyService
$ibAccount->delete();
}
$journal = TransactionJournal::find($journalId);
/** @var JournalDestroyService $service */
$service = app(JournalDestroyService::class);
$service->destroy($journal);
if (null !== $journal) {
/** @var JournalDestroyService $service */
$service = app(JournalDestroyService::class);
$service->destroy($journal);
}
}
}

View File

@@ -185,10 +185,20 @@ class CreditRecalculateService
app('log')->debug(sprintf('Now processing account #%d ("%s")', $account->id, $account->name));
// get opening balance (if present)
$this->repository->setUser($account->user);
$direction = (string)$this->repository->getMetaValue($account, 'liability_direction');
$openingBalance = $this->repository->getOpeningBalance($account);
if (null !== $openingBalance) {
app('log')->debug(sprintf('Found opening balance transaction journal #%d', $openingBalance->id));
// if account direction is "debit" ("I owe this amount") the opening balance must always be AWAY from the account:
if ('debit' === $direction) {
$this->validateOpeningBalance($account, $openingBalance);
}
}
$startOfDebt = $this->repository->getOpeningBalanceAmount($account) ?? '0';
$leftOfDebt = app('steam')->positive($startOfDebt);
app('log')->debug(sprintf('Start of debt is "%s", so initial left of debt is "%s"', $startOfDebt, $leftOfDebt));
$currency = $this->repository->getAccountCurrency($account);
$decimals = (int)($currency?->decimal_places ?? 2);
app('log')->debug(sprintf('Start of debt is "%s", so initial left of debt is "%s"', app('steam')->bcround($startOfDebt, $decimals), app('steam')->bcround($leftOfDebt, $decimals)));
/** @var AccountMetaFactory $factory */
$factory = app(AccountMetaFactory::class);
@@ -196,9 +206,6 @@ class CreditRecalculateService
// amount is positive or negative, doesn't matter.
$factory->crud($account, 'start_of_debt', $startOfDebt);
// get direction of liability:
$direction = (string)$this->repository->getMetaValue($account, 'liability_direction');
app('log')->debug(sprintf('Debt direction is "%s"', $direction));
// now loop all transactions (except opening balance and credit thing)
@@ -217,6 +224,42 @@ class CreditRecalculateService
app('log')->debug(sprintf('Done processing account #%d ("%s")', $account->id, $account->name));
}
/**
* If account direction is "debit" ("I owe this amount") the opening balance must always be AWAY from the account:
*
* @param Account $account
* @param TransactionJournal $openingBalance
*
* @return void
*/
private function validateOpeningBalance(Account $account, TransactionJournal $openingBalance)
{
/** @var Transaction $source */
$source = $openingBalance->transactions()->where('amount', '<', 0)->first();
/** @var Transaction $dest */
$dest = $openingBalance->transactions()->where('amount', '>', 0)->first();
if ((int)$source->account_id !== $account->id) {
app('log')->info(sprintf('Liability #%d has a reversed opening balance. Will fix this now.', $account->id));
app('log')->debug(sprintf('Source amount "%s" is now "%s"', $source->amount, app('steam')->positive($source->amount)));
app('log')->debug(sprintf('Destination amount "%s" is now "%s"', $dest->amount, app('steam')->negative($dest->amount)));
$source->amount = app('steam')->positive($source->amount);
$dest->amount = app('steam')->negative($source->amount);
var_dump($source->foreign_amount);
if (null !== $source->foreign_amount && '' !== $source->foreign_amount) {
$source->foreign_amount = app('steam')->positive($source->foreign_amount);
app('log')->debug(sprintf('Source foreign amount "%s" is now "%s"', $source->foreign_amount, app('steam')->positive($source->foreign_amount)));
}
if (null !== $dest->foreign_amount && '' !== $dest->foreign_amount) {
$dest->foreign_amount = app('steam')->negative($dest->foreign_amount);
app('log')->debug(sprintf('Destination amount "%s" is now "%s"', $dest->foreign_amount, app('steam')->negative($dest->foreign_amount)));
}
$source->save();
$dest->save();
return;
}
app('log')->debug('Opening balance is valid');
}
/**
* @param Account $account
* @param string $direction
@@ -227,17 +270,20 @@ class CreditRecalculateService
*/
private function processTransaction(Account $account, string $direction, Transaction $transaction, string $leftOfDebt): string
{
app('log')->debug(sprintf('Left of debt is: %s', $leftOfDebt));
$journal = $transaction->transactionJournal;
$foreignCurrency = $transaction->foreignCurrency;
$accountCurrency = $this->repository->getAccountCurrency($account);
$groupId = $journal->transaction_group_id;
$decimals = (int)$accountCurrency->decimal_places;
$type = $journal->transactionType->type;
/** @var Transaction $destTransaction */
$destTransaction = $journal->transactions()->where('amount', '>', '0')->first();
/** @var Transaction $sourceTransaction */
$sourceTransaction = $journal->transactions()->where('amount', '<', '0')->first();
app('log')->debug(sprintf('Left of debt is: %s', app('steam')->bcround($leftOfDebt, $decimals)));
if ('' === $direction) {
app('log')->warning('Direction is empty, so do nothing.');
return $leftOfDebt;
@@ -249,10 +295,10 @@ class CreditRecalculateService
// amount to use depends on the currency:
$usedAmount = $transaction->amount;
app('log')->debug(sprintf('Amount of transaction is %s', $usedAmount));
app('log')->debug(sprintf('Amount of transaction is %s', app('steam')->bcround($usedAmount, $decimals)));
if (null !== $foreignCurrency && $foreignCurrency->id === $accountCurrency->id) {
$usedAmount = $transaction->foreign_amount;
app('log')->debug(sprintf('Overruled by foreign amount. Amount of transaction is now %s', $usedAmount));
app('log')->debug(sprintf('Overruled by foreign amount. Amount of transaction is now %s', app('steam')->bcround($usedAmount, $decimals)));
}
// Case 1
@@ -267,7 +313,7 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcadd($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 1 (withdrawal into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 1 (withdrawal into credit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
@@ -283,7 +329,7 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcsub($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 2 (withdrawal away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 2 (withdrawal away from liability): %s - %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
@@ -299,7 +345,7 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcsub($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 3 (deposit away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 3 (deposit away from liability): %s - %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
@@ -315,7 +361,7 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcadd($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 4 (deposit into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 4 (deposit into credit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
// case 5: transfer into loan (from other loan).
@@ -329,7 +375,7 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcadd($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 5 (transfer into credit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 5 (transfer into credit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
// Case 6
@@ -344,7 +390,7 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcsub($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 6 (withdrawal into debit liability): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 6 (withdrawal into debit liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
// case 7
@@ -359,19 +405,35 @@ class CreditRecalculateService
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcadd($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 7 (deposit away from liability): %s - %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case 7 (deposit away from liability): %s - %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
// case 8
// it's a withdrawal from this liability (to expense account).
// if it's a debit ("I owe this amount") this increase the amount due.
// because we are paying interest.
if (
$type === TransactionType::WITHDRAWAL
&& (int)$account->id === (int)$transaction->account_id
&& -1 === bccomp($usedAmount, '0')
&& 'debit' === $direction
) {
$usedAmount = app('steam')->positive($usedAmount);
$result = bcadd($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case 8 (withdrawal away from liability): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
// in any other case, remove amount from left of debt.
if (in_array($type, [TransactionType::WITHDRAWAL, TransactionType::DEPOSIT, TransactionType::TRANSFER], true)) {
$usedAmount = app('steam')->negative($usedAmount);
$result = bcadd($leftOfDebt, $usedAmount);
app('log')->debug(sprintf('Case X (all other cases): %s + %s = %s', $leftOfDebt, $usedAmount, $result));
app('log')->debug(sprintf('Case X (all other cases): %s + %s = %s', app('steam')->bcround($leftOfDebt, $decimals), app('steam')->bcround($usedAmount, $decimals), app('steam')->bcround($result, $decimals)));
return $result;
}
Log::warning(sprintf('[6] Catch-all, should not happen. Left of debt = %s', $leftOfDebt));
Log::warning(sprintf('[-1] Catch-all, should not happen. Left of debt = %s', app('steam')->bcround($leftOfDebt, $decimals)));
return $leftOfDebt;
}

View File

@@ -29,6 +29,9 @@ use FireflyIII\Models\UserGroup;
use FireflyIII\User;
use Illuminate\Http\Request;
/**
* Trait ValidatesUserGroupTrait
*/
trait ValidatesUserGroupTrait
{
/**

View File

@@ -143,11 +143,12 @@ trait RuleManagement
$renderedEntries[] = view(
'rules.partials.trigger',
[
'oldTrigger' => OperatorQuerySearch::getRootOperator($operator['type']),
'oldValue' => $operator['value'],
'oldChecked' => false,
'count' => $index + 1,
'triggers' => $triggers,
'oldTrigger' => OperatorQuerySearch::getRootOperator($operator['type']),
'oldValue' => $operator['value'],
'oldChecked' => false,
'oldProhibited' => $operator['prohibited'] ?? false,
'count' => $index + 1,
'triggers' => $triggers,
]
)->render();
} catch (Throwable $e) {

View File

@@ -55,7 +55,6 @@ class Navigation
* @param int $skip
*
* @return Carbon
* @deprecated This method will be substituted by nextDateByInterval()
*/
public function addPeriod(Carbon $theDate, string $repeatFreq, int $skip = 0): Carbon
{
@@ -342,6 +341,35 @@ class Navigation
return $currentEnd;
}
/**
* @param string $period
* @param Carbon $beginning
* @param Carbon $end
*
* @return int
*/
public function diffInPeriods(string $period, Carbon $beginning, Carbon $end): int
{
$map = [
'daily' => 'diffInDays',
'weekly' => 'diffInWeeks',
'monthly' => 'diffInMonths',
'quarterly' => 'diffInQuarters',
'half-year' => 'diffInQuarters',
'yearly' => 'diffInYears',
];
if (!array_key_exists($period, $map)) {
app('log')->warning(sprintf('No diffInPeriods for period "%s"', $period));
return 1;
}
$func = $map[$period];
$diff = $beginning->$func($end);
if ('half-year' === $period) {
$diff = ceil($diff / 2);
}
return (int)$diff;
}
/**
* @param Carbon $theCurrentEnd
* @param string $repeatFreq

View File

@@ -782,7 +782,7 @@ class Steam
if (!is_string($preference)) {
throw new FireflyException(sprintf('Preference "language" must be a string, but is unexpectedly a "%s".', gettype($preference)));
}
return $preference;
return str_replace('-', '_', $preference);
}
/**

View File

@@ -30,7 +30,6 @@ use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class BillTransformer
@@ -150,9 +149,9 @@ class BillTransformer extends AbstractTransformer
*/
protected function paidData(Bill $bill): array
{
Log::debug(sprintf('Now in paidData for bill #%d', $bill->id));
app('log')->debug(sprintf('Now in paidData for bill #%d', $bill->id));
if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) {
Log::debug('parameters are NULL, return empty array');
app('log')->debug('parameters are NULL, return empty array');
return [
'paid_dates' => [],
@@ -163,44 +162,49 @@ class BillTransformer extends AbstractTransformer
// 2023-07-18 this particular date is used to search for the last paid date.
// 2023-07-18 the cloned $searchDate is used to grab the correct transactions.
/** @var Carbon $start */
$start = clone $this->parameters->get('start');
$start = clone $this->parameters->get('start');
$searchStart = clone $start;
$start->subDay();
$searchStart = clone $start;
//Log::debug(sprintf('Parameters are start:%s end:%s', $start->format('Y-m-d'), $this->parameters->get('end')->format('Y-m-d')));
app('log')->debug(sprintf('Parameters are start: %s end: %s', $start->format('Y-m-d'), $this->parameters->get('end')->format('Y-m-d')));
app('log')->debug(sprintf('Search parameters are: start: %s', $searchStart->format('Y-m-d')));
/*
* Get from database when bill was paid.
*/
$set = $this->repository->getPaidDatesInRange($bill, $searchStart, $this->parameters->get('end'));
//Log::debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count()));
app('log')->debug(sprintf('Count %d entries in getPaidDatesInRange()', $set->count()));
/*
* Grab from array the most recent payment. If none exist, fall back to the start date and pretend *that* was the last paid date.
*/
//Log::debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d')));
app('log')->debug(sprintf('Grab last paid date from function, return %s if it comes up with nothing.', $start->format('Y-m-d')));
$lastPaidDate = $this->lastPaidDate($set, $start);
//Log::debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d')));
app('log')->debug(sprintf('Result of lastPaidDate is %s', $lastPaidDate->format('Y-m-d')));
/*
* The next expected match (nextMatch) is, initially, the bill's date.
*/
$nextMatch = clone $bill->date;
//Log::debug(sprintf('Next match is %s (bill->date)', $nextMatch->format('Y-m-d')));
while ($nextMatch < $lastPaidDate) {
/*
* Diff in months (or other period) between bill start and last paid date or $start.
*/
$steps = app('navigation')->diffInPeriods($bill->repeat_freq, $start, $nextMatch);
$nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $steps);
if ($nextMatch->lt($lastPaidDate)) {
/*
* As long as this date is smaller than the last time the bill was paid, keep jumping ahead.
* For example: 1 jan, 1 feb, etc.
* Add another period because it's before the last paid date
*/
//Log::debug(sprintf('next match %s < last paid date %s, so add one period.', $nextMatch->format('Y-m-d'), $lastPaidDate->format('Y-m-d')));
app('log')->debug('Because the last paid date was before our next expected match, add another period.');
$nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $bill->skip);
//Log::debug(sprintf('Next match is now %s.', $nextMatch->format('Y-m-d')));
}
if ($nextMatch->isSameDay($lastPaidDate)) {
/*
* Add another period because it's the same day as the last paid date.
*/
//Log::debug('Because the last paid date was on the same day as our next expected match, add another day.');
app('log')->debug('Because the last paid date was on the same day as our next expected match, add another day.');
$nextMatch = app('navigation')->addPeriod($nextMatch, $bill->repeat_freq, $bill->skip);
}
/*
@@ -215,7 +219,7 @@ class BillTransformer extends AbstractTransformer
];
}
//Log::debug('Result', $result);
app('log')->debug(sprintf('Next match: %s', $nextMatch->toIso8601String()));
return [
'paid_dates' => $result,
@@ -254,23 +258,28 @@ class BillTransformer extends AbstractTransformer
*/
protected function payDates(Bill $bill): array
{
//Log::debug(sprintf('Now in payDates() for bill #%d', $bill->id));
app('log')->debug(sprintf('Now in payDates() for bill #%d', $bill->id));
if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) {
//Log::debug('No start or end date, give empty array.');
app('log')->debug('No start or end date, give empty array.');
return [];
}
app('log')->debug(sprintf('Start: %s, end: %s', $this->parameters->get('start')->toIso8601String(), $this->parameters->get('end')->toIso8601String()));
$set = new Collection();
$currentStart = clone $this->parameters->get('start');
// 2023-06-23 subDay to fix 7655
$currentStart->subDay();
$loop = 0;
while ($currentStart <= $this->parameters->get('end')) {
app('log')->debug(sprintf('Current start is %s', $currentStart->toIso8601String()));
$nextExpectedMatch = $this->nextDateMatch($bill, $currentStart);
// If nextExpectedMatch is after end, we continue:
if ($nextExpectedMatch > $this->parameters->get('end')) {
app('log')->debug('Next expected match is after END, so stop looking');
break;
}
app('log')->debug(sprintf('Next expected match is %s', $nextExpectedMatch->toIso8601String()));
// add to set
$set->push(clone $nextExpectedMatch);
$nextExpectedMatch->addDay();
@@ -285,13 +294,14 @@ class BillTransformer extends AbstractTransformer
return $date->format('Y-m-d');
}
);
app('log')->debug(sprintf('Found %d pay dates', $set->count()), $simple->toArray());
return $simple->toArray();
}
/**
* Given a bill and a date, this method will tell you at which moment this bill expects its next
* transaction. Whether or not it is there already, is not relevant.
* transaction. Whether it is there already, is not relevant.
*
* @param Bill $bill
* @param Carbon $date
@@ -300,15 +310,13 @@ class BillTransformer extends AbstractTransformer
*/
protected function nextDateMatch(Bill $bill, Carbon $date): Carbon
{
//Log::debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d')));
app('log')->debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d')));
$start = clone $bill->date;
//Log::debug(sprintf('Bill start date is %s', $start->format('Y-m-d')));
while ($start < $date) {
$start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
}
app('log')->debug(sprintf('Bill start date is %s', $start->format('Y-m-d')));
//Log::debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d')));
return $start;
$steps = app('navigation')->diffInPeriods($bill->repeat_freq, $start, $date);
$result = app('navigation')->addPeriod($start, $bill->repeat_freq, $steps);
app('log')->debug(sprintf('Number of steps is %d, result is %s', $steps, $start->format('Y-m-d')));
return $result;
}
}

View File

@@ -72,17 +72,17 @@ class RecurrenceTransformer extends AbstractTransformer
*/
public function transform(Recurrence $recurrence): array
{
Log::debug('Now in Recurrence::transform()');
app('log')->debug('Now in Recurrence::transform()');
$this->repository->setUser($recurrence->user);
$this->piggyRepos->setUser($recurrence->user);
$this->factory->setUser($recurrence->user);
$this->budgetRepos->setUser($recurrence->user);
Log::debug('Set user.');
app('log')->debug('Set user.');
$shortType = (string)config(sprintf('firefly.transactionTypesToShort.%s', $recurrence->transactionType->type));
$notes = $this->repository->getNoteText($recurrence);
$reps = 0 === (int)$recurrence->repetitions ? null : (int)$recurrence->repetitions;
Log::debug('Get basic data.');
app('log')->debug('Get basic data.');
// basic data.
return [
@@ -118,7 +118,7 @@ class RecurrenceTransformer extends AbstractTransformer
*/
private function getRepetitions(Recurrence $recurrence): array
{
Log::debug('Now in getRepetitions().');
app('log')->debug('Now in getRepetitions().');
$fromDate = $recurrence->latest_date ?? $recurrence->first_date;
$return = [];
@@ -157,7 +157,7 @@ class RecurrenceTransformer extends AbstractTransformer
*/
private function getTransactions(Recurrence $recurrence): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
app('log')->debug(sprintf('Now in %s', __METHOD__));
$return = [];
// get all transactions:
/** @var RecurrenceTransaction $transaction */
@@ -246,7 +246,7 @@ class RecurrenceTransformer extends AbstractTransformer
*/
private function getTransactionMeta(RecurrenceTransaction $transaction, array $array): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
app('log')->debug(sprintf('Now in %s', __METHOD__));
$array['tags'] = [];
$array['category_id'] = null;
$array['category_name'] = null;

View File

@@ -344,8 +344,8 @@ class TransactionGroupTransformer extends AbstractTransformer
],
];
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
app('log')->error($e->getMessage());
app('log')->error($e->getTraceAsString());
throw new FireflyException(sprintf('Transaction group #%d is broken. Please check out your log files.', $group->id), 0, $e);
}

View File

@@ -320,9 +320,9 @@ class BillTransformer extends AbstractTransformer
*/
protected function payDates(Bill $bill): array
{
//Log::debug(sprintf('Now in payDates() for bill #%d', $bill->id));
//app('log')->debug(sprintf('Now in payDates() for bill #%d', $bill->id));
if (null === $this->parameters->get('start') || null === $this->parameters->get('end')) {
//Log::debug('No start or end date, give empty array.');
//app('log')->debug('No start or end date, give empty array.');
return [];
}
@@ -366,14 +366,14 @@ class BillTransformer extends AbstractTransformer
*/
protected function nextDateMatch(Bill $bill, Carbon $date): Carbon
{
//Log::debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d')));
//app('log')->debug(sprintf('Now in nextDateMatch(%d, %s)', $bill->id, $date->format('Y-m-d')));
$start = clone $bill->date;
//Log::debug(sprintf('Bill start date is %s', $start->format('Y-m-d')));
//app('log')->debug(sprintf('Bill start date is %s', $start->format('Y-m-d')));
while ($start < $date) {
$start = app('navigation')->addPeriod($start, $bill->repeat_freq, $bill->skip);
}
//Log::debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d')));
//app('log')->debug(sprintf('End of loop, bill start date is now %s', $start->format('Y-m-d')));
return $start;
}

View File

@@ -270,7 +270,7 @@ class TransactionGroupTransformer extends AbstractTransformer
*/
private function stringFromArray(NullArrayObject $array, string $key, ?string $default): ?string
{
//Log::debug(sprintf('%s: %s', $key, var_export($array[$key], true)));
//app('log')->debug(sprintf('%s: %s', $key, var_export($array[$key], true)));
if (null === $array[$key] && null === $default) {
return null;
}
@@ -301,7 +301,7 @@ class TransactionGroupTransformer extends AbstractTransformer
if (null === $string) {
return null;
}
// Log::debug(sprintf('Now in date("%s")', $string));
// app('log')->debug(sprintf('Now in date("%s")', $string));
if (10 === strlen($string)) {
return Carbon::createFromFormat('Y-m-d', $string, config('app.timezone'));
}

View File

@@ -45,7 +45,7 @@ class WebhookMessageTransformer extends AbstractTransformer
try {
$json = json_encode($message->message, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
Log::error(sprintf('Could not encode webhook message #%d: %s', $message->id, $e->getMessage()));
app('log')->error(sprintf('Could not encode webhook message #%d: %s', $message->id, $e->getMessage()));
}
return [

View File

@@ -3,6 +3,31 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## v6.0.27 - 2023-10-16
### Added
- [Issue 8004](https://github.com/firefly-iii/firefly-iii/issues/8004) Warning in entrypoint script for missing variables.
### Changed
- Experimental database validation command.
- Add some values to the debug form.
- Better debug logs at various places
### Fixed
- [Issue 8020](https://github.com/firefly-iii/firefly-iii/issues/8020), [issue 8028](https://github.com/firefly-iii/firefly-iii/issues/8028) Liability calculation edge case found by @tieu1991
- [Issue 7655](https://github.com/firefly-iii/firefly-iii/issues/7655), [issue 8026](https://github.com/firefly-iii/firefly-iii/issues/8026) Bill date calculation edge case found by @devfaz
- [Issue 8051](https://github.com/firefly-iii/firefly-iii/issues/8051) Null pointer when deleting account
- [Issue 8041](https://github.com/firefly-iii/firefly-iii/issues/8041) Confusing chart is no longer confusing
- [Issue 8050](https://github.com/firefly-iii/firefly-iii/issues/8050) Path is normal for page 2.
- [Issue 8057](https://github.com/firefly-iii/firefly-iii/issues/8057) negative query parameters are handled correctly.
### API (v2.0.10)
- All endpoints (v1 and v2) should now respect the `?limit=` param.
## 6.0.26 - 2023-09-24
### Fixed

402
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -105,6 +105,7 @@ return [
'charset' => 'utf8',
'prefix' => '',
'search_path' => envNonEmpty('PGSQL_SCHEMA', 'public'),
'schema' => envNonEmpty('PGSQL_SCHEMA', 'public'),
'sslmode' => envNonEmpty('PGSQL_SSL_MODE', 'prefer'),
'sslcert' => envNonEmpty('PGSQL_SSL_CERT'),
'sslkey' => envNonEmpty('PGSQL_SSL_KEY'),

View File

@@ -112,8 +112,8 @@ return [
'handle_debts' => true,
// see cer.php for exchange rates feature flag.
],
'version' => '6.0.26',
'api_version' => '2.0.9',
'version' => '6.0.27',
'api_version' => '2.0.10',
'db_version' => 20,
// generic settings

52
package-lock.json generated
View File

@@ -7,7 +7,7 @@
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.0",
"@popperjs/core": "^2.11.8",
"alpinejs": "^3.13.0",
"alpinejs": "^3.13.1",
"bootstrap": "^5.3.0",
"bootstrap5-autocomplete": "^1.1.22",
"chart.js": "^4.4.0",
@@ -18,17 +18,17 @@
"store": "^2.0.12"
},
"devDependencies": {
"axios": "^1.5.0",
"laravel-vite-plugin": "^0.8.0",
"sass": "^1.66.1",
"vite": "^4.0.0",
"axios": "^1.5.1",
"laravel-vite-plugin": "^0.8.1",
"sass": "^1.69.0",
"vite": "^4.4.11",
"vite-plugin-manifest-sri": "^0.1.0"
}
},
"node_modules/@babel/runtime": {
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz",
"integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
"integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@@ -425,9 +425,9 @@
"integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA=="
},
"node_modules/alpinejs": {
"version": "3.13.0",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.0.tgz",
"integrity": "sha512-7FYR1Yz3evIjlJD1mZ3SYWSw+jlOmQGeQ1QiSufSQ6J84XMQFkzxm6OobiZ928SfqhGdoIp2SsABNsS4rXMMJw==",
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.13.1.tgz",
"integrity": "sha512-/LZ7mumW02V7AV5xTTftJFHS0I3KOXLl7tHm4xpxXAV+HJ/zjTT0n8MU7RZ6UoGPhmO/i+KEhQojaH/0RsH5tg==",
"dependencies": {
"@vue/reactivity": "~3.1.1"
}
@@ -452,9 +452,9 @@
"dev": true
},
"node_modules/axios": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz",
"integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==",
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz",
"integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==",
"dev": true,
"dependencies": {
"follow-redirects": "^1.15.0",
@@ -773,9 +773,9 @@
}
},
"node_modules/laravel-vite-plugin": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.0.tgz",
"integrity": "sha512-6VjLI+azBpeK6rWBiKcb/En5GnTdYpL0U4zS8gXYvb2/VSq4mlau5H3NWpSktUDBMM1b97LLgICx5zevi8IY0w==",
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-0.8.1.tgz",
"integrity": "sha512-fxzUDjOA37kOsYq8dP+3oPIlw8/kJVXwu0hOXLun82R1LpV02shGeWGYKx2lbpKffL5I0sfPPjfqbYxuqBluAA==",
"dev": true,
"dependencies": {
"picocolors": "^1.0.0",
@@ -916,9 +916,9 @@
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
},
"node_modules/rollup": {
"version": "3.29.2",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.2.tgz",
"integrity": "sha512-CJouHoZ27v6siztc21eEQGo0kIcE5D1gVPA571ez0mMYb25LGYGKnVNXpEj5MGlepmDWGXNjDB5q7uNiPHC11A==",
"version": "3.29.4",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz",
"integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
@@ -932,9 +932,9 @@
}
},
"node_modules/sass": {
"version": "1.68.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.68.0.tgz",
"integrity": "sha512-Lmj9lM/fef0nQswm1J2HJcEsBUba4wgNx2fea6yJHODREoMFnwRpZydBnX/RjyXw2REIwdkbqE4hrTo4qfDBUA==",
"version": "1.69.3",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.69.3.tgz",
"integrity": "sha512-X99+a2iGdXkdWn1akFPs0ZmelUzyAQfvqYc2P/MPTrJRuIRoTffGzT9W9nFqG00S+c8hXzVmgxhUuHFdrwxkhQ==",
"dev": true,
"dependencies": {
"chokidar": ">=3.0.0 <4.0.0",
@@ -978,9 +978,9 @@
}
},
"node_modules/vite": {
"version": "4.4.9",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
"version": "4.4.11",
"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz",
"integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==",
"dev": true,
"dependencies": {
"esbuild": "^0.18.10",

View File

@@ -6,16 +6,16 @@
"build": "vite build"
},
"devDependencies": {
"axios": "^1.5.0",
"laravel-vite-plugin": "^0.8.0",
"sass": "^1.66.1",
"vite": "^4.0.0",
"axios": "^1.5.1",
"laravel-vite-plugin": "^0.8.1",
"sass": "^1.69.0",
"vite": "^4.4.11",
"vite-plugin-manifest-sri": "^0.1.0"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^6.4.0",
"@popperjs/core": "^2.11.8",
"alpinejs": "^3.13.0",
"alpinejs": "^3.13.1",
"bootstrap": "^5.3.0",
"bootstrap5-autocomplete": "^1.1.22",
"chart.js": "^4.4.0",

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More