mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2026-01-08 11:31:20 +00:00
Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bcb734a459 | ||
|
|
8e9e0f71bf | ||
|
|
647c9c5eb0 | ||
|
|
4fa92ed5f7 | ||
|
|
febcbac1de | ||
|
|
c9763c3d05 | ||
|
|
fab6d5df8d | ||
|
|
5d872bead7 | ||
|
|
60a3cc1f72 | ||
|
|
413df5a005 | ||
|
|
5b35612be0 | ||
|
|
54441df562 | ||
|
|
87f4b59cfe | ||
|
|
4d0839cf9c | ||
|
|
56388e46f2 | ||
|
|
6b20b7ecdb | ||
|
|
ee82547eed | ||
|
|
ebd9b30f55 | ||
|
|
5b70f70aa7 | ||
|
|
80ef6fcb04 | ||
|
|
700db14de2 | ||
|
|
433397cb3d | ||
|
|
40b952c4e8 | ||
|
|
b46b01e03d | ||
|
|
70b8a10e94 | ||
|
|
b40eaf7585 | ||
|
|
aeca645a37 | ||
|
|
713dbf47fb | ||
|
|
d6c7ccf62d | ||
|
|
52385ae980 | ||
|
|
53da61429a | ||
|
|
c8a87833c6 | ||
|
|
55c8b9012c | ||
|
|
0104d46206 | ||
|
|
b9963ce0bf | ||
|
|
09247cc30b | ||
|
|
b03b0c630b | ||
|
|
ebd076e0ed | ||
|
|
a0f34666a3 | ||
|
|
1ed71ea742 | ||
|
|
b75c221626 | ||
|
|
3cf340e44c | ||
|
|
e6c0bbf082 | ||
|
|
86ca234625 | ||
|
|
7bd86fe2b6 | ||
|
|
23356b3884 | ||
|
|
ca3d836c83 | ||
|
|
3aa835a985 | ||
|
|
7b9f2b6ce5 | ||
|
|
31a9b03c1a | ||
|
|
141436aebb | ||
|
|
8d84bffc2d | ||
|
|
0fb81a6112 | ||
|
|
6563a79483 | ||
|
|
372c6ac667 | ||
|
|
e4923a3c69 | ||
|
|
54f3e60ae4 | ||
|
|
df6f65e0aa | ||
|
|
e83fdc58ff | ||
|
|
7720482930 | ||
|
|
c07fae19f9 | ||
|
|
aa3e467a3e | ||
|
|
c837692d72 | ||
|
|
61c8b79e30 | ||
|
|
d0a8e6eb5b | ||
|
|
e61236836b | ||
|
|
a235b60bef | ||
|
|
a7d15ef287 | ||
|
|
045cec4421 | ||
|
|
465e49476a | ||
|
|
ed6a331faa | ||
|
|
f578e2c9e7 | ||
|
|
e0526508cb | ||
|
|
9151f44022 | ||
|
|
276de8a470 | ||
|
|
f6ce49b586 | ||
|
|
cf3d9d26fa | ||
|
|
265385c833 |
@@ -179,6 +179,9 @@ AUTHENTICATION_GUARD=web
|
||||
# Some systems use X-Auth headers. In that case, use HTTP_X_AUTH_USERNAME or HTTP_X_AUTH_EMAIL
|
||||
# Depending on your system, REMOTE_USER may need to be changed to HTTP_REMOTE_USER
|
||||
#
|
||||
# If this header is 'unexpectedly empty', check out the documentation.
|
||||
# https://docs.firefly-iii.org/advanced-installation/authentication
|
||||
#
|
||||
AUTHENTICATION_GUARD_HEADER=REMOTE_USER
|
||||
|
||||
#
|
||||
|
||||
@@ -58,7 +58,6 @@ class BillController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO add limit
|
||||
* @param AutocompleteRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
|
||||
@@ -58,7 +58,6 @@ class BudgetController extends Controller
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO add limit
|
||||
* @param AutocompleteRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
|
||||
@@ -24,7 +24,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\BillRequest;
|
||||
use FireflyIII\Api\V1\Requests\BillUpdateRequest;
|
||||
use FireflyIII\Api\V1\Requests\BillStoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Bill;
|
||||
@@ -49,8 +50,7 @@ class BillController extends Controller
|
||||
{
|
||||
use TransactionFilter;
|
||||
|
||||
/** @var BillRepositoryInterface The bill repository */
|
||||
private $repository;
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
|
||||
/**
|
||||
@@ -205,12 +205,12 @@ class BillController extends Controller
|
||||
/**
|
||||
* Store a bill.
|
||||
*
|
||||
* @param BillRequest $request
|
||||
* @param BillStoreRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(BillRequest $request): JsonResponse
|
||||
public function store(BillStoreRequest $request): JsonResponse
|
||||
{
|
||||
$bill = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
@@ -285,12 +285,12 @@ class BillController extends Controller
|
||||
/**
|
||||
* Update a bill.
|
||||
*
|
||||
* @param BillRequest $request
|
||||
* @param BillUpdateRequest $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(BillRequest $request, Bill $bill): JsonResponse
|
||||
public function update(BillUpdateRequest $request, Bill $bill): JsonResponse
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$bill = $this->repository->update($bill, $data);
|
||||
|
||||
@@ -23,7 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\CategoryRequest;
|
||||
use FireflyIII\Api\V1\Requests\CategoryStoreRequest;
|
||||
use FireflyIII\Api\V1\Requests\CategoryUpdateRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Category;
|
||||
@@ -46,9 +47,7 @@ use League\Fractal\Resource\Item;
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
use TransactionFilter;
|
||||
|
||||
/** @var CategoryRepositoryInterface The category repository */
|
||||
private $repository;
|
||||
private CategoryRepositoryInterface $repository;
|
||||
|
||||
|
||||
/**
|
||||
@@ -175,12 +174,12 @@ class CategoryController extends Controller
|
||||
/**
|
||||
* Store new category.
|
||||
*
|
||||
* @param CategoryRequest $request
|
||||
* @param CategoryStoreRequest $request
|
||||
*
|
||||
* @return JsonResponse
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function store(CategoryRequest $request): JsonResponse
|
||||
public function store(CategoryStoreRequest $request): JsonResponse
|
||||
{
|
||||
$category = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
@@ -253,12 +252,12 @@ class CategoryController extends Controller
|
||||
/**
|
||||
* Update the category.
|
||||
*
|
||||
* @param CategoryRequest $request
|
||||
* @param CategoryUpdateRequest $request
|
||||
* @param Category $category
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function update(CategoryRequest $request, Category $category): JsonResponse
|
||||
public function update(CategoryUpdateRequest $request, Category $category): JsonResponse
|
||||
{
|
||||
$data = $request->getAll();
|
||||
$category = $this->repository->update($category, $data);
|
||||
|
||||
@@ -38,15 +38,10 @@ use Illuminate\Http\JsonResponse;
|
||||
*/
|
||||
class CategoryController extends Controller
|
||||
{
|
||||
/** @var CategoryRepositoryInterface */
|
||||
private $categoryRepository;
|
||||
|
||||
/** @var NoCategoryRepositoryInterface */
|
||||
private $noCatRepository;
|
||||
|
||||
/** @var OperationsRepositoryInterface */
|
||||
private $opsRepository;
|
||||
|
||||
private CategoryRepositoryInterface $categoryRepository;
|
||||
private NoCategoryRepositoryInterface $noCatRepository;
|
||||
private OperationsRepositoryInterface $opsRepository;
|
||||
private array $categories;
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
@@ -63,6 +58,7 @@ class CategoryController extends Controller
|
||||
$this->categoryRepository = app(CategoryRepositoryInterface::class);
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$this->noCatRepository = app(NoCategoryRepositoryInterface::class);
|
||||
$this->categories = [];
|
||||
$this->categoryRepository->setUser($user);
|
||||
$this->opsRepository->setUser($user);
|
||||
$this->noCatRepository->setUser($user);
|
||||
@@ -87,53 +83,75 @@ class CategoryController extends Controller
|
||||
/** @var Carbon $end */
|
||||
$end = $dates['end'];
|
||||
|
||||
|
||||
$tempData = [];
|
||||
$spentWith = $this->opsRepository->listExpenses($start, $end);
|
||||
$spentWithout = $this->noCatRepository->listExpenses($start, $end);
|
||||
$categories = [];
|
||||
|
||||
|
||||
/** @var array $set */
|
||||
foreach ([$spentWith, $spentWithout,] as $set) {
|
||||
foreach ($set as $currency) {
|
||||
foreach ($currency['categories'] as $category) {
|
||||
$categories[] = $category['name'];
|
||||
$outKey = sprintf('%d-e', $currency['currency_id']);
|
||||
$tempData[$outKey] = $tempData[$outKey] ?? [
|
||||
'currency_id' => $currency['currency_id'],
|
||||
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency['currency_name']]),
|
||||
'currency_code' => $currency['currency_code'],
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
'type' => 'bar', // line, area or bar
|
||||
'yAxisID' => 0, // 0, 1, 2
|
||||
'entries' => [],
|
||||
];
|
||||
$tempData = $this->processArray($tempData, $set);
|
||||
}
|
||||
|
||||
foreach ($category['transaction_journals'] as $journal) {
|
||||
// is it expense or income?
|
||||
$currentKey = sprintf('%d-%s', $currency['currency_id'], 'e');
|
||||
$name = $category['name'];
|
||||
$tempData[$currentKey]['entries'][$name] = $tempData[$currentKey]['entries'][$name] ?? '0';
|
||||
$tempData[$currentKey]['entries'][$name] = bcadd($tempData[$currentKey]['entries'][$name], $journal['amount']);
|
||||
}
|
||||
$chartData = $this->sortArray($tempData);
|
||||
|
||||
return response()->json($chartData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tempData
|
||||
* @param array $set
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function processArray(array $tempData, array $set): array
|
||||
{
|
||||
foreach ($set as $currency) {
|
||||
foreach ($currency['categories'] as $category) {
|
||||
$this->categories[] = $category['name'];
|
||||
$outKey = sprintf('%d-e', $currency['currency_id']);
|
||||
$tempData[$outKey] = $tempData[$outKey] ?? [
|
||||
'currency_id' => $currency['currency_id'],
|
||||
'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $currency['currency_name']]),
|
||||
'currency_code' => $currency['currency_code'],
|
||||
'currency_symbol' => $currency['currency_symbol'],
|
||||
'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
'type' => 'bar', // line, area or bar
|
||||
'yAxisID' => 0, // 0, 1, 2
|
||||
'entries' => [],
|
||||
];
|
||||
|
||||
foreach ($category['transaction_journals'] as $journal) {
|
||||
// is it expense or income?
|
||||
$currentKey = sprintf('%d-%s', $currency['currency_id'], 'e');
|
||||
$name = $category['name'];
|
||||
$tempData[$currentKey]['entries'][$name] = $tempData[$currentKey]['entries'][$name] ?? '0';
|
||||
$tempData[$currentKey]['entries'][$name] = bcadd($tempData[$currentKey]['entries'][$name], $journal['amount']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $tempData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tempData
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function sortArray(array $tempData): array
|
||||
{
|
||||
// re-sort every spent array and add 0 for missing entries.
|
||||
foreach ($tempData as $index => $set) {
|
||||
$oldSet = $set['entries'];
|
||||
$newSet = [];
|
||||
foreach ($categories as $category) {
|
||||
foreach ($this->categories as $category) {
|
||||
$value = $oldSet[$category] ?? '0';
|
||||
$value = -1 === bccomp($value, '0') ? bcmul($value, '-1') : $value;
|
||||
$newSet[$category] = $value;
|
||||
}
|
||||
$tempData[$index]['entries'] = $newSet;
|
||||
}
|
||||
$chartData = array_values($tempData);
|
||||
|
||||
return response()->json($chartData);
|
||||
return array_values($tempData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BillRequest.php
|
||||
* BillStoreRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
@@ -25,31 +25,19 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class BillRequest
|
||||
*
|
||||
* TODO AFTER 4.8,0: split this into two request classes.
|
||||
* Class BillStoreRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class BillRequest extends FormRequest
|
||||
class BillStoreRequest extends FormRequest
|
||||
{
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* Authorize logged in users.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
use ConvertsDataTypes, ChecksLogin;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
@@ -85,7 +73,7 @@ class BillRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
return [
|
||||
'name' => 'between:1,255|uniqueObjectForUser:bills,name',
|
||||
'amount_min' => 'numeric|gt:0',
|
||||
'amount_max' => 'numeric|gt:0',
|
||||
@@ -97,17 +85,6 @@ class BillRequest extends FormRequest
|
||||
'active' => [new IsBoolean],
|
||||
'notes' => 'between:1,65536',
|
||||
];
|
||||
switch ($this->method()) {
|
||||
default:
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
$bill = $this->route()->parameter('bill');
|
||||
$rules['name'] .= ',' . $bill->id;
|
||||
break;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
111
app/Api/V1/Requests/BillUpdateRequest.php
Normal file
111
app/Api/V1/Requests/BillUpdateRequest.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* BillUpdateRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Rules\IsBoolean;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Validator;
|
||||
|
||||
/**
|
||||
* Class BillUpdateRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class BillUpdateRequest extends FormRequest
|
||||
{
|
||||
use ConvertsDataTypes, ChecksLogin;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$active = true;
|
||||
if (null !== $this->get('active')) {
|
||||
$active = $this->boolean('active');
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $this->string('name'),
|
||||
'amount_min' => $this->string('amount_min'),
|
||||
'amount_max' => $this->string('amount_max'),
|
||||
'currency_id' => $this->integer('currency_id'),
|
||||
'currency_code' => $this->string('currency_code'),
|
||||
'date' => $this->date('date'),
|
||||
'repeat_freq' => $this->string('repeat_freq'),
|
||||
'skip' => $this->integer('skip'),
|
||||
'active' => $active,
|
||||
'order' => $this->integer('order'),
|
||||
'notes' => $this->nlString('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$bill = $this->route()->parameter('bill');
|
||||
return [
|
||||
'name' => sprintf('between:1,255|uniqueObjectForUser:bills,name,%d', $bill->id),
|
||||
'amount_min' => 'numeric|gt:0',
|
||||
'amount_max' => 'numeric|gt:0',
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
|
||||
'date' => 'date',
|
||||
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'between:0,31',
|
||||
'active' => [new IsBoolean],
|
||||
'notes' => 'between:1,65536',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the validator instance.
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function withValidator(Validator $validator): void
|
||||
{
|
||||
$validator->after(
|
||||
static function (Validator $validator) {
|
||||
$data = $validator->getData();
|
||||
$min = (float) ($data['amount_min'] ?? 0);
|
||||
$max = (float) ($data['amount_max'] ?? 0);
|
||||
if ($min > $max) {
|
||||
$validator->errors()->add('amount_min', (string) trans('validation.amount_min_over_max'));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* CategoryRequest.php
|
||||
* CategoryStoreRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
@@ -23,7 +23,8 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Rules\ZeroOrMore;
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
@@ -31,22 +32,10 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
* Class CategoryRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* TODO AFTER 4.8,0: split this into two request classes.
|
||||
*/
|
||||
class CategoryRequest extends FormRequest
|
||||
class CategoryStoreRequest extends FormRequest
|
||||
{
|
||||
use ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* Authorize logged in users.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
// Only allow authenticated users
|
||||
return auth()->check();
|
||||
}
|
||||
use ConvertsDataTypes, ChecksLogin;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
@@ -56,7 +45,8 @@ class CategoryRequest extends FormRequest
|
||||
public function getAll(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->string('name'),
|
||||
'name' => $this->string('name'),
|
||||
'notes' => $this->nlString('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -67,20 +57,8 @@ class CategoryRequest extends FormRequest
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
return [
|
||||
'name' => 'required|between:1,100|uniqueObjectForUser:categories,name',
|
||||
];
|
||||
switch ($this->method()) {
|
||||
default:
|
||||
break;
|
||||
case 'PUT':
|
||||
case 'PATCH':
|
||||
/** @var Category $category */
|
||||
$category = $this->route()->parameter('category');
|
||||
$rules['name'] = sprintf('required|between:1,100|uniqueObjectForUser:categories,name,%d', $category->id);
|
||||
break;
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
71
app/Api/V1/Requests/CategoryUpdateRequest.php
Normal file
71
app/Api/V1/Requests/CategoryUpdateRequest.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
/**
|
||||
* CategoryUpdateRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* Class CategoryUpdateRequest
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class CategoryUpdateRequest extends FormRequest
|
||||
{
|
||||
use ConvertsDataTypes, ChecksLogin;
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$notes = null;
|
||||
$all = $this->all();
|
||||
if (array_key_exists('notes', $all)) {
|
||||
$notes = $this->nlString('notes');
|
||||
}
|
||||
|
||||
return [
|
||||
'name' => $this->string('name'),
|
||||
'notes' => $notes,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The rules that the incoming request must be matched against.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$category = $this->route()->parameter('category');
|
||||
|
||||
return [
|
||||
'name' => sprintf('required|between:1,100|uniqueObjectForUser:categories,name,%d', $category->id),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ namespace FireflyIII\Api\V1\Requests;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Rules\IsAssetAccountId;
|
||||
use FireflyIII\Rules\LessThanPiggyTarget;
|
||||
use FireflyIII\Rules\ZeroOrMore;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
@@ -79,7 +78,7 @@ class PiggyBankRequest extends FormRequest
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|between:1,255|uniquePiggyBankForUser',
|
||||
'current_amount' => ['numeric', new ZeroOrMore, 'lte:target_amount'],
|
||||
'current_amount' => ['numeric', 'gte:0', 'lte:target_amount'],
|
||||
'start_date' => 'date|nullable',
|
||||
'target_date' => 'date|nullable|after:start_date',
|
||||
'notes' => 'max:65000',
|
||||
@@ -95,7 +94,7 @@ class PiggyBankRequest extends FormRequest
|
||||
$rules['name'] = 'between:1,255|uniquePiggyBankForUser:' . $piggyBank->id;
|
||||
$rules['account_id'] = ['belongsToUser:accounts', new IsAssetAccountId];
|
||||
$rules['target_amount'] = 'numeric|gt:0';
|
||||
$rules['current_amount'] = ['numeric', new ZeroOrMore, new LessThanPiggyTarget];
|
||||
$rules['current_amount'] = ['numeric', 'gte:0', new LessThanPiggyTarget];
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests;
|
||||
|
||||
use FireflyIII\Rules\ZeroOrMore;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
@@ -76,10 +75,10 @@ class PiggyBankStoreRequest extends FormRequest
|
||||
{
|
||||
return [
|
||||
'name' => 'required|between:1,255|uniquePiggyBankForUser',
|
||||
'current_amount' => ['numeric', new ZeroOrMore, 'lte:target_amount'],
|
||||
'current_amount' => ['numeric', 'gte:0', 'lte:target_amount'],
|
||||
'account_id' => 'required|numeric|belongsToUser:accounts,id',
|
||||
'object_group_id' => 'numeric|belongsToUser:object_groups,id',
|
||||
'target_amount' => ['numeric', new ZeroOrMore, 'lte:target_amount', 'required'],
|
||||
'target_amount' => ['numeric', 'gte:0', 'lte:target_amount', 'required'],
|
||||
'start_date' => 'date|nullable',
|
||||
'target_date' => 'date|nullable|after:start_date',
|
||||
'notes' => 'max:65000',
|
||||
|
||||
@@ -82,10 +82,9 @@ class TransactionStoreRequest extends FormRequest
|
||||
{
|
||||
$return = [];
|
||||
/**
|
||||
* @var int $index
|
||||
* @var array $transaction
|
||||
*/
|
||||
foreach ($this->get('transactions') as $index => $transaction) {
|
||||
foreach ($this->get('transactions') as $transaction) {
|
||||
$object = new NullArrayObject($transaction);
|
||||
$return[] = [
|
||||
'type' => $this->stringFromValue($object['type']),
|
||||
|
||||
@@ -27,6 +27,7 @@ use DB;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
@@ -55,6 +56,7 @@ class FixUnevenAmount extends Command
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$start = microtime(true);
|
||||
$count = 0;
|
||||
// get invalid journals
|
||||
@@ -64,8 +66,11 @@ class FixUnevenAmount extends Command
|
||||
->get(['transaction_journal_id', DB::raw('SUM(amount) AS the_sum')]);
|
||||
/** @var stdClass $entry */
|
||||
foreach ($journals as $entry) {
|
||||
if (0 !== bccomp((string) $entry->the_sum, '0')) {
|
||||
$this->fixJournal((int) $entry->transaction_journal_id);
|
||||
if (0 !== bccomp((string)$entry->the_sum, '0')) {
|
||||
$message = sprintf('Sum of journal #%d is %s instead of zero.', $entry->transaction_journal_id, $entry->the_sum);
|
||||
$this->warn($message);
|
||||
Log::warning($message);
|
||||
$this->fixJournal((int)$entry->transaction_journal_id);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
@@ -106,7 +111,7 @@ class FixUnevenAmount extends Command
|
||||
return;
|
||||
}
|
||||
|
||||
$amount = bcmul('-1', (string) $source->amount);
|
||||
$amount = bcmul('-1', (string)$source->amount);
|
||||
|
||||
// fix amount of destination:
|
||||
/** @var Transaction $destination */
|
||||
|
||||
@@ -61,39 +61,46 @@ class CreateDatabase extends Command
|
||||
return 0;
|
||||
}
|
||||
// try to set up a raw connection:
|
||||
$pdo = false;
|
||||
$exists = false;
|
||||
$checked = false; // checked for existence of DB?
|
||||
$dsn = sprintf('mysql:host=%s;port=%d;charset=utf8mb4', env('DB_HOST', 'localhost'), env('DB_PORT', '3306'));
|
||||
$options = [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false,
|
||||
];
|
||||
|
||||
// when it fails, display error
|
||||
try {
|
||||
$pdo = new PDO($dsn, env('DB_USERNAME'), env('DB_PASSWORD'), $options);
|
||||
} catch (PDOException $e) {
|
||||
$this->error(sprintf('Error when connecting to DB: %s', $e->getMessage()));
|
||||
|
||||
return 1;
|
||||
}
|
||||
// with PDO, try to list DB's (
|
||||
$stmt = $pdo->query('SHOW DATABASES;');
|
||||
$exists = false;
|
||||
// slightly more complex but less error prone.
|
||||
foreach ($stmt as $row) {
|
||||
$name = $row['Database'] ?? false;
|
||||
if ($name === env('DB_DATABASE')) {
|
||||
$exists = true;
|
||||
|
||||
// only continue when no error.
|
||||
if (false !== $pdo) {
|
||||
// with PDO, try to list DB's (
|
||||
$stmt = $pdo->query('SHOW DATABASES;');
|
||||
$checked = true;
|
||||
// slightly more complex but less error prone.
|
||||
foreach ($stmt as $row) {
|
||||
$name = $row['Database'] ?? false;
|
||||
if ($name === env('DB_DATABASE')) {
|
||||
$exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (false === $exists) {
|
||||
if (false === $exists && true === $checked) {
|
||||
$this->error(sprintf('Database "%s" does not exist.', env('DB_DATABASE')));
|
||||
|
||||
// try to create it.
|
||||
$pdo->exec(sprintf('CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;', env('DB_DATABASE')));
|
||||
$this->info(sprintf('Created database "%s"', env('DB_DATABASE')));
|
||||
|
||||
return 0;
|
||||
}
|
||||
$this->info(sprintf('Database "%s" exists.', env('DB_DATABASE')));
|
||||
if (true === $exists && true === $checked) {
|
||||
$this->info(sprintf('Database "%s" exists.', env('DB_DATABASE')));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -204,11 +204,11 @@ class DecryptDatabase extends Command
|
||||
try {
|
||||
$newValue = json_decode($value, true, 512, JSON_THROW_ON_ERROR) ?? $value;
|
||||
} catch (JsonException $e) {
|
||||
$message = sprintf('Could not JSON decode preference row #%d: %s', $id, $e->getMessage());
|
||||
$message = sprintf('Could not JSON decode preference row #%d: %s. This does not have to be a problem.', $id, $e->getMessage());
|
||||
$this->error($message);
|
||||
Log::error($message);
|
||||
Log::error($value);
|
||||
Log::error($e->getTraceAsString());
|
||||
Log::warning($message);
|
||||
Log::warning($value);
|
||||
Log::warning($e->getTraceAsString());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class ExportData extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:export-data
|
||||
protected $signature = 'firefly-iii:export-data
|
||||
{--user=1 : The user ID that the export should run for.}
|
||||
{--token= : The user\'s access token.}
|
||||
{--start= : First transaction to export. Defaults to your very first transaction. Only applies to transaction export.}
|
||||
@@ -74,20 +74,17 @@ class ExportData extends Command
|
||||
{--export-bills : Create a file with all your bills and some meta data.}
|
||||
{--export-piggies : Create a file with all your piggy banks and some meta data.}
|
||||
{--force : Force overwriting of previous exports if found.}';
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepository;
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $journalRepository;
|
||||
/** @var User */
|
||||
private $user;
|
||||
private AccountRepositoryInterface $accountRepository;
|
||||
private JournalRepositoryInterface $journalRepository;
|
||||
private User $user;
|
||||
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @throws CannotInsertRecord
|
||||
* @return int
|
||||
* @throws CannotInsertRecord
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
@@ -111,7 +108,6 @@ class ExportData extends Command
|
||||
return 1;
|
||||
}
|
||||
// make export object and configure it.
|
||||
|
||||
/** @var ExportDataGenerator $exporter */
|
||||
$exporter = app(ExportDataGenerator::class);
|
||||
$exporter->setUser($this->user);
|
||||
@@ -126,26 +122,24 @@ class ExportData extends Command
|
||||
$exporter->setExportRules($options['export']['rules']);
|
||||
$exporter->setExportBills($options['export']['bills']);
|
||||
$exporter->setExportPiggies($options['export']['piggies']);
|
||||
|
||||
$data = $exporter->export();
|
||||
|
||||
if (0 === count($data)) {
|
||||
if (empty($data)) {
|
||||
$this->error('You must export *something*. Use --export-transactions or another option. See docs.firefly-iii.org');
|
||||
}
|
||||
$returnCode = 0;
|
||||
if (!empty($data)) {
|
||||
try {
|
||||
$this->exportData($options, $data);
|
||||
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||
} catch (FireflyException $e) {
|
||||
$this->error(sprintf('Could not store data: %s', $e->getMessage()));
|
||||
|
||||
return 1;
|
||||
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||
$returnCode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$this->exportData($options, $data);
|
||||
} catch (FireflyException $e) {
|
||||
$this->error(sprintf('Could not store data: %s', $e->getMessage()));
|
||||
|
||||
app('telemetry')->feature('system.command.errored', $this->signature);
|
||||
return 1;
|
||||
}
|
||||
|
||||
app('telemetry')->feature('system.command.executed', $this->signature);
|
||||
return 0;
|
||||
return $returnCode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,8 +166,8 @@ class ExportData extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
* @return Collection
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getAccountsParameter(): Collection
|
||||
{
|
||||
@@ -181,7 +175,7 @@ class ExportData extends Command
|
||||
$accounts = new Collection;
|
||||
$accountList = $this->option('accounts');
|
||||
$types = [AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE];
|
||||
if (null !== $accountList && '' !== (string) $accountList) {
|
||||
if (null !== $accountList && '' !== (string)$accountList) {
|
||||
$accountIds = explode(',', $accountList);
|
||||
$accounts = $this->accountRepository->getAccountsById($accountIds);
|
||||
}
|
||||
@@ -205,35 +199,30 @@ class ExportData extends Command
|
||||
/**
|
||||
* @param string $field
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @throws Exception
|
||||
* @return Carbon
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getDateParameter(string $field): Carbon
|
||||
{
|
||||
$date = Carbon::now()->subYear();
|
||||
$error = false;
|
||||
if (null !== $this->option($field)) {
|
||||
try {
|
||||
$date = Carbon::createFromFormat('Y-m-d', $this->option($field));
|
||||
} catch (InvalidArgumentException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$this->error(sprintf('%s date "%s" must be formatted YYYY-MM-DD. Field will be ignored.', $field, $this->option('start')));
|
||||
$error = true;
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
if ('start' === $field) {
|
||||
if (false === $error && 'start' === $field) {
|
||||
$journal = $this->journalRepository->firstNull();
|
||||
$date = null === $journal ? Carbon::now()->subYear() : $journal->date;
|
||||
$date->startOfDay();
|
||||
|
||||
return $date;
|
||||
}
|
||||
if ('end' === $field) {
|
||||
if (false === $error && 'end' === $field) {
|
||||
$date = today(config('app.timezone'));
|
||||
$date->endOfDay();
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
// fallback
|
||||
@@ -241,13 +230,13 @@ class ExportData extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws FireflyException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getExportDirectory(): string
|
||||
{
|
||||
$directory = (string) $this->option('export_directory');
|
||||
$directory = (string)$this->option('export_directory');
|
||||
if (null === $directory) {
|
||||
$directory = './';
|
||||
}
|
||||
@@ -259,8 +248,8 @@ class ExportData extends Command
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function parseOptions(): array
|
||||
{
|
||||
|
||||
@@ -29,9 +29,7 @@ use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalCLIRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use Illuminate\Console\Command;
|
||||
use Log;
|
||||
|
||||
@@ -52,32 +50,18 @@ class TransferCurrenciesCorrections extends Command
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:transfer-currencies {--F|force : Force the execution of this command.}';
|
||||
/** @var array */
|
||||
private $accountCurrencies;
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $accountRepos;
|
||||
/** @var JournalCLIRepositoryInterface */
|
||||
private $cliRepos;
|
||||
/** @var int */
|
||||
private $count;
|
||||
/** @var CurrencyRepositoryInterface */
|
||||
private $currencyRepos;
|
||||
/** @var Account The destination account of the current journal. */
|
||||
private $destinationAccount;
|
||||
/** @var TransactionCurrency The currency preference of the destination account of the current journal. */
|
||||
private $destinationCurrency;
|
||||
/** @var Transaction The destination transaction of the current journal. */
|
||||
private $destinationTransaction;
|
||||
/** @var JournalRepositoryInterface */
|
||||
private $journalRepos;
|
||||
/** @var Account The source account of the current journal. */
|
||||
private $sourceAccount;
|
||||
/** @var TransactionCurrency The currency preference of the source account of the current journal. */
|
||||
private $sourceCurrency;
|
||||
/** @var Transaction The source transaction of the current journal. */
|
||||
private $sourceTransaction;
|
||||
protected $signature = 'firefly-iii:transfer-currencies {--F|force : Force the execution of this command.}';
|
||||
private array $accountCurrencies;
|
||||
private AccountRepositoryInterface $accountRepos;
|
||||
private JournalCLIRepositoryInterface $cliRepos;
|
||||
private int $count;
|
||||
|
||||
private ?Account $destinationAccount;
|
||||
private ?TransactionCurrency $destinationCurrency;
|
||||
private ?Transaction $destinationTransaction;
|
||||
private ?Account $sourceAccount;
|
||||
private ?TransactionCurrency $sourceCurrency;
|
||||
private ?Transaction $sourceTransaction;
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
@@ -124,7 +108,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
if (null === $this->destinationTransaction->transaction_currency_id && null !== $this->destinationCurrency) {
|
||||
$this->destinationTransaction
|
||||
->transaction_currency_id
|
||||
= (int) $this->destinationCurrency->id;
|
||||
= (int)$this->destinationCurrency->id;
|
||||
$message = sprintf(
|
||||
'Transaction #%d has no currency setting, now set to %s.',
|
||||
$this->destinationTransaction->id,
|
||||
@@ -144,7 +128,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
private function fixDestNullForeignAmount(): void
|
||||
{
|
||||
if (null === $this->destinationTransaction->foreign_amount && null !== $this->sourceTransaction->foreign_amount) {
|
||||
$this->destinationTransaction->foreign_amount = bcmul((string) $this->sourceTransaction->foreign_amount, '-1');
|
||||
$this->destinationTransaction->foreign_amount = bcmul((string)$this->sourceTransaction->foreign_amount, '-1');
|
||||
$this->destinationTransaction->save();
|
||||
$this->count++;
|
||||
Log::debug(
|
||||
@@ -165,7 +149,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
{
|
||||
if (null !== $this->destinationCurrency
|
||||
&& null === $this->destinationTransaction->foreign_amount
|
||||
&& (int) $this->destinationTransaction->transaction_currency_id !== (int) $this->destinationCurrency->id
|
||||
&& (int)$this->destinationTransaction->transaction_currency_id !== (int)$this->destinationCurrency->id
|
||||
) {
|
||||
$message = sprintf(
|
||||
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
|
||||
@@ -177,7 +161,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
Log::debug($message);
|
||||
$this->line($message);
|
||||
$this->count++;
|
||||
$this->destinationTransaction->transaction_currency_id = (int) $this->destinationCurrency->id;
|
||||
$this->destinationTransaction->transaction_currency_id = (int)$this->destinationCurrency->id;
|
||||
$this->destinationTransaction->save();
|
||||
}
|
||||
}
|
||||
@@ -189,7 +173,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
*/
|
||||
private function fixInvalidForeignCurrency(): void
|
||||
{
|
||||
if ((int) $this->destinationCurrency->id === (int) $this->sourceCurrency->id) {
|
||||
if ((int)$this->destinationCurrency->id === (int)$this->sourceCurrency->id) {
|
||||
// update both transactions to match:
|
||||
$this->sourceTransaction->foreign_amount = null;
|
||||
$this->sourceTransaction->foreign_currency_id = null;
|
||||
@@ -223,7 +207,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
*/
|
||||
private function fixMismatchedForeignCurrency(): void
|
||||
{
|
||||
if ((int) $this->sourceCurrency->id !== (int) $this->destinationCurrency->id) {
|
||||
if ((int)$this->sourceCurrency->id !== (int)$this->destinationCurrency->id) {
|
||||
$this->sourceTransaction->transaction_currency_id = $this->sourceCurrency->id;
|
||||
$this->sourceTransaction->foreign_currency_id = $this->destinationCurrency->id;
|
||||
$this->destinationTransaction->transaction_currency_id = $this->sourceCurrency->id;
|
||||
@@ -245,7 +229,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
if (null === $this->sourceTransaction->transaction_currency_id && null !== $this->sourceCurrency) {
|
||||
$this->sourceTransaction
|
||||
->transaction_currency_id
|
||||
= (int) $this->sourceCurrency->id;
|
||||
= (int)$this->sourceCurrency->id;
|
||||
$message = sprintf(
|
||||
'Transaction #%d has no currency setting, now set to %s.',
|
||||
$this->sourceTransaction->id,
|
||||
@@ -265,7 +249,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
private function fixSourceNullForeignAmount(): void
|
||||
{
|
||||
if (null === $this->sourceTransaction->foreign_amount && null !== $this->destinationTransaction->foreign_amount) {
|
||||
$this->sourceTransaction->foreign_amount = bcmul((string) $this->destinationTransaction->foreign_amount, '-1');
|
||||
$this->sourceTransaction->foreign_amount = bcmul((string)$this->destinationTransaction->foreign_amount, '-1');
|
||||
$this->sourceTransaction->save();
|
||||
$this->count++;
|
||||
Log::debug(
|
||||
@@ -286,7 +270,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
{
|
||||
if (null !== $this->sourceCurrency
|
||||
&& null === $this->sourceTransaction->foreign_amount
|
||||
&& (int) $this->sourceTransaction->transaction_currency_id !== (int) $this->sourceCurrency->id
|
||||
&& (int)$this->sourceTransaction->transaction_currency_id !== (int)$this->sourceCurrency->id
|
||||
) {
|
||||
$message = sprintf(
|
||||
'Transaction #%d has a currency setting #%d that should be #%d. Amount remains %s, currency is changed.',
|
||||
@@ -298,7 +282,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
Log::debug($message);
|
||||
$this->line($message);
|
||||
$this->count++;
|
||||
$this->sourceTransaction->transaction_currency_id = (int) $this->sourceCurrency->id;
|
||||
$this->sourceTransaction->transaction_currency_id = (int)$this->sourceCurrency->id;
|
||||
$this->sourceTransaction->save();
|
||||
}
|
||||
}
|
||||
@@ -310,7 +294,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
*/
|
||||
private function fixTransactionJournalCurrency(TransactionJournal $journal): void
|
||||
{
|
||||
if ((int) $journal->transaction_currency_id !== (int) $this->sourceCurrency->id) {
|
||||
if ((int)$journal->transaction_currency_id !== (int)$this->sourceCurrency->id) {
|
||||
$oldCurrencyCode = $journal->transactionCurrency->code ?? '(nothing)';
|
||||
$journal->transaction_currency_id = $this->sourceCurrency->id;
|
||||
$message = sprintf(
|
||||
@@ -424,7 +408,7 @@ class TransferCurrenciesCorrections extends Command
|
||||
{
|
||||
$configVar = app('fireflyconfig')->get(self::CONFIG_NAME, false);
|
||||
if (null !== $configVar) {
|
||||
return (bool) $configVar->data;
|
||||
return (bool)$configVar->data;
|
||||
}
|
||||
|
||||
return false; // @codeCoverageIgnore
|
||||
@@ -502,8 +486,6 @@ class TransferCurrenciesCorrections extends Command
|
||||
* For transfers, this is can be a destructive routine since we FORCE them into a currency setting whether they
|
||||
* like it or not. Previous routines MUST have set the currency setting for both accounts for this to work.
|
||||
*
|
||||
* A transfer always has the
|
||||
*
|
||||
* Both source and destination must match the respective currency preference. So FF3 must verify ALL
|
||||
* transactions.
|
||||
*/
|
||||
@@ -527,8 +509,6 @@ class TransferCurrenciesCorrections extends Command
|
||||
{
|
||||
$this->count = 0;
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
|
||||
$this->journalRepos = app(JournalRepositoryInterface::class);
|
||||
$this->cliRepos = app(JournalCLIRepositoryInterface::class);
|
||||
$this->accountCurrencies = [];
|
||||
$this->resetInformation();
|
||||
|
||||
@@ -51,13 +51,13 @@ class CategoryFactory
|
||||
* @param int|null $categoryId
|
||||
* @param null|string $categoryName
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return Category|null
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
|
||||
{
|
||||
$categoryId = (int) $categoryId;
|
||||
$categoryName = (string) $categoryName;
|
||||
$categoryId = (int)$categoryId;
|
||||
$categoryName = (string)$categoryName;
|
||||
|
||||
Log::debug(sprintf('Going to find category with ID %d and name "%s"', $categoryId, $categoryName));
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ class TransactionJournalFactory
|
||||
private array $fields;
|
||||
private PiggyBankEventFactory $piggyEventFactory;
|
||||
private PiggyBankRepositoryInterface $piggyRepository;
|
||||
private TransactionFactory $transactionFactory;
|
||||
private TransactionTypeRepositoryInterface $typeRepository;
|
||||
private User $user;
|
||||
|
||||
|
||||
@@ -35,14 +35,10 @@ use Throwable;
|
||||
*/
|
||||
class MonthReportGenerator implements ReportGeneratorInterface
|
||||
{
|
||||
/** @var Collection The accounts involved in the report. */
|
||||
private $accounts;
|
||||
/** @var Carbon The end date */
|
||||
private $end;
|
||||
/** @var Collection The expense accounts. */
|
||||
private $expense;
|
||||
/** @var Carbon The start date. */
|
||||
private $start;
|
||||
private Collection $accounts;
|
||||
private Carbon $end;
|
||||
private Collection $expense;
|
||||
private Carbon $start;
|
||||
|
||||
/**
|
||||
* Generate the report.
|
||||
|
||||
@@ -155,7 +155,7 @@ class MonthReportGenerator implements ReportGeneratorInterface
|
||||
return [
|
||||
'journals' => $journals,
|
||||
'currency' => $currency,
|
||||
'exists' => count($journals) > 0,
|
||||
'exists' => !empty($journals),
|
||||
'end' => $this->end->formatLocalized((string) trans('config.month_and_day', [], $locale)),
|
||||
'endBalance' => app('steam')->balance($account, $this->end),
|
||||
'dayBefore' => $date->formatLocalized((string) trans('config.month_and_day', [], $locale)),
|
||||
|
||||
@@ -41,16 +41,11 @@ use Throwable;
|
||||
*/
|
||||
class MonthReportGenerator implements ReportGeneratorInterface
|
||||
{
|
||||
/** @var Collection The accounts in the report. */
|
||||
private $accounts;
|
||||
/** @var Collection The budgets in the report. */
|
||||
private $budgets;
|
||||
/** @var Carbon The end date. */
|
||||
private $end;
|
||||
/** @var array The expenses in the report. */
|
||||
private $expenses;
|
||||
/** @var Carbon The start date. */
|
||||
private $start;
|
||||
private Collection $accounts;
|
||||
private Collection $budgets;
|
||||
private Carbon $end;
|
||||
private array $expenses;
|
||||
private Carbon $start;
|
||||
|
||||
/**
|
||||
* MonthReportGenerator constructor.
|
||||
|
||||
@@ -52,6 +52,12 @@ class APIEventHandler
|
||||
$user = $repository->findNull((int) $event->userId);
|
||||
if (null !== $user) {
|
||||
$email = $user->email;
|
||||
|
||||
// if user is demo user, send to owner:
|
||||
if($user->hasRole('demo')) {
|
||||
$email = config('firefly.site_owner');
|
||||
}
|
||||
|
||||
$ipAddress = Request::ip();
|
||||
|
||||
// see if user has alternative email address:
|
||||
|
||||
@@ -52,6 +52,11 @@ class AdminEventHandler
|
||||
$email = $event->user->email;
|
||||
$ipAddress = $event->ipAddress;
|
||||
|
||||
// if user is demo user, send to owner:
|
||||
if($event->user->hasRole('demo')) {
|
||||
$email = config('firefly.site_owner');
|
||||
}
|
||||
|
||||
// see if user has alternative email address:
|
||||
$pref = app('preferences')->getForUser($event->user, 'remote_guard_alt_email', null);
|
||||
if (null !== $pref) {
|
||||
|
||||
@@ -65,6 +65,10 @@ class AutomationHandler
|
||||
$email = $pref->data;
|
||||
}
|
||||
|
||||
// if user is demo user, send to owner:
|
||||
if($user->hasRole('demo')) {
|
||||
$email = config('firefly.site_owner');
|
||||
}
|
||||
|
||||
try {
|
||||
Log::debug('Trying to mail...');
|
||||
|
||||
@@ -182,6 +182,11 @@ class UserEventHandler
|
||||
$user = $event->user;
|
||||
$email = $user->email;
|
||||
$ipAddress = $event->ipAddress;
|
||||
|
||||
if($user->hasRole('demo')) {
|
||||
return; // do not email demo user.
|
||||
}
|
||||
|
||||
$list = app('preferences')->getForUser($user, 'login_ip_history', [])->data;
|
||||
|
||||
// see if user has alternative email address:
|
||||
|
||||
@@ -224,7 +224,7 @@ class AttachmentHelper implements AttachmentHelperInterface
|
||||
}
|
||||
Log::debug('Done processing uploads.');
|
||||
}
|
||||
if (!is_array($files) || (is_array($files) && 0 === count($files))) {
|
||||
if (!is_array($files) || empty($files)) {
|
||||
Log::debug('Array of files is not an array. Probably nothing uploaded. Will not store attachments.');
|
||||
}
|
||||
|
||||
|
||||
@@ -244,20 +244,6 @@ class GroupCollector implements GroupCollectorInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the result to a specific transaction group.
|
||||
*
|
||||
* @param TransactionGroup $transactionGroup
|
||||
*
|
||||
* @return GroupCollectorInterface
|
||||
*/
|
||||
public function setGroup(TransactionGroup $transactionGroup): GroupCollectorInterface
|
||||
{
|
||||
$this->query->where('transaction_groups.id', $transactionGroup->id);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit the result to a set of specific journals.
|
||||
*
|
||||
@@ -267,7 +253,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
*/
|
||||
public function setJournalIds(array $journalIds): GroupCollectorInterface
|
||||
{
|
||||
if (count($journalIds) > 0) {
|
||||
if (!empty($journalIds)) {
|
||||
$this->query->whereIn('transaction_journals.id', $journalIds);
|
||||
}
|
||||
|
||||
|
||||
@@ -238,15 +238,6 @@ interface GroupCollectorInterface
|
||||
*/
|
||||
public function setDestinationAccounts(Collection $accounts): GroupCollectorInterface;
|
||||
|
||||
/**
|
||||
* Limit the result to a specific transaction group.
|
||||
*
|
||||
* @param TransactionGroup $transactionGroup
|
||||
*
|
||||
* @return GroupCollectorInterface
|
||||
*/
|
||||
public function setGroup(TransactionGroup $transactionGroup): GroupCollectorInterface;
|
||||
|
||||
/**
|
||||
* Limit the result to a set of specific transaction journals.
|
||||
*
|
||||
|
||||
@@ -61,11 +61,10 @@ class HomeController extends Controller
|
||||
$mainTitleIcon = 'fa-hand-spock-o';
|
||||
$email = auth()->user()->email;
|
||||
$pref = app('preferences')->get('remote_guard_alt_email', null);
|
||||
if(null !== $pref) {
|
||||
if(null !== $pref && is_string($pref->data)) {
|
||||
$email = $pref->data;
|
||||
}
|
||||
|
||||
|
||||
Log::debug('Email is ', [$email]);
|
||||
|
||||
return view('admin.index', compact('title', 'mainTitleIcon','email'));
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ class LoginController extends Controller
|
||||
$this->incrementLoginAttempts($request);
|
||||
Log::channel('audit')->info(sprintf('Login failed. Attempt for user "%s" failed.', $request->get('email')));
|
||||
|
||||
return $this->sendFailedLoginResponse($request);
|
||||
$this->sendFailedLoginResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -198,6 +198,9 @@ class LoginController extends Controller
|
||||
if ('remote_user_guard' === $authGuard && '' !== $logoutUri) {
|
||||
return redirect($logoutUri);
|
||||
}
|
||||
if ('remote_user_guard' === $authGuard && '' === $logoutUri) {
|
||||
session()->flash('error',trans('firefly.cant_logout_guard'));
|
||||
}
|
||||
|
||||
$this->guard()->logout();
|
||||
|
||||
|
||||
@@ -264,10 +264,9 @@ class IndexController extends Controller
|
||||
return [];
|
||||
}
|
||||
/**
|
||||
* @var int $objectGroupId
|
||||
* @var array $array
|
||||
*/
|
||||
foreach ($sums as $objectGroupId => $array) {
|
||||
foreach ($sums as $array) {
|
||||
/**
|
||||
* @var int $currencyId
|
||||
* @var array $entry
|
||||
|
||||
@@ -111,7 +111,7 @@ class AvailableBudgetController extends Controller
|
||||
*/
|
||||
public function createAlternative(Request $request, Carbon $start, Carbon $end)
|
||||
{
|
||||
$currencies = $this->currencyRepos->getEnabled();
|
||||
$currencies = $this->currencyRepos->get();
|
||||
$availableBudgets = $this->abRepository->get($start, $end);
|
||||
|
||||
// remove already budgeted currencies:
|
||||
|
||||
@@ -86,7 +86,7 @@ class BudgetLimitController extends Controller
|
||||
*/
|
||||
public function create(Budget $budget, Carbon $start, Carbon $end)
|
||||
{
|
||||
$collection = $this->currencyRepos->getEnabled();
|
||||
$collection = $this->currencyRepos->get();
|
||||
$budgetLimits = $this->blRepository->getBudgetLimits($budget, $start, $end);
|
||||
|
||||
// remove already budgeted currencies:
|
||||
|
||||
@@ -99,7 +99,7 @@ class IndexController extends Controller
|
||||
$start = $start ?? session('start', Carbon::now()->startOfMonth());
|
||||
$end = $end ?? app('navigation')->endOfPeriod($start, $range);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$currencies = $this->currencyRepository->getEnabled();
|
||||
$currencies = $this->currencyRepository->get();
|
||||
$budgeted = '0';
|
||||
$spent = '0';
|
||||
|
||||
|
||||
@@ -41,11 +41,8 @@ use Illuminate\View\View;
|
||||
class EditController extends Controller
|
||||
{
|
||||
|
||||
/** @var CategoryRepositoryInterface The category repository */
|
||||
private $repository;
|
||||
|
||||
/** @var AttachmentHelperInterface Helper for attachments. */
|
||||
private $attachments;
|
||||
private CategoryRepositoryInterface $repository;
|
||||
private AttachmentHelperInterface $attachments;
|
||||
|
||||
/**
|
||||
* CategoryController constructor.
|
||||
@@ -58,9 +55,9 @@ class EditController extends Controller
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.categories'));
|
||||
app('view')->share('title', (string)trans('firefly.categories'));
|
||||
app('view')->share('mainTitleIcon', 'fa-bookmark');
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
$this->attachments = app(AttachmentHelperInterface::class);
|
||||
|
||||
return $next($request);
|
||||
@@ -79,7 +76,7 @@ class EditController extends Controller
|
||||
*/
|
||||
public function edit(Request $request, Category $category)
|
||||
{
|
||||
$subTitle = (string) trans('firefly.edit_category', ['name' => $category->name]);
|
||||
$subTitle = (string)trans('firefly.edit_category', ['name' => $category->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('categories.edit.fromUpdate')) {
|
||||
@@ -87,7 +84,11 @@ class EditController extends Controller
|
||||
}
|
||||
$request->session()->forget('categories.edit.fromUpdate');
|
||||
|
||||
return view('categories.edit', compact('category', 'subTitle'));
|
||||
$preFilled = [
|
||||
'notes' => $request->old('notes') ?? $this->repository->getNoteText($category),
|
||||
];
|
||||
|
||||
return view('categories.edit', compact('category', 'subTitle', 'preFilled'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +104,7 @@ class EditController extends Controller
|
||||
$data = $request->getCategoryData();
|
||||
$this->repository->update($category, $data);
|
||||
|
||||
$request->session()->flash('success', (string) trans('firefly.updated_category', ['name' => $category->name]));
|
||||
$request->session()->flash('success', (string)trans('firefly.updated_category', ['name' => $category->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
// store new attachment(s):
|
||||
@@ -112,7 +113,7 @@ class EditController extends Controller
|
||||
$this->attachments->saveAttachmentsForModel($category, $files);
|
||||
}
|
||||
if (null !== $files && auth()->user()->hasRole('demo')) {
|
||||
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
|
||||
session()->flash('info', (string)trans('firefly.no_att_demo_user'));
|
||||
}
|
||||
|
||||
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
|
||||
@@ -122,7 +123,7 @@ class EditController extends Controller
|
||||
|
||||
$redirect = redirect($this->getPreviousUri('categories.edit.uri'));
|
||||
|
||||
if (1 === (int) $request->get('return_to_edit')) {
|
||||
if (1 === (int)$request->get('return_to_edit')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('categories.edit.fromUpdate', true);
|
||||
|
||||
|
||||
@@ -50,16 +50,11 @@ class BudgetController extends Controller
|
||||
{
|
||||
use DateCalculation, AugumentData;
|
||||
|
||||
/** @var GeneratorInterface Chart generation methods. */
|
||||
protected $generator;
|
||||
/** @var OperationsRepositoryInterface */
|
||||
protected $opsRepository;
|
||||
/** @var BudgetRepositoryInterface The budget repository */
|
||||
protected $repository;
|
||||
/** @var BudgetLimitRepositoryInterface */
|
||||
private $blRepository;
|
||||
/** @var NoBudgetRepositoryInterface */
|
||||
private $nbRepository;
|
||||
protected GeneratorInterface $generator;
|
||||
protected OperationsRepositoryInterface $opsRepository;
|
||||
protected BudgetRepositoryInterface $repository;
|
||||
private BudgetLimitRepositoryInterface $blRepository;
|
||||
private NoBudgetRepositoryInterface $nbRepository;
|
||||
|
||||
/**
|
||||
* BudgetController constructor.
|
||||
@@ -185,12 +180,12 @@ class BudgetController extends Controller
|
||||
while ($start <= $end) {
|
||||
$spent = $this->opsRepository->spentInPeriod($budgetCollection, new Collection, $start, $start);
|
||||
$amount = bcadd($amount, $spent);
|
||||
$format = $start->formatLocalized((string) trans('config.month_and_day', [], $locale));
|
||||
$format = $start->formatLocalized((string)trans('config.month_and_day', [], $locale));
|
||||
$entries[$format] = $amount;
|
||||
|
||||
$start->addDay();
|
||||
}
|
||||
$data = $this->generator->singleSet((string) trans('firefly.left'), $entries);
|
||||
$data = $this->generator->singleSet((string)trans('firefly.left'), $entries);
|
||||
// add currency symbol from budget limit:
|
||||
$data['datasets'][0]['currency_symbol'] = $budgetLimit->transactionCurrency->symbol;
|
||||
$data['datasets'][0]['currency_code'] = $budgetLimit->transactionCurrency->code;
|
||||
@@ -239,7 +234,7 @@ class BudgetController extends Controller
|
||||
|
||||
// group by asset account ID:
|
||||
foreach ($journals as $journal) {
|
||||
$key = sprintf('%d-%d', (int) $journal['source_account_id'], $journal['currency_id']);
|
||||
$key = sprintf('%d-%d', (int)$journal['source_account_id'], $journal['currency_id']);
|
||||
$result[$key] = $result[$key] ?? [
|
||||
'amount' => '0',
|
||||
'currency_symbol' => $journal['currency_symbol'],
|
||||
@@ -252,7 +247,7 @@ class BudgetController extends Controller
|
||||
$names = $this->getAccountNames(array_keys($result));
|
||||
foreach ($result as $combinedId => $info) {
|
||||
$parts = explode('-', $combinedId);
|
||||
$assetId = (int) $parts[0];
|
||||
$assetId = (int)$parts[0];
|
||||
$title = sprintf('%s (%s)', $names[$assetId] ?? '(empty)', $info['currency_name']);
|
||||
$chartData[$title]
|
||||
= [
|
||||
@@ -319,7 +314,7 @@ class BudgetController extends Controller
|
||||
$names = $this->getCategoryNames(array_keys($result));
|
||||
foreach ($result as $combinedId => $info) {
|
||||
$parts = explode('-', $combinedId);
|
||||
$categoryId = (int) $parts[0];
|
||||
$categoryId = (int)$parts[0];
|
||||
$title = sprintf('%s (%s)', $names[$categoryId] ?? '(empty)', $info['currency_name']);
|
||||
$chartData[$title] = [
|
||||
'amount' => $info['amount'],
|
||||
@@ -385,7 +380,7 @@ class BudgetController extends Controller
|
||||
$names = $this->getAccountNames(array_keys($result));
|
||||
foreach ($result as $combinedId => $info) {
|
||||
$parts = explode('-', $combinedId);
|
||||
$opposingId = (int) $parts[0];
|
||||
$opposingId = (int)$parts[0];
|
||||
$name = $names[$opposingId] ?? 'no name';
|
||||
$title = sprintf('%s (%s)', $name, $info['currency_name']);
|
||||
$chartData[$title] = [
|
||||
@@ -422,12 +417,12 @@ class BudgetController extends Controller
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$generator = app(FrontpageChartGenerator::class);
|
||||
$generator->setUser(auth()->user());
|
||||
$generator->setStart($start);
|
||||
$generator->setEnd($end);
|
||||
$chartGenerator = app(FrontpageChartGenerator::class);
|
||||
$chartGenerator->setUser(auth()->user());
|
||||
$chartGenerator->setStart($start);
|
||||
$chartGenerator->setEnd($end);
|
||||
|
||||
$chartData = $generator->generate();
|
||||
$chartData = $chartGenerator->generate();
|
||||
$data = $this->generator->multiSet($chartData);
|
||||
$cache->store($data);
|
||||
|
||||
@@ -463,14 +458,14 @@ class BudgetController extends Controller
|
||||
$preferredRange = app('navigation')->preferredRangeFormat($start, $end);
|
||||
$chartData = [
|
||||
[
|
||||
'label' => (string) trans('firefly.box_spent_in_currency', ['currency' => $currency->name]),
|
||||
'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $currency->name]),
|
||||
'type' => 'bar',
|
||||
'entries' => [],
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_code' => $currency->code,
|
||||
],
|
||||
[
|
||||
'label' => (string) trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]),
|
||||
'label' => (string)trans('firefly.box_budgeted_in_currency', ['currency' => $currency->name]),
|
||||
'type' => 'bar',
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_code' => $currency->code,
|
||||
@@ -549,7 +544,7 @@ class BudgetController extends Controller
|
||||
$currentStart = app('navigation')->addPeriod($currentStart, $preferredRange, 0);
|
||||
}
|
||||
|
||||
$data = $this->generator->singleSet((string) trans('firefly.spent'), $chartData);
|
||||
$data = $this->generator->singleSet((string)trans('firefly.spent'), $chartData);
|
||||
$cache->store($data);
|
||||
|
||||
return response()->json($data);
|
||||
|
||||
@@ -187,7 +187,7 @@ class ExpenseReportController extends Controller
|
||||
$newSet[$key] = $chartData[$key]; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
if (0 === count($newSet)) {
|
||||
if (empty($newSet)) {
|
||||
$newSet = $chartData; // @codeCoverageIgnore
|
||||
}
|
||||
$data = $this->generator->multiSet($newSet);
|
||||
|
||||
@@ -62,6 +62,13 @@ abstract class Controller extends BaseController
|
||||
app('view')->share('DEMO_PASSWORD', config('firefly.demo_password'));
|
||||
app('view')->share('FF_VERSION', config('firefly.version'));
|
||||
|
||||
// share custom auth guard info.
|
||||
$authGuard = config('firefly.authentication_guard');
|
||||
$logoutUri = config('firefly.custom_logout_uri');
|
||||
|
||||
app('view')->share('authGuard', $authGuard);
|
||||
app('view')->share('logoutUri', $logoutUri);
|
||||
|
||||
// upload size
|
||||
$maxFileSize = app('steam')->phpBytes(ini_get('upload_max_filesize'));
|
||||
$maxPostSize = app('steam')->phpBytes(ini_get('post_max_size'));
|
||||
|
||||
@@ -193,7 +193,7 @@ class BoxController extends Controller
|
||||
$incomes[$currencyId] = app('amount')->formatAnything($currency, $incomes[$currencyId] ?? '0', false);
|
||||
$expenses[$currencyId] = app('amount')->formatAnything($currency, $expenses[$currencyId] ?? '0', false);
|
||||
}
|
||||
if (0 === count($sums)) {
|
||||
if (empty($sums)) {
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$sums[$currency->id] = app('amount')->formatAnything($currency, '0', false);
|
||||
$incomes[$currency->id] = app('amount')->formatAnything($currency, '0', false);
|
||||
@@ -257,7 +257,7 @@ class BoxController extends Controller
|
||||
|
||||
|
||||
$return = [];
|
||||
foreach ($netWorthSet as $index => $data) {
|
||||
foreach ($netWorthSet as $data) {
|
||||
/** @var TransactionCurrency $currency */
|
||||
$currency = $data['currency'];
|
||||
$return[$currency->id] = app('amount')->formatAnything($currency, $data['balance'], false);
|
||||
|
||||
@@ -64,7 +64,7 @@ class FrontpageController extends Controller
|
||||
}
|
||||
}
|
||||
$html = '';
|
||||
if (count($info) > 0) {
|
||||
if (!empty($info)) {
|
||||
try {
|
||||
$html = view('json.piggy-banks', compact('info'))->render();
|
||||
// @codeCoverageIgnoreStart
|
||||
|
||||
@@ -67,8 +67,6 @@ class EditController extends Controller
|
||||
{
|
||||
$subTitle = (string) trans('firefly.edit_object_group', ['title' => $objectGroup->title]);
|
||||
$subTitleIcon = 'fa-pencil';
|
||||
$targetDate = null;
|
||||
$startDate = null;
|
||||
|
||||
if (true !== session('object-groups.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('object-groups.edit.uri');
|
||||
|
||||
@@ -165,7 +165,6 @@ class BudgetController extends Controller
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, $budgets);
|
||||
$result = [];
|
||||
foreach ($spent as $currency) {
|
||||
$currencyId = $currency['currency_id'];
|
||||
foreach ($currency['budgets'] as $budget) {
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
$destinationId = $journal['destination_account_id'];
|
||||
@@ -328,7 +327,6 @@ class BudgetController extends Controller
|
||||
foreach ($expenses as $currency) {
|
||||
foreach ($currency['budgets'] as $budget) {
|
||||
$count = 0;
|
||||
$total = '0';
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
$count++;
|
||||
$key = sprintf('%d-%d', $budget['id'], $currency['currency_id']);
|
||||
@@ -377,7 +375,6 @@ class BudgetController extends Controller
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, $budgets);
|
||||
$result = [];
|
||||
foreach ($spent as $currency) {
|
||||
$currencyId = $currency['currency_id'];
|
||||
foreach ($currency['budgets'] as $budget) {
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
$result[] = [
|
||||
|
||||
@@ -40,10 +40,7 @@ use Throwable;
|
||||
*/
|
||||
class TagController extends Controller
|
||||
{
|
||||
|
||||
|
||||
/** @var OperationsRepositoryInterface */
|
||||
private $opsRepository;
|
||||
private OperationsRepositoryInterface $opsRepository;
|
||||
|
||||
/**
|
||||
* ExpenseReportController constructor.
|
||||
@@ -282,7 +279,6 @@ class TagController extends Controller
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, $tags);
|
||||
$result = [];
|
||||
foreach ($spent as $currency) {
|
||||
$currencyId = $currency['currency_id'];
|
||||
foreach ($currency['tags'] as $tag) {
|
||||
foreach ($tag['transaction_journals'] as $journal) {
|
||||
$destinationId = $journal['destination_account_id'];
|
||||
@@ -335,7 +331,6 @@ class TagController extends Controller
|
||||
$spent = $this->opsRepository->listIncome($start, $end, $accounts, $tags);
|
||||
$result = [];
|
||||
foreach ($spent as $currency) {
|
||||
$currencyId = $currency['currency_id'];
|
||||
foreach ($currency['tags'] as $tag) {
|
||||
foreach ($tag['transaction_journals'] as $journal) {
|
||||
$sourceId = $journal['source_account_id'];
|
||||
@@ -496,7 +491,6 @@ class TagController extends Controller
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, $tags);
|
||||
$result = [];
|
||||
foreach ($spent as $currency) {
|
||||
$currencyId = $currency['currency_id'];
|
||||
foreach ($currency['tags'] as $tag) {
|
||||
foreach ($tag['transaction_journals'] as $journal) {
|
||||
$result[] = [
|
||||
@@ -546,7 +540,6 @@ class TagController extends Controller
|
||||
$spent = $this->opsRepository->listIncome($start, $end, $accounts, $tags);
|
||||
$result = [];
|
||||
foreach ($spent as $currency) {
|
||||
$currencyId = $currency['currency_id'];
|
||||
foreach ($currency['tags'] as $tag) {
|
||||
foreach ($tag['transaction_journals'] as $journal) {
|
||||
$result[] = [
|
||||
|
||||
@@ -346,7 +346,6 @@ class ReportController extends Controller
|
||||
$budgets = implode(',', $request->getBudgetList()->pluck('id')->toArray());
|
||||
$tags = implode(',', $request->getTagList()->pluck('id')->toArray());
|
||||
$double = implode(',', $request->getDoubleList()->pluck('id')->toArray());
|
||||
$uri = route('reports.index');
|
||||
|
||||
if (0 === $request->getAccountList()->count()) {
|
||||
Log::debug('Account count is zero');
|
||||
|
||||
@@ -242,17 +242,15 @@ class ConvertController extends Controller
|
||||
private function getAssetAccounts(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$accountList = $accountRepository->getActiveAccountsByType([AccountType::ASSET]);
|
||||
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::ASSET]);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$balance = app('steam')->balance($account, today());
|
||||
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
|
||||
$role = (string)$accountRepository->getMetaValue($account, 'account_role');
|
||||
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
|
||||
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
}
|
||||
@@ -271,16 +269,14 @@ class ConvertController extends Controller
|
||||
private function getLiabilities(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$accountList = $accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
$accountList = $this->accountRepository->getActiveAccountsByType([AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$balance = app('steam')->balance($account, today());
|
||||
$currency = $accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
|
||||
$currency = $this->accountRepository->getAccountCurrency($account) ?? $defaultCurrency;
|
||||
$role = 'l_' . $account->accountType->type;
|
||||
$key = (string)trans('firefly.opt_group_' . $role);
|
||||
$grouped[$key][$account->id] = $account->name . ' (' . app('amount')->formatAnything($currency, $balance, false) . ')';
|
||||
@@ -295,16 +291,14 @@ class ConvertController extends Controller
|
||||
private function getValidDepositSources(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN];
|
||||
$accountList = $accountRepository
|
||||
$accountList = $this->accountRepository
|
||||
->getActiveAccountsByType([AccountType::REVENUE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$role = (string)$accountRepository->getMetaValue($account, 'account_role');
|
||||
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
|
||||
$name = $account->name;
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
@@ -337,17 +331,15 @@ class ConvertController extends Controller
|
||||
private function getValidWithdrawalDests(): array
|
||||
{
|
||||
// make repositories
|
||||
/** @var AccountRepositoryInterface $accountRepository */
|
||||
$accountRepository = app(AccountRepositoryInterface::class);
|
||||
$liabilityTypes = [AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN];
|
||||
$accountList = $accountRepository->getActiveAccountsByType(
|
||||
$accountList = $this->accountRepository->getActiveAccountsByType(
|
||||
[AccountType::EXPENSE, AccountType::CASH, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]
|
||||
);
|
||||
$grouped = [];
|
||||
// group accounts:
|
||||
/** @var Account $account */
|
||||
foreach ($accountList as $account) {
|
||||
$role = (string)$accountRepository->getMetaValue($account, 'account_role');
|
||||
$role = (string)$this->accountRepository->getMetaValue($account, 'account_role');
|
||||
$name = $account->name;
|
||||
if ('' === $role) {
|
||||
$role = 'no_account_type'; // @codeCoverageIgnore
|
||||
|
||||
@@ -171,7 +171,7 @@ class ShowController extends Controller
|
||||
{
|
||||
$accounts = [];
|
||||
|
||||
foreach ($group['transactions'] as $index => $transaction) {
|
||||
foreach ($group['transactions'] as $transaction) {
|
||||
$accounts['source'][] = [
|
||||
'type' => $transaction['source_type'],
|
||||
'id' => $transaction['source_id'],
|
||||
|
||||
@@ -49,17 +49,12 @@ class StartFireflySession extends StartSession
|
||||
$isJsonPage = strpos($uri, '/json');
|
||||
|
||||
// also stop remembering "delete" URL's.
|
||||
|
||||
if (false === $isScriptPage && false === $isDeletePage
|
||||
&& false === $isLoginPage
|
||||
&& false === $isJsonPage
|
||||
&& 'GET' === $request->method()
|
||||
&& !$request->ajax()) {
|
||||
$session->setPreviousUrl($uri);
|
||||
Log::debug(sprintf('Will set previous URL to %s', $uri));
|
||||
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Will NOT set previous URL to %s', $uri));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class BudgetFormStoreRequest extends FormRequest
|
||||
'name' => $this->string('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'auto_budget_type' => $this->integer('auto_budget_type'),
|
||||
'transaction_currency_id' => $this->integer('transaction_currency_id'),
|
||||
'transaction_currency_id' => $this->integer('auto_budget_currency_id'),
|
||||
'auto_budget_amount' => $this->string('auto_budget_amount'),
|
||||
'auto_budget_period' => $this->string('auto_budget_period'),
|
||||
];
|
||||
|
||||
@@ -42,7 +42,8 @@ class CategoryFormRequest extends FormRequest
|
||||
public function getCategoryData(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->string('name'),
|
||||
'name' => $this->string('name'),
|
||||
'notes' => $this->nlString('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Http\Requests;
|
||||
|
||||
use FireflyIII\Support\Request\ChecksLogin;
|
||||
use FireflyIII\Support\Request\ConvertsDataTypes;
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
@@ -32,7 +33,7 @@ use Illuminate\Foundation\Http\FormRequest;
|
||||
*/
|
||||
class EmailFormRequest extends FormRequest
|
||||
{
|
||||
use ChecksLogin;
|
||||
use ChecksLogin, ConvertsDataTypes;
|
||||
|
||||
/**
|
||||
* Rules for this request.
|
||||
|
||||
@@ -354,17 +354,7 @@ class CreateRecurringTransactions implements ShouldQueue
|
||||
$includeWeekend = clone $this->date;
|
||||
$includeWeekend->addDays(2);
|
||||
$occurrences = $this->repository->getOccurrencesInRange($repetition, $recurrence->first_date, $includeWeekend);
|
||||
/*
|
||||
Log::debug(
|
||||
sprintf(
|
||||
'Calculated %d occurrences between %s and %s',
|
||||
count($occurrences),
|
||||
$recurrence->first_date->format('Y-m-d'),
|
||||
$includeWeekend->format('Y-m-d')
|
||||
),
|
||||
$this->debugArray($occurrences)
|
||||
);
|
||||
*/
|
||||
|
||||
unset($includeWeekend);
|
||||
|
||||
$result = $this->handleOccurrences($recurrence, $repetition, $occurrences);
|
||||
|
||||
@@ -70,12 +70,6 @@ class ReportNewJournalsMail extends Mailable
|
||||
*/
|
||||
public function build(): self
|
||||
{
|
||||
$subject = 1 === $this->groups->count()
|
||||
? 'Firefly III has created a new transaction'
|
||||
: sprintf(
|
||||
'Firefly III has created new %d transactions',
|
||||
$this->groups->count()
|
||||
);
|
||||
$this->transform();
|
||||
|
||||
return $this->view('emails.report-new-journals-html')->text('emails.report-new-journals-text')
|
||||
|
||||
@@ -26,6 +26,7 @@ use Carbon\Carbon;
|
||||
use Eloquent;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@@ -97,7 +98,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
*/
|
||||
class Account extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
use SoftDeletes, HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that should be casted to native types.
|
||||
|
||||
@@ -70,7 +70,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
* @property-read int|null $attachments_count
|
||||
* @property-read int|null $transaction_journals_count
|
||||
* @property-read int|null $transactions_count
|
||||
* @property bool $encrypted
|
||||
*/
|
||||
class Category extends Model
|
||||
{
|
||||
@@ -135,6 +134,15 @@ class Category extends Model
|
||||
return $this->morphMany(Attachment::class, 'attachable');
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Get all of the category's notes.
|
||||
*/
|
||||
public function notes(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Note::class, 'noteable');
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return BelongsToMany
|
||||
|
||||
@@ -26,6 +26,7 @@ use Carbon\Carbon;
|
||||
use Eloquent;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
@@ -132,13 +133,10 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
* @mixin Eloquent
|
||||
* @property-read int|null $budgets_count
|
||||
* @property-read int|null $categories_count
|
||||
* @property \Illuminate\Support\Carbon|null $created_at
|
||||
* @property \Illuminate\Support\Carbon|null $updated_at
|
||||
* @property bool $reconciled
|
||||
*/
|
||||
class Transaction extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
use SoftDeletes, HasFactory;
|
||||
/**
|
||||
* The attributes that should be casted to native types.
|
||||
*
|
||||
@@ -185,7 +183,6 @@ class Transaction extends Model
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the account this object belongs to.
|
||||
*
|
||||
|
||||
@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
@@ -124,7 +125,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
*/
|
||||
class TransactionJournal extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
use SoftDeletes, HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that should be casted to native types.
|
||||
@@ -248,32 +249,6 @@ class TransactionJournal extends Model
|
||||
return $this->hasMany(TransactionJournalLink::class, 'destination_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return bool
|
||||
*/
|
||||
public function isDeposit(): bool
|
||||
{
|
||||
if (null !== $this->transaction_type_type) {
|
||||
return TransactionType::DEPOSIT === $this->transaction_type_type;
|
||||
}
|
||||
|
||||
return $this->transactionType->isDeposit();
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return bool
|
||||
*/
|
||||
public function isOpeningBalance(): bool
|
||||
{
|
||||
if (null !== $this->transaction_type_type) {
|
||||
return TransactionType::OPENING_BALANCE === $this->transaction_type_type;
|
||||
}
|
||||
|
||||
return $this->transactionType->isOpeningBalance();
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return bool
|
||||
@@ -287,19 +262,6 @@ class TransactionJournal extends Model
|
||||
return $this->transactionType->isTransfer();
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return bool
|
||||
*/
|
||||
public function isWithdrawal(): bool
|
||||
{
|
||||
if (null !== $this->transaction_type_type) {
|
||||
return TransactionType::WITHDRAWAL === $this->transaction_type_type;
|
||||
}
|
||||
|
||||
return $this->transactionType->isWithdrawal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* Get all of the notes.
|
||||
@@ -355,7 +317,7 @@ class TransactionJournal extends Model
|
||||
if (!self::isJoined($query, 'transaction_types')) {
|
||||
$query->leftJoin('transaction_types', 'transaction_types.id', '=', 'transaction_journals.transaction_type_id');
|
||||
}
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$query->whereIn('transaction_types.type', $types);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,33 +115,6 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $number
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByAccountNumber(string $number, array $types): ?Account
|
||||
{
|
||||
$query = $this->user->accounts()
|
||||
->leftJoin('account_meta', 'account_meta.account_id', '=', 'accounts.id')
|
||||
->where('account_meta.name', 'account_number')
|
||||
->where('account_meta.data', json_encode($number));
|
||||
|
||||
if (count($types) > 0) {
|
||||
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$query->whereIn('account_types.type', $types);
|
||||
}
|
||||
|
||||
/** @var Collection $accounts */
|
||||
$accounts = $query->get(['accounts.*']);
|
||||
if ($accounts->count() > 0) {
|
||||
return $accounts->first();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $iban
|
||||
* @param array $types
|
||||
@@ -152,7 +125,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
$query = $this->user->accounts()->where('iban', '!=', '')->whereNotNull('iban');
|
||||
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$query->whereIn('account_types.type', $types);
|
||||
}
|
||||
@@ -180,7 +153,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
$query = $this->user->accounts();
|
||||
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$query->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$query->whereIn('account_types.type', $types);
|
||||
}
|
||||
@@ -228,16 +201,6 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccountType(Account $account): string
|
||||
{
|
||||
return $account->accountType->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return account type or null if not found.
|
||||
*
|
||||
@@ -260,7 +223,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
/** @var Collection $result */
|
||||
$query = $this->user->accounts();
|
||||
|
||||
if (count($accountIds) > 0) {
|
||||
if (!empty($accountIds)) {
|
||||
$query->whereIn('accounts.id', $accountIds);
|
||||
}
|
||||
$query->orderBy('accounts.order', 'ASC');
|
||||
@@ -279,7 +242,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
{
|
||||
/** @var Collection $result */
|
||||
$query = $this->user->accounts();
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$query->accountTypeIn($types);
|
||||
}
|
||||
$query->orderBy('accounts.order', 'ASC');
|
||||
@@ -303,7 +266,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
$query->where('name', 'account_role');
|
||||
}, 'attachments']
|
||||
);
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$query->accountTypeIn($types);
|
||||
}
|
||||
$query->where('active', 1);
|
||||
@@ -572,7 +535,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
}
|
||||
|
||||
}
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$dbQuery->whereIn('account_types.type', $types);
|
||||
}
|
||||
@@ -630,7 +593,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
$query->where('name', 'account_role');
|
||||
}]
|
||||
);
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$query->accountTypeIn($types);
|
||||
}
|
||||
$query->where('active', 0);
|
||||
@@ -728,7 +691,7 @@ class AccountRepository implements AccountRepositoryInterface
|
||||
});
|
||||
}
|
||||
}
|
||||
if (count($types) > 0) {
|
||||
if (!empty($types)) {
|
||||
$dbQuery->leftJoin('account_types', 'accounts.account_type_id', '=', 'account_types.id');
|
||||
$dbQuery->whereIn('account_types.type', $types);
|
||||
}
|
||||
|
||||
@@ -80,7 +80,7 @@ interface AccountRepositoryInterface
|
||||
/**
|
||||
* Moved here from account CRUD.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param Account $account
|
||||
* @param Account|null $moveTo
|
||||
*
|
||||
* @return bool
|
||||
@@ -96,19 +96,9 @@ interface AccountRepositoryInterface
|
||||
*/
|
||||
public function expandWithDoubles(Collection $accounts): Collection;
|
||||
|
||||
/**
|
||||
* Find by account number. Is used.
|
||||
*
|
||||
* @param string $number
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
public function findByAccountNumber(string $number, array $types): ?Account;
|
||||
|
||||
/**
|
||||
* @param string $iban
|
||||
* @param array $types
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
@@ -116,7 +106,7 @@ interface AccountRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param array $types
|
||||
* @param array $types
|
||||
*
|
||||
* @return Account|null
|
||||
*/
|
||||
@@ -136,13 +126,6 @@ interface AccountRepositoryInterface
|
||||
*/
|
||||
public function getAccountCurrency(Account $account): ?TransactionCurrency;
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAccountType(Account $account): string;
|
||||
|
||||
/**
|
||||
* Return account type or null if not found.
|
||||
*
|
||||
@@ -189,7 +172,7 @@ interface AccountRepositoryInterface
|
||||
* Return meta value for account. Null if not found.
|
||||
*
|
||||
* @param Account $account
|
||||
* @param string $field
|
||||
* @param string $field
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
@@ -282,7 +265,7 @@ interface AccountRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $types
|
||||
* @param array $types
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
@@ -291,7 +274,7 @@ interface AccountRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param array $types
|
||||
* @param array $types
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
@@ -312,7 +295,7 @@ interface AccountRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param Account $account
|
||||
* @param array $data
|
||||
* @param array $data
|
||||
*
|
||||
* @return Account
|
||||
*/
|
||||
|
||||
@@ -157,11 +157,11 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
*/
|
||||
public function firstUseDate(Budget $budget): ?Carbon
|
||||
{
|
||||
$oldest = null;
|
||||
$journal = $budget->transactionJournals()->orderBy('date', 'ASC')->first();
|
||||
if (null !== $journal) {
|
||||
return $journal->date;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -221,7 +221,7 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
$search->where('name', 'LIKE', sprintf('%%%s%%', $query));
|
||||
}
|
||||
$search->orderBy('order', 'ASC')
|
||||
->orderBy('name', 'ASC')->where('active', 1);
|
||||
->orderBy('name', 'ASC')->where('active', 1);
|
||||
|
||||
return $search->take($limit)->get();
|
||||
}
|
||||
@@ -278,15 +278,15 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
if ('rollover' === $type) {
|
||||
$type = AutoBudget::AUTO_BUDGET_ROLLOVER;
|
||||
}
|
||||
$repos = app(CurrencyRepositoryInterface::class);
|
||||
$currencyId = (int)($data['transaction_currency_id'] ?? 0);
|
||||
$repos = app(CurrencyRepositoryInterface::class);
|
||||
$currencyId = (int)($data['transaction_currency_id'] ?? 0);
|
||||
$currencyCode = (string)($data['transaction_currency_code'] ?? '');
|
||||
|
||||
$currency = $repos->findNull($currencyId);
|
||||
if(null === $currency) {
|
||||
if (null === $currency) {
|
||||
$currency = $repos->findByCodeNull($currencyCode);
|
||||
}
|
||||
if(null === $currency) {
|
||||
if (null === $currency) {
|
||||
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
}
|
||||
|
||||
@@ -307,11 +307,11 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
$limitRepos->setUser($this->user);
|
||||
$limitRepos->store(
|
||||
[
|
||||
'budget_id' => $newBudget->id,
|
||||
'transaction_currency_id' => $autoBudget->transaction_currency_id,
|
||||
'start_date' => $start,
|
||||
'end_date' => $end,
|
||||
'amount' => $autoBudget->amount,
|
||||
'budget_id' => $newBudget->id,
|
||||
'currency_id' => $autoBudget->transaction_currency_id,
|
||||
'start_date' => $start,
|
||||
'end_date' => $end,
|
||||
'amount' => $autoBudget->amount,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -349,15 +349,15 @@ class BudgetRepository implements BudgetRepositoryInterface
|
||||
$autoBudget->budget()->associate($budget);
|
||||
}
|
||||
|
||||
$repos = app(CurrencyRepositoryInterface::class);
|
||||
$currencyId = (int)($data['transaction_currency_id'] ?? 0);
|
||||
$repos = app(CurrencyRepositoryInterface::class);
|
||||
$currencyId = (int)($data['transaction_currency_id'] ?? 0);
|
||||
$currencyCode = (string)($data['transaction_currency_code'] ?? '');
|
||||
|
||||
$currency = $repos->findNull($currencyId);
|
||||
if(null === $currency) {
|
||||
if (null === $currency) {
|
||||
$currency = $repos->findByCodeNull($currencyCode);
|
||||
}
|
||||
if(null === $currency) {
|
||||
if (null === $currency) {
|
||||
$currency = app('amount')->getDefaultCurrencyByUser($this->user);
|
||||
}
|
||||
|
||||
|
||||
@@ -160,6 +160,9 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
|
||||
|
||||
/** @noinspection MoreThanThreeArgumentsInspection */
|
||||
/**
|
||||
* TODO this method does not include foreign amount transactions. It only sums up "amount".
|
||||
* TODO this probably also applies to the other "sumExpenses" methods.
|
||||
*
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param Collection|null $accounts
|
||||
@@ -196,6 +199,7 @@ class NoBudgetRepository implements NoBudgetRepositoryInterface
|
||||
'currency_decimal_places' => $journal['currency_decimal_places'],
|
||||
];
|
||||
$array[$currencyId]['sum'] = bcadd($array[$currencyId]['sum'], app('steam')->negative($journal['amount']));
|
||||
|
||||
}
|
||||
|
||||
return $array;
|
||||
|
||||
@@ -28,6 +28,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\CategoryFactory;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Services\Internal\Destroy\CategoryDestroyService;
|
||||
@@ -202,7 +203,7 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
* @param int $limit
|
||||
* @param int $limit
|
||||
*
|
||||
* @return Collection
|
||||
*/
|
||||
@@ -241,10 +242,28 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
if (null === $category) {
|
||||
throw new FireflyException(sprintf('400003: Could not store new category with name "%s"', $data['name']));
|
||||
}
|
||||
|
||||
if (array_key_exists('notes', $data) && '' === $data['notes']) {
|
||||
$this->removeNotes($category);
|
||||
}
|
||||
if (array_key_exists('notes', $data) && '' !== $data['notes']) {
|
||||
$this->updateNotes($category, $data['notes']);
|
||||
}
|
||||
|
||||
return $category;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*/
|
||||
public function removeNotes(Category $category): void
|
||||
{
|
||||
$category->notes()->delete();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param array $data
|
||||
@@ -383,4 +402,31 @@ class CategoryRepository implements CategoryRepositoryInterface
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function updateNotes(Category $category, string $notes): void
|
||||
{
|
||||
$dbNote = $category->notes()->first();
|
||||
if (null === $dbNote) {
|
||||
$dbNote = new Note;
|
||||
$dbNote->noteable()->associate($category);
|
||||
}
|
||||
$dbNote->text = trim($notes);
|
||||
$dbNote->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getNoteText(Category $category): ?string
|
||||
{
|
||||
$dbNote = $category->notes()->first();
|
||||
if (null === $dbNote) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $dbNote->text;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,27 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
interface CategoryRepositoryInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Remove notes.
|
||||
*
|
||||
* @param Category $category
|
||||
*/
|
||||
public function removeNotes(Category $category): void;
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param string $notes
|
||||
*/
|
||||
public function updateNotes(Category $category, string $notes): void;
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getNoteText(Category $category): ?string;
|
||||
|
||||
/**
|
||||
* Delete all categories.
|
||||
*/
|
||||
|
||||
@@ -401,14 +401,6 @@ class CurrencyRepository implements CurrencyRepositoryInterface
|
||||
return $preferred;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEnabled(): Collection
|
||||
{
|
||||
return TransactionCurrency::where('enabled', true)->orderBy('code', 'ASC')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currency exchange rate.
|
||||
*
|
||||
|
||||
@@ -203,11 +203,6 @@ interface CurrencyRepositoryInterface
|
||||
*/
|
||||
public function getCurrencyByPreference(Preference $preference): TransactionCurrency;
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function getEnabled(): Collection;
|
||||
|
||||
/**
|
||||
* Get currency exchange rate.
|
||||
*
|
||||
|
||||
@@ -215,7 +215,6 @@ class JournalRepository implements JournalRepositoryInterface
|
||||
*/
|
||||
public function getLinkNoteText(TransactionJournalLink $link): string
|
||||
{
|
||||
$notes = null;
|
||||
/** @var Note $note */
|
||||
$note = $link->notes()->first();
|
||||
if (null !== $note) {
|
||||
|
||||
@@ -60,7 +60,6 @@ trait CreatesObjectGroups
|
||||
*/
|
||||
protected function findOrCreateObjectGroup(string $title): ?ObjectGroup
|
||||
{
|
||||
$group = null;
|
||||
$maxOrder = $this->getObjectGroupMaxOrder();
|
||||
if (!$this->hasObjectGroup($title)) {
|
||||
return ObjectGroup::create(
|
||||
|
||||
@@ -328,8 +328,7 @@ trait ModifiesPiggyBanks
|
||||
*
|
||||
* @return PiggyBank
|
||||
*/
|
||||
public function update(PiggyBank $piggyBank, array $data): PiggyBank
|
||||
{
|
||||
private function updateProperties(PiggyBank $piggyBank, array $data): PiggyBank {
|
||||
if (array_key_exists('name', $data) && '' !== $data['name']) {
|
||||
$piggyBank->name = $data['name'];
|
||||
}
|
||||
@@ -344,7 +343,18 @@ trait ModifiesPiggyBanks
|
||||
}
|
||||
$piggyBank->startdate = $data['startdate'] ?? $piggyBank->startdate;
|
||||
$piggyBank->save();
|
||||
return $piggyBank;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PiggyBank $piggyBank
|
||||
* @param array $data
|
||||
*
|
||||
* @return PiggyBank
|
||||
*/
|
||||
public function update(PiggyBank $piggyBank, array $data): PiggyBank
|
||||
{
|
||||
$piggyBank = $this->updateProperties($piggyBank, $data);
|
||||
$this->updateNote($piggyBank, $data['notes'] ?? '');
|
||||
|
||||
// update the order of the piggy bank:
|
||||
|
||||
@@ -327,7 +327,7 @@ class RecurringRepository implements RecurringRepositoryInterface
|
||||
foreach ($journalMeta as $journalId) {
|
||||
$search[] = (int)$journalId;
|
||||
}
|
||||
if (0 === count($search)) {
|
||||
if (empty($search)) {
|
||||
|
||||
return new Collection;
|
||||
}
|
||||
|
||||
@@ -476,7 +476,6 @@ class TagRepository implements TagRepositoryInterface
|
||||
*/
|
||||
public function update(Tag $tag, array $data): Tag
|
||||
{
|
||||
$oldTag = $data['tag'];
|
||||
$tag->tag = $data['tag'];
|
||||
$tag->date = $data['date'];
|
||||
$tag->description = $data['description'];
|
||||
|
||||
@@ -275,7 +275,7 @@ trait RecurringTransactionTrait
|
||||
*/
|
||||
protected function updateTags(RecurrenceTransaction $transaction, array $tags): void
|
||||
{
|
||||
if (count($tags) > 0) {
|
||||
if (!empty($tags)) {
|
||||
/** @var RecurrenceMeta $entry */
|
||||
$entry = $transaction->recurrenceTransactionMeta()->where('name', 'tags')->first();
|
||||
if (null === $entry) {
|
||||
@@ -284,7 +284,7 @@ trait RecurringTransactionTrait
|
||||
$entry->value = json_encode($tags);
|
||||
$entry->save();
|
||||
}
|
||||
if (0 === count($tags)) {
|
||||
if (empty($tags)) {
|
||||
// delete if present
|
||||
$transaction->recurrenceTransactionMeta()->where('name', 'tags')->delete();
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ class BillUpdateService
|
||||
protected User $user;
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Bill $bill
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill
|
||||
@@ -69,43 +69,19 @@ class BillUpdateService
|
||||
$currency->enabled = true;
|
||||
$currency->save();
|
||||
|
||||
// old values
|
||||
$oldData = [
|
||||
'name' => $bill->name,
|
||||
'amount_min' => $bill->amount_min,
|
||||
'amount_max' => $bill->amount_max,
|
||||
'transaction_currency_name' => $bill->transactionCurrency->name,
|
||||
];
|
||||
// new values
|
||||
$data['transaction_currency_name'] = $currency->name;
|
||||
|
||||
if (isset($data['name']) && '' !== (string)$data['name']) {
|
||||
$bill->name = $data['name'];
|
||||
}
|
||||
|
||||
if (isset($data['amount_min']) && '' !== (string)$data['amount_min']) {
|
||||
$bill->amount_min = $data['amount_min'];
|
||||
}
|
||||
if (isset($data['amount_max']) && '' !== (string)$data['amount_max']) {
|
||||
$bill->amount_max = $data['amount_max'];
|
||||
}
|
||||
if (isset($data['date']) && '' !== (string)$data['date']) {
|
||||
$bill->date = $data['date'];
|
||||
}
|
||||
if (isset($data['repeat_freq']) && '' !== (string)$data['repeat_freq']) {
|
||||
$bill->repeat_freq = $data['repeat_freq'];
|
||||
}
|
||||
if (isset($data['skip']) && '' !== (string)$data['skip']) {
|
||||
$bill->skip = $data['skip'];
|
||||
}
|
||||
if (isset($data['active']) && is_bool($data['active'])) {
|
||||
$bill->active = $data['active'];
|
||||
}
|
||||
|
||||
$bill->transaction_currency_id = $currency->id;
|
||||
$bill->match = 'EMPTY';
|
||||
$bill->automatch = true;
|
||||
$bill = $this->updateBillProperties($bill, $data);
|
||||
$bill->transaction_currency_id = $currency->id;
|
||||
$bill->save();
|
||||
// old values
|
||||
$oldData = [
|
||||
'name' => $bill->name,
|
||||
'amount_min' => $bill->amount_min,
|
||||
'amount_max' => $bill->amount_max,
|
||||
'transaction_currency_name' => $bill->transactionCurrency->name,
|
||||
];
|
||||
|
||||
|
||||
// update note:
|
||||
if (isset($data['notes'])) {
|
||||
@@ -132,6 +108,7 @@ class BillUpdateService
|
||||
$bill->objectGroups()->sync([$objectGroup->id]);
|
||||
$bill->save();
|
||||
}
|
||||
|
||||
return $bill;
|
||||
}
|
||||
// remove if name is empty. Should be overruled by ID.
|
||||
@@ -148,9 +125,10 @@ class BillUpdateService
|
||||
$bill->objectGroups()->sync([$objectGroup->id]);
|
||||
$bill->save();
|
||||
}
|
||||
|
||||
return $bill;
|
||||
}
|
||||
if(0 === $objectGroupId) {
|
||||
if (0 === $objectGroupId) {
|
||||
$bill->objectGroups()->sync([]);
|
||||
$bill->save();
|
||||
}
|
||||
@@ -159,7 +137,7 @@ class BillUpdateService
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param Bill $bill
|
||||
* @param array $oldData
|
||||
* @param array $newData
|
||||
*/
|
||||
@@ -177,9 +155,9 @@ class BillUpdateService
|
||||
}
|
||||
Log::debug(sprintf('Found %d rules', $rules->count()));
|
||||
$fields = [
|
||||
'name' => 'description_contains',
|
||||
'amount_min' => 'amount_more',
|
||||
'amount_max' => 'amount_less',
|
||||
'name' => 'description_contains',
|
||||
'amount_min' => 'amount_more',
|
||||
'amount_max' => 'amount_less',
|
||||
'transaction_currency_name' => 'currency_is'];
|
||||
foreach ($fields as $field => $ruleTriggerKey) {
|
||||
if ($oldData[$field] === $newData[$field]) {
|
||||
@@ -193,9 +171,9 @@ class BillUpdateService
|
||||
|
||||
/**
|
||||
* @param Collection $rules
|
||||
* @param string $key
|
||||
* @param string $oldValue
|
||||
* @param string $newValue
|
||||
* @param string $key
|
||||
* @param string $oldValue
|
||||
* @param string $newValue
|
||||
*/
|
||||
private function updateRules(Collection $rules, string $key, string $oldValue, string $newValue): void
|
||||
{
|
||||
@@ -219,7 +197,7 @@ class BillUpdateService
|
||||
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
* @param Rule $rule
|
||||
* @param string $key
|
||||
*
|
||||
* @return RuleTrigger|null
|
||||
@@ -231,25 +209,64 @@ class BillUpdateService
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param int $oldOrder
|
||||
* @param int $newOrder
|
||||
* @param int $oldOrder
|
||||
* @param int $newOrder
|
||||
*/
|
||||
private function updateOrder(Bill $bill, int $oldOrder, int $newOrder): void
|
||||
{
|
||||
if ($newOrder > $oldOrder) {
|
||||
$this->user->bills()->where('order', '<=', $newOrder)->where('order', '>', $oldOrder)
|
||||
->where('bills.id', '!=', $bill->id)
|
||||
->update(['order' => DB::raw('bills.order-1')]);
|
||||
->where('bills.id', '!=', $bill->id)
|
||||
->update(['order' => DB::raw('bills.order-1')]);
|
||||
$bill->order = $newOrder;
|
||||
$bill->save();
|
||||
}
|
||||
if ($newOrder < $oldOrder) {
|
||||
$this->user->bills()->where('order', '>=', $newOrder)->where('order', '<', $oldOrder)
|
||||
->where('bills.id', '!=', $bill->id)
|
||||
->update(['order' => DB::raw('bills.order+1')]);
|
||||
->where('bills.id', '!=', $bill->id)
|
||||
->update(['order' => DB::raw('bills.order+1')]);
|
||||
$bill->order = $newOrder;
|
||||
$bill->save();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Bill $bill
|
||||
* @param array $data
|
||||
*
|
||||
* @return Bill
|
||||
*/
|
||||
private function updateBillProperties(Bill $bill, array $data): Bill
|
||||
{
|
||||
|
||||
if (isset($data['name']) && '' !== (string)$data['name']) {
|
||||
$bill->name = $data['name'];
|
||||
}
|
||||
|
||||
if (isset($data['amount_min']) && '' !== (string)$data['amount_min']) {
|
||||
$bill->amount_min = $data['amount_min'];
|
||||
}
|
||||
if (isset($data['amount_max']) && '' !== (string)$data['amount_max']) {
|
||||
$bill->amount_max = $data['amount_max'];
|
||||
}
|
||||
if (isset($data['date']) && '' !== (string)$data['date']) {
|
||||
$bill->date = $data['date'];
|
||||
}
|
||||
if (isset($data['repeat_freq']) && '' !== (string)$data['repeat_freq']) {
|
||||
$bill->repeat_freq = $data['repeat_freq'];
|
||||
}
|
||||
if (isset($data['skip']) && '' !== (string)$data['skip']) {
|
||||
$bill->skip = $data['skip'];
|
||||
}
|
||||
if (isset($data['active']) && is_bool($data['active'])) {
|
||||
$bill->active = $data['active'];
|
||||
}
|
||||
|
||||
$bill->match = 'EMPTY';
|
||||
$bill->automatch = true;
|
||||
$bill->save();
|
||||
|
||||
return $bill;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Services\Internal\Update;
|
||||
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
@@ -68,6 +69,7 @@ class CategoryUpdateService
|
||||
$this->updateRuleTriggers($oldName, $data['name']);
|
||||
$this->updateRuleActions($oldName, $data['name']);
|
||||
$this->updateRecurrences($oldName, $data['name']);
|
||||
$this->updateNotes($category, $data);
|
||||
|
||||
return $category;
|
||||
}
|
||||
@@ -137,4 +139,40 @@ class CategoryUpdateService
|
||||
->update(['rt_meta.value' => $newName]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Category $category
|
||||
* @param array $data
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
private function updateNotes(Category $category, array $data): void
|
||||
{
|
||||
$note = array_key_exists('notes', $data) ? $data['notes'] : null;
|
||||
if (null === $note) {
|
||||
return;
|
||||
}
|
||||
if ('' === $note) {
|
||||
$dbNote = $category->notes()->first();
|
||||
if (null !== $dbNote) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) {
|
||||
Log::debug($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
$dbNote = $category->notes()->first();
|
||||
if (null === $dbNote) {
|
||||
$dbNote = new Note;
|
||||
$dbNote->noteable()->associate($category);
|
||||
}
|
||||
$dbNote->text = trim($note);
|
||||
$dbNote->save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -76,10 +76,6 @@ class JournalUpdateService
|
||||
private $transactionGroup;
|
||||
/** @var TransactionJournal The journal to update. */
|
||||
private $transactionJournal;
|
||||
/** @var Account If new account info is submitted, this array will hold the valid destination. */
|
||||
private $validDestination;
|
||||
/** @var Account If new account info is submitted, this array will hold the valid source. */
|
||||
private $validSource;
|
||||
|
||||
/**
|
||||
* JournalUpdateService constructor.
|
||||
|
||||
@@ -41,8 +41,7 @@ class RecurrenceUpdateService
|
||||
{
|
||||
use TransactionTypeTrait, RecurringTransactionTrait;
|
||||
|
||||
/** @var User */
|
||||
private $user;
|
||||
private User $user;
|
||||
|
||||
/**
|
||||
* Updates a recurrence.
|
||||
@@ -99,7 +98,7 @@ class RecurrenceUpdateService
|
||||
$this->createRepetitions($recurrence, $data['repetitions'] ?? []);
|
||||
}
|
||||
|
||||
// update all transactions (and associated meta-data);
|
||||
// update all transactions (and associated meta-data)
|
||||
if (null !== $data['transactions']) {
|
||||
$this->deleteTransactions($recurrence);
|
||||
$this->createTransactions($recurrence, $data['transactions'] ?? []);
|
||||
|
||||
@@ -350,6 +350,7 @@ class Amount
|
||||
try {
|
||||
$value = Crypt::decrypt($value); // verified
|
||||
} catch (DecryptException $e) {
|
||||
// ignore decryption error.
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
||||
@@ -67,9 +67,9 @@ class RemoteUserGuard implements Guard
|
||||
|
||||
return;
|
||||
}
|
||||
// Get the user identifier from $_SERVER
|
||||
// Get the user identifier from $_SERVER or apache filtered headers
|
||||
$header = config('auth.guard_header', 'REMOTE_USER');
|
||||
$userID = request()->server($header) ?? null;
|
||||
$userID = request()->server($header) ?? apache_request_headers()[$header] ?? null;
|
||||
if (null === $userID) {
|
||||
Log::error(sprintf('No user in header "%s".', $header));
|
||||
throw new FireflyException('The guard header was unexpectedly empty. See the logs.');
|
||||
@@ -80,7 +80,7 @@ class RemoteUserGuard implements Guard
|
||||
|
||||
// store email address if present in header and not already set.
|
||||
$header = config('auth.guard_email');
|
||||
$emailAddress = request()->server($header) ?? null;
|
||||
$emailAddress = (string) (request()->server($header) ?? null);
|
||||
$preference = app('preferences')->getForUser($retrievedUser, 'remote_guard_alt_email', null);
|
||||
|
||||
if (null !== $emailAddress && null === $preference && $emailAddress !== $userID) {
|
||||
|
||||
@@ -31,6 +31,7 @@ use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
||||
/**
|
||||
* Class FrontpageChartGenerator
|
||||
*/
|
||||
@@ -64,9 +65,9 @@ class FrontpageChartGenerator
|
||||
{
|
||||
$budgets = $this->budgetRepository->getActiveBudgets();
|
||||
$data = [
|
||||
['label' => (string) trans('firefly.spent_in_budget'), 'entries' => [], 'type' => 'bar'],
|
||||
['label' => (string) trans('firefly.left_to_spend'), 'entries' => [], 'type' => 'bar'],
|
||||
['label' => (string) trans('firefly.overspent'), 'entries' => [], 'type' => 'bar'],
|
||||
['label' => (string)trans('firefly.spent_in_budget'), 'entries' => [], 'type' => 'bar'],
|
||||
['label' => (string)trans('firefly.left_to_spend'), 'entries' => [], 'type' => 'bar'],
|
||||
['label' => (string)trans('firefly.overspent'), 'entries' => [], 'type' => 'bar'],
|
||||
];
|
||||
|
||||
// loop al budgets:
|
||||
@@ -91,7 +92,7 @@ class FrontpageChartGenerator
|
||||
$this->opsRepository->setUser($user);
|
||||
|
||||
$locale = app('steam')->getLocale();
|
||||
$this->monthAndDayFormat = (string) trans('config.month_and_day', [], $locale);
|
||||
$this->monthAndDayFormat = (string)trans('config.month_and_day', [], $locale);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +118,7 @@ class FrontpageChartGenerator
|
||||
*
|
||||
* @param array $data
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function processBudget(array $data, Budget $budget): array
|
||||
@@ -133,6 +135,7 @@ class FrontpageChartGenerator
|
||||
if (0 !== $limits->count()) {
|
||||
return $this->budgetLimits($data, $budget, $limits);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -142,6 +145,7 @@ class FrontpageChartGenerator
|
||||
*
|
||||
* @param array $data
|
||||
* @param Budget $budget
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function noBudgetLimits(array $data, Budget $budget): array
|
||||
@@ -154,6 +158,7 @@ class FrontpageChartGenerator
|
||||
$data[1]['entries'][$title] = 0; // left to spend
|
||||
$data[2]['entries'][$title] = 0; // overspent
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -163,6 +168,7 @@ class FrontpageChartGenerator
|
||||
* @param array $data
|
||||
* @param Budget $budget
|
||||
* @param Collection $limits
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function budgetLimits(array $data, Budget $budget, Collection $limits): array
|
||||
@@ -171,6 +177,7 @@ class FrontpageChartGenerator
|
||||
foreach ($limits as $limit) {
|
||||
$data = $this->processLimit($data, $budget, $limit);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -180,6 +187,7 @@ class FrontpageChartGenerator
|
||||
* @param array $data
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function processLimit(array $data, Budget $budget, BudgetLimit $limit): array
|
||||
@@ -187,8 +195,12 @@ class FrontpageChartGenerator
|
||||
$spent = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, null, new Collection([$budget]), $limit->transactionCurrency);
|
||||
/** @var array $entry */
|
||||
foreach ($spent as $entry) {
|
||||
$data = $this->processRow($data, $budget, $limit, $entry);
|
||||
// only spent the entry where the entry's currency matches the budget limit's currency
|
||||
if ($entry['currency_id'] === (int)$limit->transaction_currency_id) {
|
||||
$data = $this->processRow($data, $budget, $limit, $entry);
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -202,6 +214,7 @@ class FrontpageChartGenerator
|
||||
* @param Budget $budget
|
||||
* @param BudgetLimit $limit
|
||||
* @param array $entry
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function processRow(array $data, Budget $budget, BudgetLimit $limit, array $entry): array
|
||||
|
||||
@@ -57,8 +57,6 @@ class WholePeriodChartGenerator
|
||||
public function generate(Category $category, Carbon $start, Carbon $end): array
|
||||
{
|
||||
$collection = new Collection([$category]);
|
||||
/** @var CategoryRepositoryInterface $repository */
|
||||
$repository = app(CategoryRepositoryInterface::class);
|
||||
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
|
||||
@@ -717,7 +717,7 @@ class ExportDataGenerator
|
||||
*/
|
||||
private function mergeTags(array $tags): string
|
||||
{
|
||||
if (0 === count($tags)) {
|
||||
if (empty($tags)) {
|
||||
return '';
|
||||
}
|
||||
$smol = [];
|
||||
|
||||
@@ -72,41 +72,6 @@ class AccountForm
|
||||
return $grouped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a <select> with all active asset accounts.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function activeAssetAccountList(string $name, $value = null, array $options = null): string
|
||||
{
|
||||
$types = [AccountType::ASSET, AccountType::DEFAULT];
|
||||
$grouped = $this->getAccountsGrouped($types);
|
||||
|
||||
return $this->select($name, $grouped, $value, $options);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a list that includes liabilities.
|
||||
*
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @param array $options
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function activeLongAccountList(string $name, $value = null, array $options = null): string
|
||||
{
|
||||
$types = [AccountType::ASSET, AccountType::DEFAULT, AccountType::MORTGAGE, AccountType::DEBT, AccountType::CREDITCARD, AccountType::LOAN,];
|
||||
$grouped = $this->getAccountsGrouped($types);
|
||||
|
||||
return $this->select($name, $grouped, $value, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Grouped dropdown list of all accounts that are valid as the destination of a withdrawal.
|
||||
*
|
||||
|
||||
@@ -129,7 +129,7 @@ trait RequestInformation
|
||||
$triggers = [];
|
||||
$data = $request->get('triggers');
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $index => $triggerInfo) {
|
||||
foreach ($data as $triggerInfo) {
|
||||
$triggers[] = [
|
||||
'type' => $triggerInfo['type'] ?? '',
|
||||
'value' => $triggerInfo['value'] ?? '',
|
||||
|
||||
@@ -153,11 +153,8 @@ class Preferences
|
||||
{
|
||||
$fullName = sprintf('preference%s%s', $user->id, $name);
|
||||
if (Cache::has($fullName)) {
|
||||
Log::debug(sprintf('Retrieved preference "%s" from cache ("%s").', $name, $fullName));
|
||||
|
||||
return Cache::get($fullName);
|
||||
}
|
||||
Log::debug(sprintf('Retrieved preference "%s" FRESH.', $name));
|
||||
$preference = Preference::where('user_id', $user->id)->where('name', $name)->first(['id', 'name', 'data', 'updated_at', 'created_at']);
|
||||
if (null !== $preference && null === $preference->data) {
|
||||
try {
|
||||
@@ -192,7 +189,6 @@ class Preferences
|
||||
public function getFreshForUser(User $user, string $name, $default = null): ?Preference
|
||||
{
|
||||
$fullName = sprintf('preference%s%s', $user->id, $name);
|
||||
Log::debug(sprintf('Retrieved preference "%s" FRESH.', $name));
|
||||
$preference = Preference::where('user_id', $user->id)->where('name', $name)->first(['id', 'name', 'data', 'updated_at', 'created_at']);
|
||||
if (null !== $preference && null === $preference->data) {
|
||||
try {
|
||||
@@ -272,7 +268,6 @@ class Preferences
|
||||
public function forget(User $user, string $name): void
|
||||
{
|
||||
$key = sprintf('preference%s%s', $user->id, $name);
|
||||
Log::debug(sprintf('Going to forget key "%s"', $key));
|
||||
Cache::forget($key);
|
||||
Cache::put($key, '', 5);
|
||||
}
|
||||
@@ -307,7 +302,6 @@ class Preferences
|
||||
if (null !== $pref) {
|
||||
$pref->data = $value;
|
||||
$pref->save();
|
||||
Log::debug(sprintf('Saved new value under existing preference object. "%s"', $fullName));
|
||||
Cache::forever($fullName, $pref);
|
||||
|
||||
return $pref;
|
||||
@@ -319,7 +313,6 @@ class Preferences
|
||||
$pref->user()->associate($user);
|
||||
|
||||
$pref->save();
|
||||
Log::debug(sprintf('Saved new value under new preference object. "%s"', $fullName));
|
||||
Cache::forever($fullName, $pref);
|
||||
|
||||
return $pref;
|
||||
|
||||
@@ -154,9 +154,9 @@ class BudgetReportGenerator
|
||||
*/
|
||||
private function generalBudgetReport(): void
|
||||
{
|
||||
$budgets = $this->repository->getBudgets();
|
||||
$budgetList = $this->repository->getBudgets();
|
||||
/** @var Budget $budget */
|
||||
foreach ($budgets as $budget) {
|
||||
foreach ($budgetList as $budget) {
|
||||
$this->processBudget($budget);
|
||||
}
|
||||
}
|
||||
@@ -192,14 +192,14 @@ class BudgetReportGenerator
|
||||
*/
|
||||
private function processLimit(Budget $budget, BudgetLimit $limit): void
|
||||
{
|
||||
$budgetId = (int)$budget->id;
|
||||
$limitId = (int)$limit->id;
|
||||
$currency = $limit->transactionCurrency ?? $this->currency;
|
||||
$currencyId = (int)$currency->id;
|
||||
$expenses = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, $this->accounts, new Collection([$budget]));
|
||||
$spent = $expenses[$currencyId]['sum'] ?? '0';
|
||||
$left = -1 === bccomp(bcadd($limit->amount, $spent), '0') ? '0' : bcadd($limit->amount, $spent);
|
||||
$overspent = 1 === bccomp(bcmul($spent, '-1'), $limit->amount) ? bcadd($spent, $limit->amount) : '0';
|
||||
$budgetId = (int)$budget->id;
|
||||
$limitId = (int)$limit->id;
|
||||
$limitCurrency = $limit->transactionCurrency ?? $this->currency;
|
||||
$currencyId = (int)$limitCurrency->id;
|
||||
$expenses = $this->opsRepository->sumExpenses($limit->start_date, $limit->end_date, $this->accounts, new Collection([$budget]));
|
||||
$spent = $expenses[$currencyId]['sum'] ?? '0';
|
||||
$left = -1 === bccomp(bcadd($limit->amount, $spent), '0') ? '0' : bcadd($limit->amount, $spent);
|
||||
$overspent = 1 === bccomp(bcmul($spent, '-1'), $limit->amount) ? bcadd($spent, $limit->amount) : '0';
|
||||
|
||||
$this->report['budgets'][$budgetId]['budget_limits'][$limitId] = $this->report['budgets'][$budgetId]['budget_limits'][$limitId] ?? [
|
||||
'budget_limit_id' => $limitId,
|
||||
@@ -212,10 +212,10 @@ class BudgetReportGenerator
|
||||
'left' => $left,
|
||||
'overspent' => $overspent,
|
||||
'currency_id' => $currencyId,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'currency_code' => $limitCurrency->code,
|
||||
'currency_name' => $limitCurrency->name,
|
||||
'currency_symbol' => $limitCurrency->symbol,
|
||||
'currency_decimal_places' => $limitCurrency->decimal_places,
|
||||
];
|
||||
|
||||
// make sum information:
|
||||
@@ -226,10 +226,10 @@ class BudgetReportGenerator
|
||||
'left' => '0',
|
||||
'overspent' => '0',
|
||||
'currency_id' => $currencyId,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'currency_code' => $limitCurrency->code,
|
||||
'currency_name' => $limitCurrency->name,
|
||||
'currency_symbol' => $limitCurrency->symbol,
|
||||
'currency_decimal_places' => $limitCurrency->decimal_places,
|
||||
];
|
||||
$this->report['sums'][$currencyId]['budgeted'] = bcadd($this->report['sums'][$currencyId]['budgeted'], $limit->amount);
|
||||
$this->report['sums'][$currencyId]['spent'] = bcadd($this->report['sums'][$currencyId]['spent'], $spent);
|
||||
|
||||
@@ -54,6 +54,7 @@ class Steam
|
||||
$cache->addProperty($account->id);
|
||||
$cache->addProperty('balance');
|
||||
$cache->addProperty($date);
|
||||
$cache->addProperty($currency ? $currency->id : 0);
|
||||
if ($cache->has()) {
|
||||
return $cache->get(); // @codeCoverageIgnore
|
||||
}
|
||||
@@ -186,7 +187,7 @@ class Steam
|
||||
$end->addDay();
|
||||
$balances = [];
|
||||
$formatted = $start->format('Y-m-d');
|
||||
$startBalance = $this->balance($account, $start);
|
||||
$startBalance = $this->balance($account, $start, $currency);
|
||||
|
||||
/** @var AccountRepositoryInterface $repository */
|
||||
|
||||
@@ -196,7 +197,7 @@ class Steam
|
||||
$repository->setUser($account->user);
|
||||
$currency = $repository->getAccountCurrency($account) ?? app('amount')->getDefaultCurrencyByUser($account->user);
|
||||
}
|
||||
$currencyId = $currency->id;
|
||||
$currencyId = (int)$currency->id;
|
||||
|
||||
$start->addDay();
|
||||
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
/*
|
||||
* Breadcrumbs.php
|
||||
* Copyright (c) 2020 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/>.
|
||||
*/
|
||||
|
||||
namespace FireflyIII\Support\Twig;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use Route;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
/**
|
||||
* Class Breadcrumbs
|
||||
*/
|
||||
class Breadcrumbs extends AbstractExtension
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
$this->renderBreadcrumb(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TwigFunction
|
||||
*/
|
||||
private function renderBreadcrumb(): TwigFunction
|
||||
{
|
||||
return new TwigFunction(
|
||||
'ff3bc',
|
||||
static function (?array $args): string {
|
||||
$name = Route::getCurrentRoute()->getName() ?? '';
|
||||
|
||||
// loop for actual breadcrumb:
|
||||
$arr = config(sprintf('bc.%s', $name));
|
||||
|
||||
if (null === $arr) {
|
||||
throw new FireflyException(sprintf('No breadcrumbs for route "%s".', $name));
|
||||
}
|
||||
$breadcrumbs = $this->getBreadcrumbs($arr);
|
||||
|
||||
return $this->getHtml($breadcrumbs);
|
||||
|
||||
},
|
||||
['is_safe' => ['html']]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $arr
|
||||
*
|
||||
* @return array
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getBreadcrumbs(array $arr)
|
||||
{
|
||||
$breadcrumbs = [];
|
||||
$hasParent = true;
|
||||
$loop = 0;
|
||||
while (true === $hasParent && $loop < 30) {
|
||||
$breadcrumbs[] = $arr;
|
||||
if (null === $arr['parent']) {
|
||||
$hasParent = false;
|
||||
|
||||
}
|
||||
if (null !== $arr['parent']) {
|
||||
$arr = config(sprintf('bc.%s', $arr['parent']));
|
||||
if (null === $arr) {
|
||||
throw new FireflyException(sprintf('No (2) breadcrumbs for route "%s".', $name));
|
||||
}
|
||||
}
|
||||
$loop++; // safety catch
|
||||
}
|
||||
|
||||
// reverse order
|
||||
return array_reverse($breadcrumbs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $breadcrumbs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtml(array $breadcrumbs): string
|
||||
{
|
||||
// get HTML
|
||||
$html = '<ol class="breadcrumb float-sm-right">';
|
||||
foreach ($breadcrumbs as $index => $breadcrumb) {
|
||||
$class = 'breadcrumb-item';
|
||||
if ($index === count($breadcrumbs) - 1) {
|
||||
// active!
|
||||
$class = 'breadcrumb-item active';
|
||||
}
|
||||
$route = '#';
|
||||
if (null !== $breadcrumb['static_route']) {
|
||||
$route = route($breadcrumb['static_route']);
|
||||
}
|
||||
if (null !== $breadcrumb['dynamic_route']) {
|
||||
$route = route($breadcrumb['dynamic_route'], $args[$index - 1] ?? []);
|
||||
}
|
||||
$html .= sprintf('<li class="%1$s"><a href="%2$s" title="%3$s">%3$s</a></li>', $class, $route, trans($breadcrumb['title']));
|
||||
}
|
||||
|
||||
return $html . '</ol>';
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,7 @@ namespace FireflyIII\Transformers;
|
||||
|
||||
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@@ -33,8 +34,8 @@ use Illuminate\Support\Collection;
|
||||
*/
|
||||
class CategoryTransformer extends AbstractTransformer
|
||||
{
|
||||
/** @var OperationsRepositoryInterface */
|
||||
private $opsRepository;
|
||||
private OperationsRepositoryInterface $opsRepository;
|
||||
private CategoryRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* CategoryTransformer constructor.
|
||||
@@ -44,6 +45,7 @@ class CategoryTransformer extends AbstractTransformer
|
||||
public function __construct()
|
||||
{
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,6 +58,7 @@ class CategoryTransformer extends AbstractTransformer
|
||||
public function transform(Category $category): array
|
||||
{
|
||||
$this->opsRepository->setUser($category->user);
|
||||
$this->repository->setUser($category->user);
|
||||
|
||||
$spent = [];
|
||||
$earned = [];
|
||||
@@ -65,11 +68,14 @@ class CategoryTransformer extends AbstractTransformer
|
||||
$earned = $this->beautify($this->opsRepository->sumIncome($start, $end, null, new Collection([$category])));
|
||||
$spent = $this->beautify($this->opsRepository->sumExpenses($start, $end, null, new Collection([$category])));
|
||||
}
|
||||
$notes = $this->repository->getNoteText($category);
|
||||
|
||||
return [
|
||||
'id' => (int)$category->id,
|
||||
'created_at' => $category->created_at->toAtomString(),
|
||||
'updated_at' => $category->updated_at->toAtomString(),
|
||||
'name' => $category->name,
|
||||
'notes' => $notes,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'links' => [
|
||||
@@ -90,7 +96,7 @@ class CategoryTransformer extends AbstractTransformer
|
||||
{
|
||||
$return = [];
|
||||
foreach ($array as $data) {
|
||||
$data['sum'] = number_format((float) $data['sum'], (int) $data['currency_decimal_places'], '.', '');
|
||||
$data['sum'] = number_format((float)$data['sum'], (int)$data['currency_decimal_places'], '.', '');
|
||||
$return[] = $data;
|
||||
}
|
||||
|
||||
|
||||
@@ -569,6 +569,6 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
return null;
|
||||
}
|
||||
|
||||
return $object['interest_date']->toAtomString();
|
||||
return $object[$key]->toAtomString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,16 +360,8 @@ class FireflyValidator extends Validator
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
// and finally a "will match everything check":
|
||||
$classes = array_keys(config('firefly.search.operators'));
|
||||
/** @var TriggerInterface $class */
|
||||
$class = $classes[$triggerType] ?? false;
|
||||
if (false === $class) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$class::willMatchEverything($value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
43
changelog.md
43
changelog.md
@@ -2,6 +2,49 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## 5.4.6 (API 1.4.0) - 2020-10-07
|
||||
|
||||
### Added
|
||||
- [Issue 4031](https://github.com/firefly-iii/firefly-iii/issues/4031) Rule groups can be collapsed.
|
||||
- [Issue 4002](https://github.com/firefly-iii/firefly-iii/issues/4002) Category now support notes, although they're not displayed anywhere yet.
|
||||
|
||||
### Changed
|
||||
- Upgrade to Laravel 8
|
||||
|
||||
### Deprecated
|
||||
- Initial release.
|
||||
|
||||
### Removed
|
||||
- Initial release.
|
||||
|
||||
### Fixed
|
||||
- [Issue 4001](https://github.com/firefly-iii/firefly-iii/issues/4001) [issue 4005](https://github.com/firefly-iii/firefly-iii/issues/4005) [issue 4011](https://github.com/firefly-iii/firefly-iii/issues/4011) Special characters are double escaped.
|
||||
- [Issue 4006](https://github.com/firefly-iii/firefly-iii/issues/4006) Unclear error message fixed.
|
||||
- [Issue 4015](https://github.com/firefly-iii/firefly-iii/issues/4015) Better handling of headers in Apache.
|
||||
- [Issue 4023](https://github.com/firefly-iii/firefly-iii/issues/4023) Fix issue with logout and admin view.
|
||||
- Missing help text can now be translated.
|
||||
- Demo sites send messages to me, not "demo@firefly".
|
||||
|
||||
|
||||
### Security
|
||||
- Initial release.
|
||||
|
||||
### API
|
||||
- Initial release
|
||||
|
||||
|
||||
## 5.4.5 (API 1.4.0) - 2020-10-28
|
||||
|
||||
### Fixed
|
||||
- [Issue 3853](https://github.com/firefly-iii/firefly-iii/issues/3853) Could not create rules with IBAN values.
|
||||
- [Issue 3991](https://github.com/firefly-iii/firefly-iii/issues/3991) Hardcoded array key broke editing.
|
||||
- [Issue 3992](https://github.com/firefly-iii/firefly-iii/issues/3992) Amount problems in account chart for multi-currency charts.
|
||||
- [Issue 4000](https://github.com/firefly-iii/firefly-iii/issues/4000) Budget chart did not handle multiple currencies well.
|
||||
- [Issue 4003](https://github.com/firefly-iii/firefly-iii/issues/4003) Was unable to create new auto budget limits in foreign currency.
|
||||
|
||||
### Security
|
||||
- [Issue 3990](https://github.com/firefly-iii/firefly-iii/issues/3990) Unescaped content could break the auto-complete.
|
||||
|
||||
## 5.4.4 (API 1.4.0) - 2020-10-24
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -84,14 +84,15 @@
|
||||
"ext-xml": "*",
|
||||
"adldap2/adldap2-laravel": "6.*",
|
||||
"bacon/bacon-qr-code": "2.*",
|
||||
"davejamesmiller/laravel-breadcrumbs": "5.*",
|
||||
"diglactic/laravel-breadcrumbs": "^6.0",
|
||||
"doctrine/dbal": "2.*",
|
||||
"fideloper/proxy": "4.*",
|
||||
"gdbots/query-parser": "^2.0",
|
||||
"guzzlehttp/guzzle": "^7.2",
|
||||
"jc5/google2fa-laravel": "2.0.5",
|
||||
"laravel/framework": "^7.0",
|
||||
"laravel/passport": "9.*",
|
||||
"laravel/ui": "^2.0",
|
||||
"laravel/framework": "^8.0",
|
||||
"laravel/passport": "10.*",
|
||||
"laravel/ui": "^3.0",
|
||||
"laravelcollective/html": "6.*",
|
||||
"league/commonmark": "1.*",
|
||||
"league/csv": "^9.6",
|
||||
@@ -107,30 +108,22 @@
|
||||
"barryvdh/laravel-ide-helper": "2.*",
|
||||
"ergebnis/phpstan-rules": "^0.15.0",
|
||||
"filp/whoops": "2.*",
|
||||
"fzaninotto/faker": "1.*",
|
||||
"fakerphp/faker": "1.*",
|
||||
"johnkary/phpunit-speedtrap": "^3.1",
|
||||
"mockery/mockery": "1.*",
|
||||
"nunomaduro/larastan": "^0.6.2",
|
||||
"phpstan/phpstan": "^0.12.34",
|
||||
"phpstan/phpstan-deprecation-rules": "^0.12.5",
|
||||
"phpunit/phpunit": "^9.2",
|
||||
"psalm/plugin-laravel": "^1.1",
|
||||
"roave/security-advisories": "dev-master",
|
||||
"thecodingmachine/phpstan-strict-rules": "^0.12.0",
|
||||
"vimeo/psalm": "^3.10"
|
||||
"vimeo/psalm": "^4.1"
|
||||
},
|
||||
"suggest": {
|
||||
},
|
||||
"repositories": [
|
||||
|
||||
],
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"database/seeds",
|
||||
"database/factories"
|
||||
],
|
||||
"psr-4": {
|
||||
"FireflyIII\\": "app/"
|
||||
"FireflyIII\\": "app/",
|
||||
"Database\\Factories\\": "database/factories/",
|
||||
"Database\\Seeders\\": "database/seeders/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
|
||||
2358
composer.lock
generated
2358
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'index' => [
|
||||
'parent' => null,
|
||||
'title' => 'breadcrumbs.home',
|
||||
'static_route' => 'index',
|
||||
'dynamic_route' => null,
|
||||
],
|
||||
'home' => [
|
||||
'parent' => null,
|
||||
'title' => 'breadcrumbs.home',
|
||||
'static_route' => 'index',
|
||||
'dynamic_route' => null,
|
||||
],
|
||||
'accounts' => [
|
||||
'index' => [
|
||||
'parent' => 'index',
|
||||
'title' => 'breadcrumbs.accounts',
|
||||
'static_route' => null,
|
||||
'dynamic_route' => 'accounts.index',
|
||||
],
|
||||
'show' => [
|
||||
'parent' => 'accounts.index',
|
||||
'title' => 'breadcrumbs.accounts_show',
|
||||
'static_route' => null,
|
||||
'dynamic_route' => 'accounts.show',
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -94,8 +94,7 @@ return [
|
||||
'telemetry' => true,
|
||||
],
|
||||
|
||||
//'encryption' => null === env('USE_ENCRYPTION') || true === env('USE_ENCRYPTION'),
|
||||
'version' => '5.4.4',
|
||||
'version' => '5.4.6',
|
||||
'api_version' => '1.4.0',
|
||||
'db_version' => 15,
|
||||
'maxUploadSize' => 1073741824, // 1 GB
|
||||
|
||||
@@ -25,7 +25,6 @@ use TwigBridge\Extension\Laravel\Url;
|
||||
use TwigBridge\Extension\Loader\Facades;
|
||||
use TwigBridge\Extension\Loader\Filters;
|
||||
use TwigBridge\Extension\Loader\Functions;
|
||||
use FireflyIII\Support\Twig\Breadcrumbs;
|
||||
|
||||
/**
|
||||
* Configuration options for Twig.
|
||||
@@ -138,7 +137,6 @@ return [
|
||||
Rule::class,
|
||||
TransactionGroupTwig::class,
|
||||
Translation::class,
|
||||
Breadcrumbs::class,
|
||||
|
||||
],
|
||||
|
||||
@@ -194,8 +192,7 @@ return [
|
||||
],
|
||||
'AccountForm' => [
|
||||
'is_safe' => [
|
||||
'activeAssetAccountList', 'activeLongAccountList', 'activeWithdrawalDestinations', 'activeDepositDestinations',
|
||||
'assetAccountCheckList', 'assetAccountList', 'longAccountList',
|
||||
'activeWithdrawalDestinations', 'activeDepositDestinations', 'assetAccountCheckList', 'assetAccountList', 'longAccountList',
|
||||
],
|
||||
],
|
||||
'CurrencyForm' => [
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @var \Illuminate\Database\Eloquent\Factory $factory */
|
||||
|
||||
use Faker\Generator as Faker;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
|
||||
$factory->define(Account::class, function (Faker $faker) {
|
||||
return [
|
||||
'user_id' => 1,
|
||||
'account_type_id' => 1,
|
||||
'name' => $faker->words(3, true),
|
||||
'virtual_balance' => '0',
|
||||
'active' => 1,
|
||||
'encrypted' => 0,
|
||||
'order' => 1,
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Account::class, AccountType::ASSET, function ($faker) {
|
||||
return [
|
||||
'account_type_id' => 3,
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Account::class, AccountType::INITIAL_BALANCE, function ($faker) {
|
||||
return [
|
||||
'account_type_id' => 6,
|
||||
];
|
||||
});
|
||||
|
||||
$factory->state(Account::class, AccountType::EXPENSE, function ($faker) {
|
||||
return [
|
||||
'account_type_id' => 4,
|
||||
];
|
||||
});
|
||||
101
database/factories/FireflyIII/Models/AccountFactory.php
Normal file
101
database/factories/FireflyIII/Models/AccountFactory.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/*
|
||||
* AccountFactory.php
|
||||
* Copyright (c) 2020 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 Database\Factories\FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* Class AccountFactory
|
||||
*/
|
||||
class AccountFactory extends Factory
|
||||
{
|
||||
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Account::class;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'user_id' => 1,
|
||||
'account_type_id' => 1,
|
||||
'name' => $this->faker->words(3, true),
|
||||
'virtual_balance' => '0',
|
||||
'active' => 1,
|
||||
'encrypted' => 0,
|
||||
'order' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccountFactory
|
||||
*/
|
||||
public function asset()
|
||||
{
|
||||
return $this->state(
|
||||
function () {
|
||||
return [
|
||||
'account_type_id' => 3,
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccountFactory
|
||||
*/
|
||||
public function initialBalance()
|
||||
{
|
||||
return $this->state(
|
||||
function () {
|
||||
return [
|
||||
'account_type_id' => 6,
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AccountFactory
|
||||
*/
|
||||
public function expense()
|
||||
{
|
||||
return $this->state(
|
||||
function () {
|
||||
return [
|
||||
'account_type_id' => 4,
|
||||
];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ZeroOrMore.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
/*
|
||||
* TransactionFactory.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -22,44 +21,35 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Rules;
|
||||
namespace Database\Factories\FireflyIII\Models;
|
||||
|
||||
use Illuminate\Contracts\Validation\Rule;
|
||||
|
||||
use FireflyIII\Models\Transaction;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
*
|
||||
* Class ZeroOrMore
|
||||
* @codeCoverageIgnore
|
||||
* Class TransactionFactory
|
||||
*/
|
||||
class ZeroOrMore implements Rule
|
||||
class TransactionFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = Transaction::class;
|
||||
|
||||
/**
|
||||
* Get the validation error message.
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return string
|
||||
* @return array
|
||||
*/
|
||||
public function message(): string
|
||||
public function definition()
|
||||
{
|
||||
return trans('validation.zero_or_more');
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the validation rule passes.
|
||||
*
|
||||
* @param string $attribute
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function passes($attribute, $value): bool
|
||||
{
|
||||
$value = (string)$value;
|
||||
if ('' === $value) {
|
||||
return true;
|
||||
}
|
||||
$res = bccomp('0', $value);
|
||||
|
||||
return $res <= 0;
|
||||
return [
|
||||
'transaction_journal_id' => 0,
|
||||
'account_id' => 0,
|
||||
'amount' => 5,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
/*
|
||||
* TransactionJournalFactory.php
|
||||
* Copyright (c) 2020 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 Database\Factories\FireflyIII\Models;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
/**
|
||||
* Class TransactionJournalFactory
|
||||
*/
|
||||
class TransactionJournalFactory extends Factory
|
||||
{
|
||||
/**
|
||||
* The name of the factory's corresponding model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $model = TransactionJournal::class;
|
||||
|
||||
/**
|
||||
* Define the model's default state.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function definition()
|
||||
{
|
||||
return [
|
||||
'user_id' => 1,
|
||||
'transaction_type_id' => 1,
|
||||
'description' => $this->faker->words(3, true),
|
||||
'tag_count' => 0,
|
||||
'date' => $this->faker->date('Y-m-d'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
public function openingBalance()
|
||||
{
|
||||
return $this
|
||||
->state(fn () => ['transaction_type_id' => 4])
|
||||
->afterCreating(
|
||||
function (TransactionJournal $journal) {
|
||||
// fix factory
|
||||
$obAccount = Account::factory(Account::class)->initialBalance()->create();
|
||||
$assetAccount = Account::factory(Account::class)->asset()->create();
|
||||
Transaction::factory()->create(
|
||||
[
|
||||
'account_id' => $obAccount->id,
|
||||
'transaction_journal_id' => $journal->id,
|
||||
'amount' => '5',
|
||||
]
|
||||
);
|
||||
Transaction::factory()->create(
|
||||
[
|
||||
'account_id' => $assetAccount->id,
|
||||
'transaction_journal_id' => $journal->id,
|
||||
'amount' => '-5',
|
||||
]
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Factories\Factory
|
||||
*/
|
||||
public function brokenOpeningBalance()
|
||||
{
|
||||
return $this->state(
|
||||
function () {
|
||||
return [
|
||||
'transaction_type_id' => 4,
|
||||
];
|
||||
}
|
||||
)->afterCreating(
|
||||
function (TransactionJournal $journal) {
|
||||
$ob1 = Account::factory(Account::class)->initialBalance()->create();
|
||||
$ob2 = Account::factory(Account::class)->initialBalance()->create();
|
||||
|
||||
Transaction::factory()->create(
|
||||
[
|
||||
'account_id' => $ob1->id,
|
||||
'transaction_journal_id' => $journal->id,
|
||||
'amount' => '5',
|
||||
]
|
||||
);
|
||||
Transaction::factory()->create(
|
||||
[
|
||||
'account_id' => $ob2->id,
|
||||
'transaction_journal_id' => $journal->id,
|
||||
'amount' => '5',
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user