Merge pull request #7565 from firefly-iii/chore/cleanup

chore: code cleanup.
This commit is contained in:
James Cole 2023-05-29 14:01:32 +02:00 committed by GitHub
commit 023a3fdade
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
295 changed files with 12418 additions and 12324 deletions

View File

@ -744,16 +744,16 @@
},
{
"name": "symfony/console",
"version": "v6.2.10",
"version": "v6.2.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "12288d9f4500f84a4d02254d4aa968b15488476f"
"reference": "5aa03db8ef0a5457c316ec580e69562d97734c77"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/12288d9f4500f84a4d02254d4aa968b15488476f",
"reference": "12288d9f4500f84a4d02254d4aa968b15488476f",
"url": "https://api.github.com/repos/symfony/console/zipball/5aa03db8ef0a5457c316ec580e69562d97734c77",
"reference": "5aa03db8ef0a5457c316ec580e69562d97734c77",
"shasum": ""
},
"require": {
@ -820,7 +820,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.2.10"
"source": "https://github.com/symfony/console/tree/v6.2.11"
},
"funding": [
{
@ -836,7 +836,7 @@
"type": "tidelift"
}
],
"time": "2023-04-28T13:37:43+00:00"
"time": "2023-05-26T08:16:21+00:00"
},
{
"name": "symfony/deprecation-contracts",
@ -1755,16 +1755,16 @@
},
{
"name": "symfony/process",
"version": "v6.2.10",
"version": "v6.2.11",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "b34cdbc9c5e75d45a3703e63a48ad07aafa8bf2e"
"reference": "97ae9721bead9d1a39b5650e2f4b7834b93b539c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/b34cdbc9c5e75d45a3703e63a48ad07aafa8bf2e",
"reference": "b34cdbc9c5e75d45a3703e63a48ad07aafa8bf2e",
"url": "https://api.github.com/repos/symfony/process/zipball/97ae9721bead9d1a39b5650e2f4b7834b93b539c",
"reference": "97ae9721bead9d1a39b5650e2f4b7834b93b539c",
"shasum": ""
},
"require": {
@ -1796,7 +1796,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v6.2.10"
"source": "https://github.com/symfony/process/tree/v6.2.11"
},
"funding": [
{
@ -1812,7 +1812,7 @@
"type": "tidelift"
}
],
"time": "2023-04-18T13:56:57+00:00"
"time": "2023-05-19T07:42:48+00:00"
},
{
"name": "symfony/service-contracts",

View File

@ -32,7 +32,10 @@ SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd $SCRIPT_DIR/php-cs-fixer
composer update
rm -f .php-cs-fixer.cache
echo 'Removed cache...'
echo 'Running...'
PHP_CS_FIXER_IGNORE_ENV=true ./vendor/bin/php-cs-fixer fix --config $SCRIPT_DIR/php-cs-fixer/.php-cs-fixer.php --allow-risky=yes
echo 'Done!'
cd $SCRIPT_DIR/..
exit 0

View File

@ -92,7 +92,11 @@ class AccountController extends Controller
if (in_array($account->accountType->type, $this->balanceTypes, true)) {
$balance = app('steam')->balance($account, $date);
$nameWithBalance = sprintf('%s (%s)', $account->name, app('amount')->formatAnything($currency, $balance, false));
$nameWithBalance = sprintf(
'%s (%s)',
$account->name,
app('amount')->formatAnything($currency, $balance, false)
);
}
$return[] = [
@ -113,10 +117,10 @@ class AccountController extends Controller
usort(
$return,
function ($a, $b) use ($order) {
$pos_a = array_search($a['type'], $order, true);
$pos_b = array_search($b['type'], $order, true);
$posA = array_search($a['type'], $order, true);
$posB = array_search($b['type'], $order, true);
return $pos_a - $pos_b;
return $posA - $posB;
}
);

View File

@ -74,6 +74,42 @@ abstract class Controller extends BaseController
);
}
/**
* Method to help build URL's.
*
* @return string
*/
final protected function buildParams(): string
{
$return = '?';
$params = [];
foreach ($this->parameters as $key => $value) {
if ('page' === $key) {
continue;
}
if ($value instanceof Carbon) {
$params[$key] = $value->format('Y-m-d');
continue;
}
$params[$key] = $value;
}
return $return.http_build_query($params);
}
/**
* @return Manager
*/
final protected function getManager(): Manager
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
return $manager;
}
/**
* Method to grab all parameters from the URL.
*
@ -110,7 +146,13 @@ abstract class Controller extends BaseController
$obj = Carbon::parse($date);
} catch (InvalidDateException|InvalidFormatException $e) {
// don't care
app('log')->warning(sprintf('Ignored invalid date "%s" in API controller parameter check: %s', substr($date, 0, 20), $e->getMessage()));
app('log')->warning(
sprintf(
'Ignored invalid date "%s" in API controller parameter check: %s',
substr($date, 0, 20),
$e->getMessage()
)
);
}
}
$bag->set($field, $obj);
@ -169,41 +211,4 @@ abstract class Controller extends BaseController
return $bag;
}
/**
* Method to help build URL's.
*
* @return string
*/
final protected function buildParams(): string
{
$return = '?';
$params = [];
foreach ($this->parameters as $key => $value) {
if ('page' === $key) {
continue;
}
if ($value instanceof Carbon) {
$params[$key] = $value->format('Y-m-d');
continue;
}
$params[$key] = $value;
}
return $return.http_build_query($params);
}
/**
* @return Manager
*/
final protected function getManager(): Manager
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v1';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
return $manager;
}
}

View File

@ -201,91 +201,6 @@ class DestroyController extends Controller
return response()->json([], 204);
}
/**
*
*/
private function destroyBudgets(): void
{
/** @var AvailableBudgetRepositoryInterface $abRepository */
$abRepository = app(AvailableBudgetRepositoryInterface::class);
$abRepository->destroyAll();
/** @var BudgetLimitRepositoryInterface $blRepository */
$blRepository = app(BudgetLimitRepositoryInterface::class);
$blRepository->destroyAll();
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgetRepository->destroyAll();
}
/**
*
*/
private function destroyBills(): void
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyPiggyBanks(): void
{
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRules(): void
{
/** @var RuleGroupRepositoryInterface $repository */
$repository = app(RuleGroupRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRecurringTransactions(): void
{
/** @var RecurringRepositoryInterface $repository */
$repository = app(RecurringRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyCategories(): void
{
/** @var CategoryRepositoryInterface $categoryRepos */
$categoryRepos = app(CategoryRepositoryInterface::class);
$categoryRepos->destroyAll();
}
/**
*
*/
private function destroyTags(): void
{
/** @var TagRepositoryInterface $tagRepository */
$tagRepository = app(TagRepositoryInterface::class);
$tagRepository->destroyAll();
}
private function destroyObjectGroups(): void
{
/** @var ObjectGroupRepositoryInterface $repository */
$repository = app(ObjectGroupRepositoryInterface::class);
$repository->deleteAll();
}
/**
* @param array $types
*/
@ -311,6 +226,91 @@ class DestroyController extends Controller
}
}
/**
*
*/
private function destroyBills(): void
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyBudgets(): void
{
/** @var AvailableBudgetRepositoryInterface $abRepository */
$abRepository = app(AvailableBudgetRepositoryInterface::class);
$abRepository->destroyAll();
/** @var BudgetLimitRepositoryInterface $blRepository */
$blRepository = app(BudgetLimitRepositoryInterface::class);
$blRepository->destroyAll();
/** @var BudgetRepositoryInterface $budgetRepository */
$budgetRepository = app(BudgetRepositoryInterface::class);
$budgetRepository->destroyAll();
}
/**
*
*/
private function destroyCategories(): void
{
/** @var CategoryRepositoryInterface $categoryRepos */
$categoryRepos = app(CategoryRepositoryInterface::class);
$categoryRepos->destroyAll();
}
private function destroyObjectGroups(): void
{
/** @var ObjectGroupRepositoryInterface $repository */
$repository = app(ObjectGroupRepositoryInterface::class);
$repository->deleteAll();
}
/**
*
*/
private function destroyPiggyBanks(): void
{
/** @var PiggyBankRepositoryInterface $repository */
$repository = app(PiggyBankRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRecurringTransactions(): void
{
/** @var RecurringRepositoryInterface $repository */
$repository = app(RecurringRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyRules(): void
{
/** @var RuleGroupRepositoryInterface $repository */
$repository = app(RuleGroupRepositoryInterface::class);
$repository->destroyAll();
}
/**
*
*/
private function destroyTags(): void
{
/** @var TagRepositoryInterface $tagRepository */
$tagRepository = app(TagRepositoryInterface::class);
$tagRepository->destroyAll();
}
/**
* @param array $types
*/

View File

@ -69,34 +69,6 @@ class ExportController extends Controller
return $this->returnExport('accounts');
}
/**
* @param string $key
*
* @return LaravelResponse
* @throws FireflyException
*/
private function returnExport(string $key): LaravelResponse
{
$date = date('Y-m-d-H-i-s');
$fileName = sprintf('%s-export-%s.csv', $date, $key);
$data = $this->exporter->export();
/** @var LaravelResponse $response */
$response = response($data[$key]);
$response
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename='.$fileName)
->header('Content-Transfer-Encoding', 'binary')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', (string)strlen($data[$key]));
return $response;
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/exportBills
@ -228,4 +200,32 @@ class ExportController extends Controller
return $this->returnExport('transactions');
}
/**
* @param string $key
*
* @return LaravelResponse
* @throws FireflyException
*/
private function returnExport(string $key): LaravelResponse
{
$date = date('Y-m-d-H-i-s');
$fileName = sprintf('%s-export-%s.csv', $date, $key);
$data = $this->exporter->export();
/** @var LaravelResponse $response */
$response = response($data[$key]);
$response
->header('Content-Description', 'File Transfer')
->header('Content-Type', 'application/octet-stream')
->header('Content-Disposition', 'attachment; filename='.$fileName)
->header('Content-Transfer-Encoding', 'binary')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', (string)strlen($data[$key]));
return $response;
}
}

View File

@ -43,6 +43,7 @@ class PurgeController extends Controller
* TODO cleanup and use repositories.
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/data/purgeData
*
* @return JsonResponse
*/
public function purge(): JsonResponse

View File

@ -29,8 +29,8 @@ use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
use Preferences;
/**

View File

@ -34,8 +34,8 @@ use FireflyIII\Transformers\AttachmentTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
/**
* Class StoreController

View File

@ -97,21 +97,6 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransactionByJournal
*
* Show a single transaction, by transaction journal.
*
* @param TransactionJournal $transactionJournal
*
* @return JsonResponse
*/
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
{
return $this->show($transactionJournal->transactionGroup);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransaction
@ -148,4 +133,19 @@ class ShowController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/transactions/getTransactionByJournal
*
* Show a single transaction, by transaction journal.
*
* @param TransactionJournal $transactionJournal
*
* @return JsonResponse
*/
public function showJournal(TransactionJournal $transactionJournal): JsonResponse
{
return $this->show($transactionJournal->transactionGroup);
}
}

View File

@ -35,9 +35,9 @@ use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use Validator;
/**

View File

@ -32,8 +32,8 @@ use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use League\Fractal\Resource\Item;
use Illuminate\Support\Facades\Log;
use League\Fractal\Resource\Item;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**

View File

@ -97,6 +97,35 @@ class UpdateController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/enableCurrency
*
* Enable a currency.
*
* @param TransactionCurrency $currency
*
* @return JsonResponse
* @throws FireflyException
* @throws JsonException
*/
public function enable(TransactionCurrency $currency): JsonResponse
{
$this->repository->enable($currency);
$manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/defaultCurrency
@ -128,35 +157,6 @@ class UpdateController extends Controller
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/enableCurrency
*
* Enable a currency.
*
* @param TransactionCurrency $currency
*
* @return JsonResponse
* @throws FireflyException
* @throws JsonException
*/
public function enable(TransactionCurrency $currency): JsonResponse
{
$this->repository->enable($currency);
$manager = $this->getManager();
$defaultCurrency = app('amount')->getDefaultCurrencyByUser(auth()->user());
$this->parameters->set('defaultCurrency', $defaultCurrency);
/** @var CurrencyTransformer $transformer */
$transformer = app(CurrencyTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($currency, $transformer, 'currencies');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/currencies/updateCurrency

View File

@ -32,10 +32,10 @@ use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use JsonException;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use Illuminate\Support\Facades\Log;
/**
* Class AccountController
@ -61,6 +61,7 @@ class AccountController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/search/searchAccounts
*
* @param Request $request
*
* @return JsonResponse|Response

View File

@ -121,6 +121,30 @@ class BasicController extends Controller
return response()->json($return);
}
/**
* Check if date is outside session range.
*
* @param Carbon $date
*
* @param Carbon $start
* @param Carbon $end
*
* @return bool
*/
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
{
$result = false;
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
$result = true;
}
// start and end in the past? use $end
if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
$result = true;
}
return $result;
}
/**
* @param Carbon $start
* @param Carbon $end
@ -399,28 +423,4 @@ class BasicController extends Controller
return $return;
}
/**
* Check if date is outside session range.
*
* @param Carbon $date
*
* @param Carbon $start
* @param Carbon $end
*
* @return bool
*/
protected function notInDateRange(Carbon $date, Carbon $start, Carbon $end): bool // Validate a preference
{
$result = false;
if ($start->greaterThanOrEqualTo($date) && $end->greaterThanOrEqualTo($date)) {
$result = true;
}
// start and end in the past? use $end
if ($start->lessThanOrEqualTo($date) && $end->lessThanOrEqualTo($date)) {
$result = true;
}
return $result;
}
}

View File

@ -94,42 +94,6 @@ class ConfigurationController extends Controller
return response()->json($return);
}
/**
* Get all config values.
*
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
return [
'is_demo_site' => $isDemoSite?->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => $singleUser?->data,
];
}
/**
* @return array
*/
private function getStaticConfiguration(): array
{
$list = EitherConfigKey::$static;
$return = [];
foreach ($list as $key) {
$return[$key] = config($key);
}
return $return;
}
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v1)#/configuration/getSingleConfiguration
@ -200,4 +164,40 @@ class ConfigurationController extends Controller
return response()->json(['data' => $data])->header('Content-Type', self::CONTENT_TYPE);
}
/**
* Get all config values.
*
* @return array
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getDynamicConfiguration(): array
{
$isDemoSite = app('fireflyconfig')->get('is_demo_site');
$updateCheck = app('fireflyconfig')->get('permission_update_check');
$lastCheck = app('fireflyconfig')->get('last_update_check');
$singleUser = app('fireflyconfig')->get('single_user_mode');
return [
'is_demo_site' => $isDemoSite?->data,
'permission_update_check' => null === $updateCheck ? null : (int)$updateCheck->data,
'last_update_check' => null === $lastCheck ? null : (int)$lastCheck->data,
'single_user_mode' => $singleUser?->data,
];
}
/**
* @return array
*/
private function getStaticConfiguration(): array
{
$list = EitherConfigKey::$static;
$return = [];
foreach ($list as $key) {
$return[$key] = config($key);
}
return $return;
}
}

View File

@ -122,6 +122,7 @@ class ShowController extends Controller
*
* @param Webhook $webhook
* @param TransactionGroup $group
*
* @return JsonResponse
*/
public function triggerTransaction(Webhook $webhook, TransactionGroup $group): JsonResponse
@ -141,6 +142,7 @@ class ShowController extends Controller
// trigger event to send them:
event(new RequestedSendWebhookMessages());
return response()->json([], 204);
}
}

View File

@ -83,6 +83,7 @@ class MoveTransactionsRequest extends FormRequest
/**
* @param Validator $validator
*
* @return void
*/
private function validateMove(Validator $validator): void

View File

@ -30,9 +30,9 @@ use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use FireflyIII\Validation\Api\Data\Bulk\ValidatesBulkTransactionQuery;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
use JsonException;
use Illuminate\Support\Facades\Log;
/**
* Class TransactionRequest

View File

@ -82,28 +82,6 @@ class GenericRequest extends FormRequest
return $return;
}
/**
*
*/
private function parseAccounts(): void
{
if (0 !== $this->accounts->count()) {
return;
}
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('accounts');
if (is_array($array)) {
foreach ($array as $accountId) {
$accountId = (int)$accountId;
$account = $repository->find($accountId);
if (null !== $account) {
$this->accounts->push($account);
}
}
}
}
/**
* @return Collection
*/
@ -114,28 +92,6 @@ class GenericRequest extends FormRequest
return $this->bills;
}
/**
*
*/
private function parseBills(): void
{
if (0 !== $this->bills->count()) {
return;
}
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('bills');
if (is_array($array)) {
foreach ($array as $billId) {
$billId = (int)$billId;
$bill = $repository->find($billId);
if (null !== $bill) {
$this->bills->push($bill);
}
}
}
}
/**
* @return Collection
*/
@ -146,28 +102,6 @@ class GenericRequest extends FormRequest
return $this->budgets;
}
/**
*
*/
private function parseBudgets(): void
{
if (0 !== $this->budgets->count()) {
return;
}
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('budgets');
if (is_array($array)) {
foreach ($array as $budgetId) {
$budgetId = (int)$budgetId;
$budget = $repository->find($budgetId);
if (null !== $budget) {
$this->budgets->push($budget);
}
}
}
}
/**
* @return Collection
*/
@ -178,28 +112,6 @@ class GenericRequest extends FormRequest
return $this->categories;
}
/**
*
*/
private function parseCategories(): void
{
if (0 !== $this->categories->count()) {
return;
}
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('categories');
if (is_array($array)) {
foreach ($array as $categoryId) {
$categoryId = (int)$categoryId;
$category = $repository->find($categoryId);
if (null !== $category) {
$this->categories->push($category);
}
}
}
}
/**
* @return Carbon
*/
@ -268,6 +180,114 @@ class GenericRequest extends FormRequest
return $this->tags;
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
// this is cheating, but it works to initialize the collections.
$this->accounts = new Collection();
$this->budgets = new Collection();
$this->categories = new Collection();
$this->bills = new Collection();
$this->tags = new Collection();
return [
'start' => 'required|date',
'end' => 'required|date|after_or_equal:start',
];
}
/**
*
*/
private function parseAccounts(): void
{
if (0 !== $this->accounts->count()) {
return;
}
$repository = app(AccountRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('accounts');
if (is_array($array)) {
foreach ($array as $accountId) {
$accountId = (int)$accountId;
$account = $repository->find($accountId);
if (null !== $account) {
$this->accounts->push($account);
}
}
}
}
/**
*
*/
private function parseBills(): void
{
if (0 !== $this->bills->count()) {
return;
}
$repository = app(BillRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('bills');
if (is_array($array)) {
foreach ($array as $billId) {
$billId = (int)$billId;
$bill = $repository->find($billId);
if (null !== $bill) {
$this->bills->push($bill);
}
}
}
}
/**
*
*/
private function parseBudgets(): void
{
if (0 !== $this->budgets->count()) {
return;
}
$repository = app(BudgetRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('budgets');
if (is_array($array)) {
foreach ($array as $budgetId) {
$budgetId = (int)$budgetId;
$budget = $repository->find($budgetId);
if (null !== $budget) {
$this->budgets->push($budget);
}
}
}
}
/**
*
*/
private function parseCategories(): void
{
if (0 !== $this->categories->count()) {
return;
}
$repository = app(CategoryRepositoryInterface::class);
$repository->setUser(auth()->user());
$array = $this->get('categories');
if (is_array($array)) {
foreach ($array as $categoryId) {
$categoryId = (int)$categoryId;
$category = $repository->find($categoryId);
if (null !== $category) {
$this->categories->push($category);
}
}
}
}
/**
*
*/
@ -289,24 +309,4 @@ class GenericRequest extends FormRequest
}
}
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
// this is cheating, but it works to initialize the collections.
$this->accounts = new Collection();
$this->budgets = new Collection();
$this->categories = new Collection();
$this->bills = new Collection();
$this->tags = new Collection();
return [
'start' => 'required|date',
'end' => 'required|date|after_or_equal:start',
];
}
}

View File

@ -33,7 +33,6 @@ use FireflyIII\Support\Request\AppendsLocationData;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Log;
/**
* Class UpdateRequest
@ -77,6 +76,7 @@ class UpdateRequest extends FormRequest
'liability_start_date' => ['liability_start_date', 'date'],
];
$data = $this->getAllData($fields);
return $this->appendLocationData($data, null);
}

View File

@ -28,8 +28,8 @@ use FireflyIII\Rules\IsBoolean;
use FireflyIII\Support\Request\ChecksLogin;
use FireflyIII\Support\Request\ConvertsDataTypes;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class StoreRequest

View File

@ -73,65 +73,6 @@ class StoreRequest extends FormRequest
];
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return [];
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array
*/
private function getRepetitionData(): array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return [];
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = $repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@ -198,4 +139,63 @@ class StoreRequest extends FormRequest
}
);
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array
*/
private function getRepetitionData(): array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return [];
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = $repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return [];
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
}

View File

@ -80,70 +80,6 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array|null
*/
private function getRepetitionData(): ?array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return null;
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = (string)$repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
if (0 === count($return)) {
return null;
}
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array|null
*/
private function getTransactionData(): ?array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@ -212,4 +148,68 @@ class UpdateRequest extends FormRequest
}
);
}
/**
* Returns the repetition data as it is found in the submitted data.
*
* @return array|null
*/
private function getRepetitionData(): ?array
{
$return = [];
// repetition data:
/** @var array|null $repetitions */
$repetitions = $this->get('repetitions');
if (null === $repetitions) {
return null;
}
/** @var array $repetition */
foreach ($repetitions as $repetition) {
$current = [];
if (array_key_exists('type', $repetition)) {
$current['type'] = $repetition['type'];
}
if (array_key_exists('moment', $repetition)) {
$current['moment'] = (string)$repetition['moment'];
}
if (array_key_exists('skip', $repetition)) {
$current['skip'] = (int)$repetition['skip'];
}
if (array_key_exists('weekend', $repetition)) {
$current['weekend'] = (int)$repetition['weekend'];
}
$return[] = $current;
}
if (0 === count($return)) {
return null;
}
return $return;
}
/**
* Returns the transaction data as it is found in the submitted data. It's a complex method according to code
* standards but it just has a lot of ??-statements because of the fields that may or may not exist.
*
* @return array|null
*/
private function getTransactionData(): ?array
{
$return = [];
// transaction data:
/** @var array|null $transactions */
$transactions = $this->get('transactions');
if (null === $transactions) {
return null;
}
/** @var array $transaction */
foreach ($transactions as $transaction) {
$return[] = $this->getSingleTransactionData($transaction);
}
return $return;
}
}

View File

@ -67,48 +67,6 @@ class StoreRequest extends FormRequest
return $data;
}
/**
* @return array
*/
private function getRuleTriggers(): array
{
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* @return array
*/
private function getRuleActions(): array
{
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@ -162,21 +120,6 @@ class StoreRequest extends FormRequest
);
}
/**
* Adds an error to the validator when there are no triggers in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$triggers = $data['triggers'] ?? [];
// need at least one trigger
if (!is_countable($triggers) || 0 === count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
@ -192,6 +135,35 @@ class StoreRequest extends FormRequest
}
}
/**
* Adds an error to the validator when there are no ACTIVE actions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneActiveAction(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
// need at least one trigger
if (!is_countable($actions) || 0 === count($actions)) {
return;
}
$allInactive = true;
$inactiveIndex = 0;
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
}
}
/**
* Adds an error to the validator when there are no ACTIVE triggers in the array of data.
*
@ -222,31 +194,59 @@ class StoreRequest extends FormRequest
}
/**
* Adds an error to the validator when there are no ACTIVE actions in the array of data.
* Adds an error to the validator when there are no triggers in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneActiveAction(Validator $validator): void
protected function atLeastOneTrigger(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
$triggers = $data['triggers'] ?? [];
// need at least one trigger
if (!is_countable($actions) || 0 === count($actions)) {
return;
}
$allInactive = true;
$inactiveIndex = 0;
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
if (!is_countable($triggers) || 0 === count($triggers)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
/**
* @return array
*/
private function getRuleActions(): array
{
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* @return array
*/
private function getRuleTriggers(): array
{
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'true')),
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
}

View File

@ -52,11 +52,24 @@ class TestRequest extends FormRequest
}
/**
* @return int
* @return array
*/
private function getPage(): int
public function rules(): array
{
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page');
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'accounts' => '',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
];
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts');
}
/**
@ -70,23 +83,10 @@ class TestRequest extends FormRequest
}
/**
* @return array
* @return int
*/
private function getAccounts(): array
private function getPage(): int
{
return $this->get('accounts');
}
/**
* @return array
*/
public function rules(): array
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
'accounts' => '',
'accounts.*' => 'required|exists:accounts,id|belongsToUser:accounts',
];
return 0 === (int)$this->query('page') ? 1 : (int)$this->query('page');
}
}

View File

@ -49,24 +49,6 @@ class TriggerRequest extends FormRequest
];
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts') ?? [];
}
/**
* @return array
*/
@ -79,4 +61,22 @@ class TriggerRequest extends FormRequest
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
];
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts') ?? [];
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', substr($this->query($field), 0, 10));
}
}

View File

@ -73,56 +73,6 @@ class UpdateRequest extends FormRequest
return $return;
}
/**
* @return array|null
*/
private function getRuleTriggers(): ?array
{
if (!$this->has('triggers')) {
return null;
}
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $active,
'stop_processing' => $stopProcessing,
];
}
}
return $return;
}
/**
* @return array|null
*/
private function getRuleActions(): ?array
{
if (!$this->has('actions')) {
return null;
}
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@ -180,6 +130,21 @@ class UpdateRequest extends FormRequest
);
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneAction(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? null;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
@ -195,6 +160,36 @@ class UpdateRequest extends FormRequest
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
*/
protected function atLeastOneValidAction(Validator $validator): void
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
$allInactive = true;
$inactiveIndex = 0;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
return;
}
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
}
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
@ -225,47 +220,52 @@ class UpdateRequest extends FormRequest
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
* @return array|null
*/
protected function atLeastOneAction(Validator $validator): void
private function getRuleActions(): ?array
{
$data = $validator->getData();
$actions = $data['actions'] ?? null;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
if (!$this->has('actions')) {
return null;
}
$actions = $this->get('actions');
$return = [];
if (is_array($actions)) {
foreach ($actions as $action) {
$return[] = [
'type' => $action['type'],
'value' => $action['value'],
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
];
}
}
return $return;
}
/**
* Adds an error to the validator when there are no repetitions in the array of data.
*
* @param Validator $validator
* @return array|null
*/
protected function atLeastOneValidAction(Validator $validator): void
private function getRuleTriggers(): ?array
{
$data = $validator->getData();
$actions = $data['actions'] ?? [];
$allInactive = true;
$inactiveIndex = 0;
// need at least one action
if (is_array($actions) && 0 === count($actions)) {
return;
if (!$this->has('triggers')) {
return null;
}
$triggers = $this->get('triggers');
$return = [];
if (is_array($triggers)) {
foreach ($triggers as $trigger) {
$active = array_key_exists('active', $trigger) ? $trigger['active'] : true;
$stopProcessing = array_key_exists('stop_processing', $trigger) ? $trigger['stop_processing'] : false;
$return[] = [
'type' => $trigger['type'],
'value' => $trigger['value'],
'active' => $active,
'stop_processing' => $stopProcessing,
];
}
}
foreach ($actions as $index => $action) {
$active = array_key_exists('active', $action) ? $action['active'] : true; // assume true
if (true === $active) {
$allInactive = false;
}
if (false === $active) {
$inactiveIndex = $index;
}
}
if (true === $allInactive) {
$validator->errors()->add(sprintf('actions.%d.active', $inactiveIndex), (string)trans('validation.at_least_one_active_action'));
}
return $return;
}
}

View File

@ -49,24 +49,6 @@ class TestRequest extends FormRequest
];
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts');
}
/**
* @return array
*/
@ -79,4 +61,22 @@ class TestRequest extends FormRequest
'accounts.*' => 'exists:accounts,id|belongsToUser:accounts',
];
}
/**
* @return array
*/
private function getAccounts(): array
{
return $this->get('accounts');
}
/**
* @param string $field
*
* @return Carbon|null
*/
private function getDate(string $field): ?Carbon
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
}
}

View File

@ -50,13 +50,14 @@ class TriggerRequest extends FormRequest
}
/**
* @param string $field
*
* @return Carbon|null
* @return array
*/
private function getDate(string $field): ?Carbon
public function rules(): array
{
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
];
}
/**
@ -68,13 +69,12 @@ class TriggerRequest extends FormRequest
}
/**
* @return array
* @param string $field
*
* @return Carbon|null
*/
public function rules(): array
private function getDate(string $field): ?Carbon
{
return [
'start' => 'date',
'end' => 'date|after_or_equal:start',
];
return null === $this->query($field) ? null : Carbon::createFromFormat('Y-m-d', $this->query($field));
}
}

View File

@ -35,8 +35,8 @@ use FireflyIII\Validation\CurrencyValidation;
use FireflyIII\Validation\GroupValidation;
use FireflyIII\Validation\TransactionValidation;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\Validator;
/**
* Class StoreRequest
@ -69,103 +69,6 @@ class StoreRequest extends FormRequest
// TODO include location and ability to process it.
}
/**
* Get transaction data.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
/**
* @var array $transaction
*/
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
'type' => $this->clearString($object['type'], false),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
'currency_code' => $this->clearString((string)$object['currency_code'], false),
// foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
// amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string)$object['amount'], false),
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
// description.
'description' => $this->clearString($object['description'], false),
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']),
'source_name' => $this->clearString((string)$object['source_name'], false),
'source_iban' => $this->clearString((string)$object['source_iban'], false),
'source_number' => $this->clearString((string)$object['source_number'], false),
'source_bic' => $this->clearString((string)$object['source_bic'], false),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name'], false),
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
'destination_number' => $this->clearString((string)$object['destination_number'], false),
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
// budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
'budget_name' => $this->clearString((string)$object['budget_name'], false),
// category info
'category_id' => $this->integerFromValue((string)$object['category_id']),
'category_name' => $this->clearString((string)$object['category_name'], false),
// journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
'bill_name' => $this->clearString((string)$object['bill_name'], false),
// piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
// some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
'notes' => $this->clearString((string)$object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
// all custom fields:
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
'external_id' => $this->clearString((string)$object['external_id'], false),
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
'external_url' => $this->clearString((string)$object['external_url'], false),
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
// custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
];
}
return $return;
}
/**
* The rules that the incoming request must be matched against.
*
@ -294,4 +197,101 @@ class StoreRequest extends FormRequest
}
);
}
/**
* Get transaction data.
*
* @return array
*/
private function getTransactionData(): array
{
$return = [];
/**
* @var array $transaction
*/
foreach ($this->get('transactions') as $transaction) {
$object = new NullArrayObject($transaction);
$return[] = [
'type' => $this->clearString($object['type'], false),
'date' => $this->dateFromValue($object['date']),
'order' => $this->integerFromValue((string)$object['order']),
'currency_id' => $this->integerFromValue((string)$object['currency_id']),
'currency_code' => $this->clearString((string)$object['currency_code'], false),
// foreign currency info:
'foreign_currency_id' => $this->integerFromValue((string)$object['foreign_currency_id']),
'foreign_currency_code' => $this->clearString((string)$object['foreign_currency_code'], false),
// amount and foreign amount. Cannot be 0.
'amount' => $this->clearString((string)$object['amount'], false),
'foreign_amount' => $this->clearString((string)$object['foreign_amount'], false),
// description.
'description' => $this->clearString($object['description'], false),
// source of transaction. If everything is null, assume cash account.
'source_id' => $this->integerFromValue((string)$object['source_id']),
'source_name' => $this->clearString((string)$object['source_name'], false),
'source_iban' => $this->clearString((string)$object['source_iban'], false),
'source_number' => $this->clearString((string)$object['source_number'], false),
'source_bic' => $this->clearString((string)$object['source_bic'], false),
// destination of transaction. If everything is null, assume cash account.
'destination_id' => $this->integerFromValue((string)$object['destination_id']),
'destination_name' => $this->clearString((string)$object['destination_name'], false),
'destination_iban' => $this->clearString((string)$object['destination_iban'], false),
'destination_number' => $this->clearString((string)$object['destination_number'], false),
'destination_bic' => $this->clearString((string)$object['destination_bic'], false),
// budget info
'budget_id' => $this->integerFromValue((string)$object['budget_id']),
'budget_name' => $this->clearString((string)$object['budget_name'], false),
// category info
'category_id' => $this->integerFromValue((string)$object['category_id']),
'category_name' => $this->clearString((string)$object['category_name'], false),
// journal bill reference. Optional. Will only work for withdrawals
'bill_id' => $this->integerFromValue((string)$object['bill_id']),
'bill_name' => $this->clearString((string)$object['bill_name'], false),
// piggy bank reference. Optional. Will only work for transfers
'piggy_bank_id' => $this->integerFromValue((string)$object['piggy_bank_id']),
'piggy_bank_name' => $this->clearString((string)$object['piggy_bank_name'], false),
// some other interesting properties
'reconciled' => $this->convertBoolean((string)$object['reconciled']),
'notes' => $this->clearString((string)$object['notes']),
'tags' => $this->arrayFromValue($object['tags']),
// all custom fields:
'internal_reference' => $this->clearString((string)$object['internal_reference'], false),
'external_id' => $this->clearString((string)$object['external_id'], false),
'original_source' => sprintf('ff3-v%s|api-v%s', config('firefly.version'), config('firefly.api_version')),
'recurrence_id' => $this->integerFromValue($object['recurrence_id']),
'bunq_payment_id' => $this->clearString((string)$object['bunq_payment_id'], false),
'external_url' => $this->clearString((string)$object['external_url'], false),
'sepa_cc' => $this->clearString((string)$object['sepa_cc'], false),
'sepa_ct_op' => $this->clearString((string)$object['sepa_ct_op'], false),
'sepa_ct_id' => $this->clearString((string)$object['sepa_ct_id'], false),
'sepa_db' => $this->clearString((string)$object['sepa_db'], false),
'sepa_country' => $this->clearString((string)$object['sepa_country'], false),
'sepa_ep' => $this->clearString((string)$object['sepa_ep'], false),
'sepa_ci' => $this->clearString((string)$object['sepa_ci'], false),
'sepa_batch_id' => $this->clearString((string)$object['sepa_batch_id'], false),
// custom date fields. Must be Carbon objects. Presence is optional.
'interest_date' => $this->dateFromValue($object['interest_date']),
'book_date' => $this->dateFromValue($object['book_date']),
'process_date' => $this->dateFromValue($object['process_date']),
'due_date' => $this->dateFromValue($object['due_date']),
'payment_date' => $this->dateFromValue($object['payment_date']),
'invoice_date' => $this->dateFromValue($object['invoice_date']),
];
}
return $return;
}
}

View File

@ -62,7 +62,6 @@ class UpdateRequest extends FormRequest
*/
public function getAll(): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
$this->integerFields = [
'order',
@ -292,6 +291,7 @@ class UpdateRequest extends FormRequest
/**
* @param array $current
* @param array $transaction
*
* @return array
*/
private function getFloatData(array $current, array $transaction): array
@ -319,6 +319,7 @@ class UpdateRequest extends FormRequest
public function rules(): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
return [
// basic fields for group:
'group_title' => 'between:1,1000',

View File

@ -29,8 +29,8 @@ use FireflyIII\Api\V2\Request\Autocomplete\AutocompleteRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Administration\Account\AccountRepositoryInterface as AdminAccountRepositoryInterface;
use FireflyIII\Support\Http\Api\AccountFilter;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
@ -43,8 +43,8 @@ class AccountController extends Controller
{
use AccountFilter;
private array $balanceTypes;
private AdminAccountRepositoryInterface $adminRepository;
private array $balanceTypes;
private AccountRepositoryInterface $repository;
/**

View File

@ -53,6 +53,7 @@ class AccountController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(AccountRepositoryInterface::class);
return $next($request);
}
);
@ -63,6 +64,7 @@ class AccountController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/charts/getChartAccountOverview
*
* @param DateRequest $request
*
* @return JsonResponse
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface

View File

@ -64,6 +64,54 @@ class Controller extends BaseController
}
}
/**
* @param string $key
* @param LengthAwarePaginator $paginator
* @param AbstractTransformer $transformer
*
* @return array
*/
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
{
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$objects = $paginator->getCollection();
// the transformer, at this point, needs to collect information that ALL items in the collection
// require, like meta data and stuff like that, and save it for later.
$transformer->collectMetaData($objects);
$resource = new FractalCollection($objects, $transformer, $key);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return $manager->createData($resource)->toArray();
}
/**
* Returns a JSON API object and returns it.
*
* @param string $key
* @param Model $object
* @param AbstractTransformer $transformer
*
* @return array
*/
final protected function jsonApiObject(string $key, Model $object, AbstractTransformer $transformer): array
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$transformer->collectMetaData(new Collection([$object]));
$resource = new Item($object, $transformer, $key);
return $manager->createData($resource)->toArray();
}
/**
* TODO duplicate from V1 controller
* Method to grab all parameters from the URL.
@ -131,49 +179,4 @@ class Controller extends BaseController
return $bag;
}
/**
* @param string $key
* @param LengthAwarePaginator $paginator
* @param AbstractTransformer $transformer
* @return array
*/
final protected function jsonApiList(string $key, LengthAwarePaginator $paginator, AbstractTransformer $transformer): array
{
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$objects = $paginator->getCollection();
// the transformer, at this point, needs to collect information that ALL items in the collection
// require, like meta data and stuff like that, and save it for later.
$transformer->collectMetaData($objects);
$resource = new FractalCollection($objects, $transformer, $key);
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return $manager->createData($resource)->toArray();
}
/**
* Returns a JSON API object and returns it.
*
* @param string $key
* @param Model $object
* @param AbstractTransformer $transformer
* @return array
*/
final protected function jsonApiObject(string $key, Model $object, AbstractTransformer $transformer): array
{
// create some objects:
$manager = new Manager();
$baseUrl = request()->getSchemeAndHttpHost().'/api/v2';
$manager->setSerializer(new JsonApiSerializer($baseUrl));
$transformer->collectMetaData(new Collection([$object]));
$resource = new Item($object, $transformer, $key);
return $manager->createData($resource)->toArray();
}
}

View File

@ -48,6 +48,7 @@ class SumController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BillRepositoryInterface::class);
return $next($request);
}
);
@ -58,6 +59,7 @@ class SumController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/transactions-sum/getBillsPaidTrSum
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function paid(DateRequest $request): JsonResponse
@ -75,6 +77,7 @@ class SumController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/transactions-sum/getBillsUnpaidTrSum
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function unpaid(DateRequest $request): JsonResponse

View File

@ -41,6 +41,7 @@ class ListController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);
}
);
@ -51,6 +52,7 @@ class ListController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/budgets/listBudgets
*
* @param Request $request
*
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
@ -61,6 +63,7 @@ class ListController extends Controller
$paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page'));
$transformer = new BudgetTransformer();
return response()
->api($this->jsonApiList('budgets', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);

View File

@ -48,6 +48,7 @@ class ShowController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);
}
);

View File

@ -48,6 +48,7 @@ class SumController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetRepositoryInterface::class);
return $next($request);
}
);
@ -58,6 +59,7 @@ class SumController extends Controller
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/budgets/getBudgetedForBudget
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function budgeted(DateRequest $request): JsonResponse
@ -72,7 +74,9 @@ class SumController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/budgets/getSpentForBudget
*
* @param DateRequest $request
*
* @return JsonResponse
*/
public function spent(DateRequest $request): JsonResponse

View File

@ -42,6 +42,7 @@ class ListController extends Controller
$this->middleware(
function ($request, $next) {
$this->repository = app(BudgetLimitRepositoryInterface::class);
return $next($request);
}
);
@ -60,6 +61,7 @@ class ListController extends Controller
$paginator = new LengthAwarePaginator($collection, $total, $this->pageSize, $this->parameters->get('page'));
$transformer = new BudgetLimitTransformer();
return response()
->api($this->jsonApiList('budget_limits', $paginator, $transformer))
->header('Content-Type', self::CONTENT_TYPE);

View File

@ -48,6 +48,7 @@ class NetWorthController extends Controller
function ($request, $next) {
$this->netWorth = app(NetWorthInterface::class);
$this->netWorth->setUser(auth()->user());
return $next($request);
}
);
@ -56,7 +57,9 @@ class NetWorthController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/net-worth/getNetWorth
*
* @param SingleDateRequest $request
*
* @return JsonResponse
*/
public function get(SingleDateRequest $request): JsonResponse

View File

@ -37,7 +37,9 @@ class PreferencesController extends Controller
/**
* This endpoint is documented at:
* https://api-docs.firefly-iii.org/?urls.primaryName=2.0.0%20(v2)#/preferences/getPreference
*
* @param Preference $preference
*
* @return JsonResponse
*/
public function get(Preference $preference): JsonResponse

View File

@ -46,6 +46,7 @@ class AccountController extends Controller
*
* @param ListRequest $request
* @param Account $account
*
* @return JsonResponse
*/
public function listTransactions(ListRequest $request, Account $account): JsonResponse

View File

@ -60,6 +60,7 @@ class AutocompleteRequest extends FormRequest
$array = array_diff($array, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION]);
/** @var User $user */
$user = auth()->user();
return [
'types' => $array,
'query' => $this->convertString('query'),

View File

@ -31,6 +31,7 @@ use Illuminate\Support\Collection;
/**
* Class AutoSum
*
* @deprecated
*/
class AutoSum
@ -39,6 +40,7 @@ class AutoSum
* @param Collection $objects
* @param Closure $getCurrency
* @param Closure $getSum
*
* @return array
*/
public function autoSum(Collection $objects, Closure $getCurrency, Closure $getSum): array

View File

@ -91,6 +91,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All auto budget amounts are positive.');
return;
}
/** @var AutoBudget $item */
@ -110,6 +111,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All available budget amounts are positive.');
return;
}
/** @var AvailableBudget $item */
@ -129,6 +131,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All bill amounts are positive.');
return;
}
/** @var Bill $item */
@ -148,6 +151,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All budget limit amounts are positive.');
return;
}
/** @var BudgetLimit $item */
@ -167,6 +171,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All currency exchange rates are positive.');
return;
}
/** @var BudgetLimit $item */
@ -186,6 +191,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All piggy bank amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
@ -207,6 +213,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All recurring transaction amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
@ -227,6 +234,7 @@ class CorrectAmounts extends Command
$count = $set->count();
if (0 === $count) {
$this->info('Correct: All piggy bank repetition amounts are positive.');
return;
}
/** @var PiggyBankRepetition $item */
@ -255,6 +263,7 @@ class CorrectAmounts extends Command
}
if (0 === $fixed) {
$this->info('Correct: All rule trigger amounts are positive.');
return;
}
$this->line(sprintf('Corrected %d rule trigger amount(s).', $fixed));

View File

@ -56,6 +56,7 @@ class CorrectDatabase extends Command
// if table does not exist, return false
if (!Schema::hasTable('users')) {
$this->error('No "users"-table, will not continue.');
return 1;
}
$commands = [

View File

@ -130,6 +130,7 @@ class CorrectOpeningBalanceCurrencies extends Command
return $account;
}
}
return null;
}

View File

@ -63,6 +63,7 @@ class FixIbans extends Command
/**
* @param Collection $accounts
*
* @return void
*/
private function countAndCorrectIbans(Collection $accounts): void
@ -83,7 +84,8 @@ class FixIbans extends Command
if (array_key_exists($iban, $set[$userId])) {
// iban already in use! two exceptions exist:
if (
!(AccountType::EXPENSE === $set[$userId][$iban] && AccountType::REVENUE === $type) && // allowed combination
!(AccountType::EXPENSE === $set[$userId][$iban] && AccountType::REVENUE === $type)
&& // allowed combination
!(AccountType::REVENUE === $set[$userId][$iban] && AccountType::EXPENSE === $type) // also allowed combination.
) {
$this->line(
@ -108,6 +110,7 @@ class FixIbans extends Command
/**
* @param Collection $accounts
*
* @return void
*/
private function filterIbans(Collection $accounts): void

View File

@ -36,11 +36,13 @@ class TriggerCreditCalculation extends Command
public function handle(): int
{
$this->processAccounts();
return 0;
}
/**
* @param Account $account
*
* @return void
*/
private function processAccount(Account $account): void

View File

@ -53,6 +53,7 @@ class CreateGroupMemberships extends Command
/**
* TODO move to helper.
*
* @param User $user
*
* @throws FireflyException

View File

@ -85,6 +85,7 @@ class UpdateGroupInformation extends Command
$group = $user->userGroup;
if (null === $group) {
$this->warn(sprintf('User "%s" has no group.', $user->email));
return;
}
$set = [
@ -112,6 +113,7 @@ class UpdateGroupInformation extends Command
* @param User $user
* @param UserGroup $group
* @param string $className
*
* @return void
*/
private function updateGroupInfoForObject(User $user, UserGroup $group, string $className): void
@ -120,6 +122,7 @@ class UpdateGroupInformation extends Command
$result = $className::where('user_id', $user->id)->where('user_group_id', null)->update(['user_group_id' => $group->id]);
} catch (QueryException $e) {
$this->error(sprintf('Could not update group information for "%s" because of error "%s"', $className, $e->getMessage()));
return;
}
if (0 !== $result) {

View File

@ -54,7 +54,8 @@ class ForceDecimalSize extends Command
protected $description = 'This command resizes DECIMAL columns in MySQL or PostgreSQL and correct amounts (only MySQL).';
protected $signature = 'firefly-iii:force-decimal-size';
private string $cast;
private array $classes = [
private array $classes
= [
'accounts' => Account::class,
'auto_budgets' => AutoBudget::class,
'available_budgets' => AvailableBudget::class,
@ -69,7 +70,8 @@ class ForceDecimalSize extends Command
private string $operator;
private string $regularExpression;
private array $tables = [
private array $tables
= [
'accounts' => ['virtual_balance'],
'auto_budgets' => ['amount'],
'available_budgets' => ['amount'],
@ -102,6 +104,7 @@ class ForceDecimalSize extends Command
$this->updateDecimals();
}
$this->line('Done!');
return 0;
}
@ -110,6 +113,7 @@ class ForceDecimalSize extends Command
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctAccountAmounts(TransactionCurrency $currency, array $fields): void
@ -134,6 +138,7 @@ class ForceDecimalSize extends Command
$result = $query->get(['accounts.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All accounts in %s', $currency->code));
return;
}
/** @var Account $account */
@ -164,12 +169,14 @@ class ForceDecimalSize extends Command
DB::connection()->getPdo()->sqliteCreateFunction('REGEXP', function ($pattern, $value) {
mb_regex_encoding('UTF-8');
$pattern = trim($pattern, '"');
return (false !== mb_ereg($pattern, (string)$value)) ? 1 : 0;
});
}
if (!in_array((string)config('database.default'), ['mysql', 'pgsql', 'sqlite'], true)) {
$this->line(sprintf('Skip correcting amounts, does not support "%s"...', (string)config('database.default')));
return;
}
$this->correctAmountsByCurrency();
@ -195,6 +202,7 @@ class ForceDecimalSize extends Command
* This method loops the available tables that may need fixing, and calls for the right method that can fix them.
*
* @param TransactionCurrency $currency
*
* @return void
* @throws FireflyException
*/
@ -243,8 +251,10 @@ class ForceDecimalSize extends Command
/**
* This method fixes all auto budgets in currency $currency.
*
* @param TransactionCurrency $currency
* @param string $table
*
* @return void
*/
private function correctGeneric(TransactionCurrency $currency, string $table): void
@ -271,6 +281,7 @@ class ForceDecimalSize extends Command
$result = $query->get(['*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All %s in %s', $table, $currency->code));
return;
}
/** @var Model $item */
@ -294,6 +305,7 @@ class ForceDecimalSize extends Command
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctPiggyAmounts(TransactionCurrency $currency, array $fields): void
@ -320,6 +332,7 @@ class ForceDecimalSize extends Command
$result = $query->get(['piggy_banks.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All piggy banks in %s', $currency->code));
return;
}
/** @var PiggyBank $item */
@ -340,8 +353,10 @@ class ForceDecimalSize extends Command
/**
* This method fixes all piggy bank events in currency $currency.
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctPiggyEventAmounts(TransactionCurrency $currency, array $fields): void
@ -369,6 +384,7 @@ class ForceDecimalSize extends Command
$result = $query->get(['piggy_bank_events.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All piggy bank events in %s', $currency->code));
return;
}
/** @var PiggyBankEvent $item */
@ -392,6 +408,7 @@ class ForceDecimalSize extends Command
*
* @param TransactionCurrency $currency
* @param array $fields
*
* @return void
*/
private function correctPiggyRepetitionAmounts(TransactionCurrency $currency, array $fields)
@ -419,6 +436,7 @@ class ForceDecimalSize extends Command
$result = $query->get(['piggy_bank_repetitions.*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All piggy bank repetitions in %s', $currency->code));
return;
}
/** @var PiggyBankRepetition $item */
@ -441,6 +459,7 @@ class ForceDecimalSize extends Command
* This method fixes all transactions in currency $currency.
*
* @param TransactionCurrency $currency
*
* @return void
*/
private function correctTransactionAmounts(TransactionCurrency $currency): void
@ -482,6 +501,7 @@ class ForceDecimalSize extends Command
$result = $query->get(['*']);
if (0 === $result->count()) {
$this->line(sprintf('Correct: All transactions in foreign currency %s', $currency->code));
return;
}
/** @var Transaction $item */
@ -534,6 +554,7 @@ class ForceDecimalSize extends Command
switch ($type) {
default:
$this->error(sprintf('Cannot handle database type "%s".', $type));
return;
case 'pgsql':
$query = sprintf('ALTER TABLE %s ALTER COLUMN %s TYPE DECIMAL(32,12);', $name, $field);

View File

@ -52,6 +52,7 @@ class ForceMigration extends Command
/**
* Execute the console command.
*
* @throws FireflyException
*/
public function handle(): int
@ -69,8 +70,10 @@ class ForceMigration extends Command
$user = $this->getUser();
Log::channel('audit')->info(sprintf('User #%d ("%s") forced migrations.', $user->id, $user->email));
$this->forceMigration();
return 0;
}
return 0;
}

View File

@ -124,6 +124,7 @@ class VerifySecurityAlerts extends Command
/**
* @param array $array
*
* @return void
*/
private function saveSecurityAdvisory(array $array): void

View File

@ -153,6 +153,7 @@ class Cron extends Command
/**
* @param bool $force
* @param Carbon|null $date
*
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface

View File

@ -165,6 +165,7 @@ class DecryptDatabase extends Command
/**
* @param string $table
* @param array $fields
*
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/

View File

@ -85,6 +85,7 @@ class UpgradeLiabilitiesEight extends Command
/**
* @param Account $account
*
* @return void
*/
private function deleteCreditTransaction(Account $account): void
@ -100,6 +101,7 @@ class UpgradeLiabilitiesEight extends Command
$service = new TransactionGroupDestroyService();
$service->destroy($group);
Log::debug(sprintf('Deleted liability credit group #%d', $group->id));
return;
}
Log::debug('No liability credit journal found.');
@ -107,6 +109,7 @@ class UpgradeLiabilitiesEight extends Command
/**
* @param $account
*
* @return int
*/
private function deleteTransactions($account): int
@ -152,11 +155,13 @@ class UpgradeLiabilitiesEight extends Command
$count++;
}
}
return $count;
}
/**
* @param Account $account
*
* @return bool
*/
private function hasBadOpening(Account $account): bool
@ -169,6 +174,7 @@ class UpgradeLiabilitiesEight extends Command
->first(['transaction_journals.*']);
if (null === $openingJournal) {
Log::debug('Account has no opening balance and can be skipped.');
return false;
}
$liabilityJournal = TransactionJournal::leftJoin('transactions', 'transactions.transaction_journal_id', '=', 'transaction_journals.id')
@ -177,10 +183,12 @@ class UpgradeLiabilitiesEight extends Command
->first(['transaction_journals.*']);
if (null === $liabilityJournal) {
Log::debug('Account has no liability credit and can be skipped.');
return false;
}
if (!$openingJournal->date->isSameDay($liabilityJournal->date)) {
Log::debug('Account has opening/credit not on the same day.');
return false;
}
Log::debug('Account has bad opening balance data.');
@ -213,6 +221,7 @@ class UpgradeLiabilitiesEight extends Command
/**
* @param Account $account
*
* @return void
*/
private function reverseOpeningBalance(Account $account): void
@ -235,6 +244,7 @@ class UpgradeLiabilitiesEight extends Command
$source->save();
$dest->save();
Log::debug(sprintf('Opening balance transaction journal #%d reversed.', $openingJournal->id));
return;
}
Log::warning('Did not find opening balance.');

View File

@ -168,45 +168,6 @@ class GracefulNotFoundHandler extends ExceptionHandler
return redirect(route('accounts.index', [$shortType]));
}
/**
* @param Request $request
* @param Throwable $exception
*
* @return Response
* @throws Throwable
*/
private function handleGroup(Request $request, Throwable $exception)
{
Log::debug('404 page is probably a deleted group. Redirect to overview of group types.');
/** @var User $user */
$user = auth()->user();
$route = $request->route();
$groupId = (int)$route->parameter('transactionGroup');
/** @var TransactionGroup|null $group */
$group = $user->transactionGroups()->withTrashed()->find($groupId);
if (null === $group) {
Log::error(sprintf('Could not find group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
/** @var TransactionJournal|null $journal */
$journal = $group->transactionJournals()->withTrashed()->first();
if (null === $journal) {
Log::error(sprintf('Could not find journal for group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
$type = $journal->transactionType->type;
$request->session()->reflash();
if (TransactionType::RECONCILIATION === $type) {
return redirect(route('accounts.index', ['asset']));
}
return redirect(route('transactions.index', [strtolower($type)]));
}
/**
* @param Request $request
* @param Throwable $exception
@ -250,4 +211,43 @@ class GracefulNotFoundHandler extends ExceptionHandler
return parent::render($request, $exception);
}
/**
* @param Request $request
* @param Throwable $exception
*
* @return Response
* @throws Throwable
*/
private function handleGroup(Request $request, Throwable $exception)
{
Log::debug('404 page is probably a deleted group. Redirect to overview of group types.');
/** @var User $user */
$user = auth()->user();
$route = $request->route();
$groupId = (int)$route->parameter('transactionGroup');
/** @var TransactionGroup|null $group */
$group = $user->transactionGroups()->withTrashed()->find($groupId);
if (null === $group) {
Log::error(sprintf('Could not find group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
/** @var TransactionJournal|null $journal */
$journal = $group->transactionJournals()->withTrashed()->first();
if (null === $journal) {
Log::error(sprintf('Could not find journal for group %d, so give big fat error.', $groupId));
return parent::render($request, $exception);
}
$type = $journal->transactionType->type;
$request->session()->reflash();
if (TransactionType::RECONCILIATION === $type) {
return redirect(route('accounts.index', ['asset']));
}
return redirect(route('transactions.index', [strtolower($type)]));
}
}

View File

@ -225,23 +225,6 @@ class Handler extends ExceptionHandler
parent::report($e);
}
/**
* @param Throwable $e
*
* @return bool
*/
private function shouldntReportLocal(Throwable $e): bool
{
return !is_null(
Arr::first(
$this->dontReport,
function ($type) use ($e) {
return $e instanceof $type;
}
)
);
}
/**
* Convert a validation exception into a response.
*
@ -280,4 +263,21 @@ class Handler extends ExceptionHandler
return null !== $previousHost && $previousHost === $safeHost ? $previous : $safe;
}
/**
* @param Throwable $e
*
* @return bool
*/
private function shouldntReportLocal(Throwable $e): bool
{
return !is_null(
Arr::first(
$this->dontReport,
function ($type) use ($e) {
return $e instanceof $type;
}
)
);
}
}

View File

@ -33,8 +33,8 @@ use FireflyIII\Services\Internal\Support\AccountServiceTrait;
use FireflyIII\Services\Internal\Support\LocationServiceTrait;
use FireflyIII\Services\Internal\Update\AccountUpdateService;
use FireflyIII\User;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Factory to create or return accounts.
@ -69,6 +69,47 @@ class AccountFactory
$this->validFields = config('firefly.valid_account_fields');
}
/**
* @param array $data
*
* @return Account
* @throws FireflyException
* @throws JsonException
*/
public function create(array $data): Account
{
Log::debug('Now in AccountFactory::create()');
$type = $this->getAccountType($data);
$data['iban'] = $this->filterIban($data['iban'] ?? null);
// account may exist already:
$return = $this->find($data['name'], $type->type);
if (null !== $return) {
return $return;
}
$return = $this->createAccount($type, $data);
event(new StoredAccount($return));
return $return;
}
/**
* @param string $accountName
* @param string $accountType
*
* @return Account|null
*/
public function find(string $accountName, string $accountType): ?Account
{
Log::debug(sprintf('Now in AccountFactory::find("%s", "%s")', $accountName, $accountType));
$type = AccountType::whereType($accountType)->first();
return $this->user->accounts()->where('account_type_id', $type->id)->where('name', $accountName)->first();
}
/**
* @param string $accountName
* @param string $accountType
@ -106,30 +147,12 @@ class AccountFactory
}
/**
* @param array $data
*
* @return Account
* @throws FireflyException
* @throws JsonException
* @param User $user
*/
public function create(array $data): Account
public function setUser(User $user): void
{
Log::debug('Now in AccountFactory::create()');
$type = $this->getAccountType($data);
$data['iban'] = $this->filterIban($data['iban'] ?? null);
// account may exist already:
$return = $this->find($data['name'], $type->type);
if (null !== $return) {
return $return;
}
$return = $this->createAccount($type, $data);
event(new StoredAccount($return));
return $return;
$this->user = $user;
$this->accountRepository->setUser($user);
}
/**
@ -168,17 +191,32 @@ class AccountFactory
}
/**
* @param string $accountName
* @param string $accountType
* @param Account $account
* @param array $data
*
* @return Account|null
* @return array
* @throws FireflyException
* @throws JsonException
*/
public function find(string $accountName, string $accountType): ?Account
private function cleanMetaDataArray(Account $account, array $data): array
{
Log::debug(sprintf('Now in AccountFactory::find("%s", "%s")', $accountName, $accountType));
$type = AccountType::whereType($accountType)->first();
$currencyId = array_key_exists('currency_id', $data) ? (int)$data['currency_id'] : 0;
$currencyCode = array_key_exists('currency_code', $data) ? (string)$data['currency_code'] : '';
$accountRole = array_key_exists('account_role', $data) ? (string)$data['account_role'] : null;
$currency = $this->getCurrency($currencyId, $currencyCode);
return $this->user->accounts()->where('account_type_id', $type->id)->where('name', $accountName)->first();
// only asset account may have a role:
if ($account->accountType->type !== AccountType::ASSET) {
$accountRole = '';
}
// only liability may have direction:
if (array_key_exists('liability_direction', $data) && !in_array($account->accountType->type, config('firefly.valid_liabilities'), true)) {
$data['liability_direction'] = null;
}
$data['account_role'] = $accountRole;
$data['currency_id'] = $currency->id;
return $data;
}
/**
@ -254,29 +292,29 @@ class AccountFactory
* @param Account $account
* @param array $data
*
* @return array
* @throws FireflyException
* @throws JsonException
*/
private function cleanMetaDataArray(Account $account, array $data): array
private function storeCreditLiability(Account $account, array $data)
{
$currencyId = array_key_exists('currency_id', $data) ? (int)$data['currency_id'] : 0;
$currencyCode = array_key_exists('currency_code', $data) ? (string)$data['currency_code'] : '';
$accountRole = array_key_exists('account_role', $data) ? (string)$data['account_role'] : null;
$currency = $this->getCurrency($currencyId, $currencyCode);
// only asset account may have a role:
if ($account->accountType->type !== AccountType::ASSET) {
$accountRole = '';
Log::debug('storeCreditLiability');
$account->refresh();
$accountType = $account->accountType->type;
$direction = $this->accountRepository->getMetaValue($account, 'liability_direction');
$valid = config('firefly.valid_liabilities');
if (in_array($accountType, $valid, true)) {
Log::debug('Is a liability with credit ("i am owed") direction.');
if ($this->validOBData($data)) {
Log::debug('Has valid CL data.');
$openingBalance = $data['opening_balance'];
$openingBalanceDate = $data['opening_balance_date'];
// store credit transaction.
$this->updateCreditTransaction($account, $direction, $openingBalance, $openingBalanceDate);
}
if (!$this->validOBData($data)) {
Log::debug('Does NOT have valid CL data, deletr any CL transaction.');
$this->deleteCreditTransaction($account);
}
// only liability may have direction:
if (array_key_exists('liability_direction', $data) && !in_array($account->accountType->type, config('firefly.valid_liabilities'), true)) {
$data['liability_direction'] = null;
}
$data['account_role'] = $accountRole;
$data['currency_id'] = $currency->id;
return $data;
}
/**
@ -344,35 +382,6 @@ class AccountFactory
}
}
/**
* @param Account $account
* @param array $data
*
* @throws FireflyException
*/
private function storeCreditLiability(Account $account, array $data)
{
Log::debug('storeCreditLiability');
$account->refresh();
$accountType = $account->accountType->type;
$direction = $this->accountRepository->getMetaValue($account, 'liability_direction');
$valid = config('firefly.valid_liabilities');
if (in_array($accountType, $valid, true)) {
Log::debug('Is a liability with credit ("i am owed") direction.');
if ($this->validOBData($data)) {
Log::debug('Has valid CL data.');
$openingBalance = $data['opening_balance'];
$openingBalanceDate = $data['opening_balance_date'];
// store credit transaction.
$this->updateCreditTransaction($account, $direction, $openingBalance, $openingBalanceDate);
}
if (!$this->validOBData($data)) {
Log::debug('Does NOT have valid CL data, deletr any CL transaction.');
$this->deleteCreditTransaction($account);
}
}
}
/**
* @param Account $account
* @param array $data
@ -396,13 +405,4 @@ class AccountFactory
$updateService->setUser($account->user);
$updateService->update($account, ['order' => $order]);
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->accountRepository->setUser($user);
}
}

View File

@ -33,6 +33,16 @@ use Illuminate\Support\Facades\Log;
*/
class AccountMetaFactory
{
/**
* @param array $data
*
* @return AccountMeta|null
*/
public function create(array $data): ?AccountMeta
{
return AccountMeta::create($data);
}
/**
* Create update or delete meta data.
*
@ -68,14 +78,4 @@ class AccountMetaFactory
return $entry;
}
/**
* @param array $data
*
* @return AccountMeta|null
*/
public function create(array $data): ?AccountMeta
{
return AccountMeta::create($data);
}
}

View File

@ -30,8 +30,8 @@ use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
use FireflyIII\Services\Internal\Support\BillServiceTrait;
use FireflyIII\User;
use Illuminate\Database\QueryException;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class BillFactory

View File

@ -36,6 +36,16 @@ class CategoryFactory
{
private User $user;
/**
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
return $this->user->categories()->where('name', $name)->first();
}
/**
* @param int|null $categoryId
* @param null|string $categoryName
@ -83,16 +93,6 @@ class CategoryFactory
return null;
}
/**
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
return $this->user->categories()->where('name', $name)->first();
}
/**
* @param User $user
*/

View File

@ -25,7 +25,6 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Support\Facades\Log;

View File

@ -29,9 +29,9 @@ use FireflyIII\Models\Recurrence;
use FireflyIII\Services\Internal\Support\RecurringTransactionTrait;
use FireflyIII\Services\Internal\Support\TransactionTypeTrait;
use FireflyIII\User;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\MessageBag;
use JsonException;
use Illuminate\Support\Facades\Log;
/**
* Class RecurrenceFactory

View File

@ -35,6 +35,40 @@ class TagFactory
{
private User $user;
/**
* @param array $data
*
* @return Tag|null
*/
public function create(array $data): ?Tag
{
$zoomLevel = 0 === (int)$data['zoom_level'] ? null : (int)$data['zoom_level'];
$latitude = 0.0 === (float)$data['latitude'] ? null : (float)$data['latitude']; // intentional float
$longitude = 0.0 === (float)$data['longitude'] ? null : (float)$data['longitude']; // intentional float
$array = [
'user_id' => $this->user->id,
'tag' => trim($data['tag']),
'tagMode' => 'nothing',
'date' => $data['date'],
'description' => $data['description'],
'latitude' => null,
'longitude' => null,
'zoomLevel' => null,
];
$tag = Tag::create($array);
if (null !== $tag && null !== $latitude && null !== $longitude) {
// create location object.
$location = new Location();
$location->latitude = $latitude;
$location->longitude = $longitude;
$location->zoom_level = $zoomLevel;
$location->locatable()->associate($tag);
$location->save();
}
return $tag;
}
/**
* @param string $tag
*
@ -72,40 +106,6 @@ class TagFactory
return $newTag;
}
/**
* @param array $data
*
* @return Tag|null
*/
public function create(array $data): ?Tag
{
$zoomLevel = 0 === (int)$data['zoom_level'] ? null : (int)$data['zoom_level'];
$latitude = 0.0 === (float)$data['latitude'] ? null : (float)$data['latitude']; // intentional float
$longitude = 0.0 === (float)$data['longitude'] ? null : (float)$data['longitude']; // intentional float
$array = [
'user_id' => $this->user->id,
'tag' => trim($data['tag']),
'tagMode' => 'nothing',
'date' => $data['date'],
'description' => $data['description'],
'latitude' => null,
'longitude' => null,
'zoomLevel' => null,
];
$tag = Tag::create($array);
if (null !== $tag && null !== $latitude && null !== $longitude) {
// create location object.
$location = new Location();
$location->latitude = $latitude;
$location->longitude = $longitude;
$location->zoom_level = $zoomLevel;
$location->locatable()->associate($tag);
$location->save();
}
return $tag;
}
/**
* @param User $user
*/

View File

@ -80,6 +80,95 @@ class TransactionFactory
return $this->create(app('steam')->negative($amount), $foreignAmount);
}
/**
* Create transaction with positive amount (for destination accounts).
*
* @param string $amount
* @param string|null $foreignAmount
*
* @return Transaction
* @throws FireflyException
*/
public function createPositive(string $amount, ?string $foreignAmount): Transaction
{
if ('' === $foreignAmount) {
$foreignAmount = null;
}
if (null !== $foreignAmount) {
$foreignAmount = app('steam')->positive($foreignAmount);
}
return $this->create(app('steam')->positive($amount), $foreignAmount);
}
/**
* @param Account $account
*
*/
public function setAccount(Account $account): void
{
$this->account = $account;
}
/**
* @param array $accountInformation
*/
public function setAccountInformation(array $accountInformation): void
{
$this->accountInformation = $accountInformation;
}
/**
* @param TransactionCurrency $currency
*
*/
public function setCurrency(TransactionCurrency $currency): void
{
$this->currency = $currency;
}
/**
* @param TransactionCurrency|null $foreignCurrency |null
*
*/
public function setForeignCurrency(?TransactionCurrency $foreignCurrency): void
{
$this->foreignCurrency = $foreignCurrency;
}
/**
* @param TransactionJournal $journal
*
*/
public function setJournal(TransactionJournal $journal): void
{
$this->journal = $journal;
}
/**
* @param bool $reconciled
*
*/
public function setReconciled(bool $reconciled): void
{
$this->reconciled = $reconciled;
}
/**
* @param User $user
*
*/
public function setUser(User $user): void
{
// empty function.
}
/**
* @param string $amount
* @param string|null $foreignAmount
@ -171,93 +260,4 @@ class TransactionFactory
$service = app(AccountUpdateService::class);
$service->update($this->account, ['iban' => $this->accountInformation['iban']]);
}
/**
* Create transaction with positive amount (for destination accounts).
*
* @param string $amount
* @param string|null $foreignAmount
*
* @return Transaction
* @throws FireflyException
*/
public function createPositive(string $amount, ?string $foreignAmount): Transaction
{
if ('' === $foreignAmount) {
$foreignAmount = null;
}
if (null !== $foreignAmount) {
$foreignAmount = app('steam')->positive($foreignAmount);
}
return $this->create(app('steam')->positive($amount), $foreignAmount);
}
/**
* @param Account $account
*
*/
public function setAccount(Account $account): void
{
$this->account = $account;
}
/**
* @param array $accountInformation
*/
public function setAccountInformation(array $accountInformation): void
{
$this->accountInformation = $accountInformation;
}
/**
* @param TransactionCurrency $currency
*
*/
public function setCurrency(TransactionCurrency $currency): void
{
$this->currency = $currency;
}
/**
* @param TransactionCurrency|null $foreignCurrency |null
*
*/
public function setForeignCurrency(?TransactionCurrency $foreignCurrency): void
{
$this->foreignCurrency = $foreignCurrency;
}
/**
* @param TransactionJournal $journal
*
*/
public function setJournal(TransactionJournal $journal): void
{
$this->journal = $journal;
}
/**
* @param bool $reconciled
*
*/
public function setReconciled(bool $reconciled): void
{
$this->reconciled = $reconciled;
}
/**
* @param User $user
*
*/
public function setUser(User $user): void
{
// empty function.
}
}

View File

@ -27,8 +27,8 @@ use FireflyIII\Exceptions\DuplicateTransactionException;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\User;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class TransactionGroupFactory

View File

@ -48,8 +48,8 @@ use FireflyIII\Support\NullArrayObject;
use FireflyIII\User;
use FireflyIII\Validation\AccountValidator;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class TransactionJournalFactory
@ -143,6 +143,79 @@ class TransactionJournalFactory
return $collection;
}
/**
* @param bool $errorOnHash
*/
public function setErrorOnHash(bool $errorOnHash): void
{
$this->errorOnHash = $errorOnHash;
if (true === $errorOnHash) {
Log::info('Will trigger duplication alert for this journal.');
}
}
/**
* Set the user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->currencyRepository->setUser($this->user);
$this->tagFactory->setUser($user);
$this->billRepository->setUser($this->user);
$this->budgetRepository->setUser($this->user);
$this->categoryRepository->setUser($this->user);
$this->piggyRepository->setUser($this->user);
$this->accountRepository->setUser($this->user);
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $data
* @param string $field
*/
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
{
$set = [
'journal' => $journal,
'name' => $field,
'data' => (string)($data[$field] ?? ''),
];
if ($data[$field] instanceof Carbon) {
$data[$field]->setTimezone(config('app.timezone'));
Log::debug(sprintf('%s Date: %s (%s)', $field, $data[$field], $data[$field]->timezone->getName()));
$set['data'] = $data[$field]->format('Y-m-d H:i:s');
}
Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data']));
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
$factory->updateOrCreate($set);
}
/**
* Set foreign currency to NULL if it's the same as the normal currency:
*
* @param TransactionCurrency|null $currency
* @param TransactionCurrency|null $foreignCurrency
*
* @return TransactionCurrency|null
*/
private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency
{
if (null === $currency) {
return null;
}
if (null !== $foreignCurrency && $foreignCurrency->id === $currency->id) {
return null;
}
return $foreignCurrency;
}
/**
* @param NullArrayObject $row
*
@ -304,24 +377,6 @@ class TransactionJournalFactory
return $journal;
}
/**
* @param NullArrayObject $row
*
* @return string
* @throws JsonException
*/
private function hashArray(NullArrayObject $row): string
{
$dataRow = $row->getArrayCopy();
unset($dataRow['import_hash_v2'], $dataRow['original_source']);
$json = json_encode($dataRow, JSON_THROW_ON_ERROR);
$hash = hash('sha256', $json);
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
return $hash;
}
/**
* If this transaction already exists, throw an error.
*
@ -354,6 +409,183 @@ class TransactionJournalFactory
}
}
/**
* Force the deletion of an entire set of transaction journals and their meta object in case of
* an error creating a group.
*
* @param Collection $collection
*/
private function forceDeleteOnError(Collection $collection): void
{
Log::debug(sprintf('forceDeleteOnError on collection size %d item(s)', $collection->count()));
$service = app(JournalDestroyService::class);
/** @var TransactionJournal $journal */
foreach ($collection as $journal) {
Log::debug(sprintf('forceDeleteOnError on journal #%d', $journal->id));
$service->destroy($journal);
}
}
/**
* @param Transaction $transaction
*/
private function forceTrDelete(Transaction $transaction): void
{
$transaction->delete();
}
/**
* @param TransactionCurrency|null $currency
* @param Account $account
*
* @return TransactionCurrency
* @throws FireflyException
* @throws JsonException
*/
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{
Log::debug('Now in getCurrency()');
/** @var Preference|null $preference */
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:
return app('amount')->getDefaultCurrencyByUser($this->user);
}
$result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency();
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
return $result;
}
/**
* @param string $type
* @param TransactionCurrency|null $currency
* @param Account $source
* @param Account $destination
*
* @return TransactionCurrency
* @throws FireflyException
* @throws JsonException
*/
private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency
{
Log::debug('Now in getCurrencyByAccount()');
return match ($type) {
default => $this->getCurrency($currency, $source),
TransactionType::DEPOSIT => $this->getCurrency($currency, $destination),
};
}
/**
* @param string $description
*
* @return string
*/
private function getDescription(string $description): string
{
$description = '' === $description ? '(empty description)' : $description;
return substr($description, 0, 255);
}
/**
* @param string $type
* @param TransactionCurrency|null $foreignCurrency
* @param Account $destination
*
* @return TransactionCurrency|null
* @throws FireflyException
* @throws JsonException
*/
private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency
{
if (TransactionType::TRANSFER === $type) {
return $this->getCurrency($foreignCurrency, $destination);
}
return $foreignCurrency;
}
/**
* @param NullArrayObject $row
*
* @return string
* @throws JsonException
*/
private function hashArray(NullArrayObject $row): string
{
$dataRow = $row->getArrayCopy();
unset($dataRow['import_hash_v2'], $dataRow['original_source']);
$json = json_encode($dataRow, JSON_THROW_ON_ERROR);
$hash = hash('sha256', $json);
Log::debug(sprintf('The hash is: %s', $hash), $dataRow);
return $hash;
}
/**
* @param Account|null $sourceAccount
* @param Account|null $destinationAccount
* @return array
*/
private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
if (null !== $sourceAccount && null !== $destinationAccount) {
Log::debug('Both accounts exist, simply return them.');
return [$sourceAccount, $destinationAccount];
}
if (null !== $sourceAccount && null === $destinationAccount) {
Log::debug('Destination account is NULL, source account is not.');
$account = $this->accountRepository->getReconciliation($sourceAccount);
Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type));
return [$sourceAccount, $account];
}
if (null === $sourceAccount && null !== $destinationAccount) {
Log::debug('Source account is NULL, destination account is not.');
$account = $this->accountRepository->getReconciliation($destinationAccount);
Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type));
return [$account, $destinationAccount];
}
Log::debug('Unused fallback');
return [$sourceAccount, $destinationAccount];
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $transaction
*/
private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
{
foreach ($this->fields as $field) {
$this->storeMeta($journal, $transaction, $field);
}
}
/**
* Link a piggy bank to this journal.
*
* @param TransactionJournal $journal
* @param NullArrayObject $data
*/
private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void
{
Log::debug('Will now store piggy event.');
$piggyBank = $this->piggyRepository->findPiggyBank((int)$data['piggy_bank_id'], $data['piggy_bank_name']);
if (null !== $piggyBank) {
$this->piggyEventFactory->create($journal, $piggyBank);
Log::debug('Create piggy event.');
return;
}
Log::debug('Create no piggy event');
}
/**
* @param NullArrayObject $data
*
@ -395,236 +627,4 @@ class TransactionJournalFactory
throw new FireflyException(sprintf('Destination: %s', $this->accountValidator->destError));
}
}
/**
* Set the user.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
$this->currencyRepository->setUser($this->user);
$this->tagFactory->setUser($user);
$this->billRepository->setUser($this->user);
$this->budgetRepository->setUser($this->user);
$this->categoryRepository->setUser($this->user);
$this->piggyRepository->setUser($this->user);
$this->accountRepository->setUser($this->user);
}
/**
* @param Account|null $sourceAccount
* @param Account|null $destinationAccount
* @return array
*/
private function reconciliationSanityCheck(?Account $sourceAccount, ?Account $destinationAccount): array
{
Log::debug(sprintf('Now in %s', __METHOD__));
if (null !== $sourceAccount && null !== $destinationAccount) {
Log::debug('Both accounts exist, simply return them.');
return [$sourceAccount, $destinationAccount];
}
if (null !== $sourceAccount && null === $destinationAccount) {
Log::debug('Destination account is NULL, source account is not.');
$account = $this->accountRepository->getReconciliation($sourceAccount);
Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type));
return [$sourceAccount, $account];
}
if (null === $sourceAccount && null !== $destinationAccount) {
Log::debug('Source account is NULL, destination account is not.');
$account = $this->accountRepository->getReconciliation($destinationAccount);
Log::debug(sprintf('Will return account #%d ("%s") of type "%s"', $account->id, $account->name, $account->accountType->type));
return [$account, $destinationAccount];
}
Log::debug('Unused fallback');
return [$sourceAccount, $destinationAccount];
}
/**
* @param string $type
* @param TransactionCurrency|null $currency
* @param Account $source
* @param Account $destination
*
* @return TransactionCurrency
* @throws FireflyException
* @throws JsonException
*/
private function getCurrencyByAccount(string $type, ?TransactionCurrency $currency, Account $source, Account $destination): TransactionCurrency
{
Log::debug('Now in getCurrencyByAccount()');
return match ($type) {
default => $this->getCurrency($currency, $source),
TransactionType::DEPOSIT => $this->getCurrency($currency, $destination),
};
}
/**
* @param TransactionCurrency|null $currency
* @param Account $account
*
* @return TransactionCurrency
* @throws FireflyException
* @throws JsonException
*/
private function getCurrency(?TransactionCurrency $currency, Account $account): TransactionCurrency
{
Log::debug('Now in getCurrency()');
/** @var Preference|null $preference */
$preference = $this->accountRepository->getAccountCurrency($account);
if (null === $preference && null === $currency) {
// return user's default:
return app('amount')->getDefaultCurrencyByUser($this->user);
}
$result = ($preference ?? $currency) ?? app('amount')->getSystemCurrency();
Log::debug(sprintf('Currency is now #%d (%s) because of account #%d (%s)', $result->id, $result->code, $account->id, $account->name));
return $result;
}
/**
* Set foreign currency to NULL if it's the same as the normal currency:
*
* @param TransactionCurrency|null $currency
* @param TransactionCurrency|null $foreignCurrency
*
* @return TransactionCurrency|null
*/
private function compareCurrencies(?TransactionCurrency $currency, ?TransactionCurrency $foreignCurrency): ?TransactionCurrency
{
if (null === $currency) {
return null;
}
if (null !== $foreignCurrency && $foreignCurrency->id === $currency->id) {
return null;
}
return $foreignCurrency;
}
/**
* @param string $type
* @param TransactionCurrency|null $foreignCurrency
* @param Account $destination
*
* @return TransactionCurrency|null
* @throws FireflyException
* @throws JsonException
*/
private function getForeignByAccount(string $type, ?TransactionCurrency $foreignCurrency, Account $destination): ?TransactionCurrency
{
if (TransactionType::TRANSFER === $type) {
return $this->getCurrency($foreignCurrency, $destination);
}
return $foreignCurrency;
}
/**
* @param string $description
*
* @return string
*/
private function getDescription(string $description): string
{
$description = '' === $description ? '(empty description)' : $description;
return substr($description, 0, 255);
}
/**
* Force the deletion of an entire set of transaction journals and their meta object in case of
* an error creating a group.
*
* @param Collection $collection
*/
private function forceDeleteOnError(Collection $collection): void
{
Log::debug(sprintf('forceDeleteOnError on collection size %d item(s)', $collection->count()));
$service = app(JournalDestroyService::class);
/** @var TransactionJournal $journal */
foreach ($collection as $journal) {
Log::debug(sprintf('forceDeleteOnError on journal #%d', $journal->id));
$service->destroy($journal);
}
}
/**
* @param Transaction $transaction
*/
private function forceTrDelete(Transaction $transaction): void
{
$transaction->delete();
}
/**
* Link a piggy bank to this journal.
*
* @param TransactionJournal $journal
* @param NullArrayObject $data
*/
private function storePiggyEvent(TransactionJournal $journal, NullArrayObject $data): void
{
Log::debug('Will now store piggy event.');
$piggyBank = $this->piggyRepository->findPiggyBank((int)$data['piggy_bank_id'], $data['piggy_bank_name']);
if (null !== $piggyBank) {
$this->piggyEventFactory->create($journal, $piggyBank);
Log::debug('Create piggy event.');
return;
}
Log::debug('Create no piggy event');
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $transaction
*/
private function storeMetaFields(TransactionJournal $journal, NullArrayObject $transaction): void
{
foreach ($this->fields as $field) {
$this->storeMeta($journal, $transaction, $field);
}
}
/**
* @param TransactionJournal $journal
* @param NullArrayObject $data
* @param string $field
*/
protected function storeMeta(TransactionJournal $journal, NullArrayObject $data, string $field): void
{
$set = [
'journal' => $journal,
'name' => $field,
'data' => (string)($data[$field] ?? ''),
];
if ($data[$field] instanceof Carbon) {
$data[$field]->setTimezone(config('app.timezone'));
Log::debug(sprintf('%s Date: %s (%s)', $field, $data[$field], $data[$field]->timezone->getName()));
$set['data'] = $data[$field]->format('Y-m-d H:i:s');
}
Log::debug(sprintf('Going to store meta-field "%s", with value "%s".', $set['name'], $set['data']));
/** @var TransactionJournalMetaFactory $factory */
$factory = app(TransactionJournalMetaFactory::class);
$factory->updateOrCreate($set);
}
/**
* @param bool $errorOnHash
*/
public function setErrorOnHash(bool $errorOnHash): void
{
$this->errorOnHash = $errorOnHash;
if (true === $errorOnHash) {
Log::info('Will trigger duplication alert for this journal.');
}
}
}

View File

@ -68,16 +68,6 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $result;
}
/**
* Return the preferred period.
*
* @return string
*/
protected function preferredPeriod(): string
{
return 'day';
}
/**
* Set accounts.
*
@ -169,4 +159,14 @@ class MonthReportGenerator implements ReportGeneratorInterface
{
return $this;
}
/**
* Return the preferred period.
*
* @return string
*/
protected function preferredPeriod(): string
{
return 'day';
}
}

View File

@ -31,8 +31,8 @@ use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Throwable;
/**

View File

@ -82,6 +82,34 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $result;
}
/**
* Set the involved accounts.
*
* @param Collection $accounts
*
* @return ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface
{
$this->accounts = $accounts;
return $this;
}
/**
* Set the involved budgets.
*
* @param Collection $budgets
*
* @return ReportGeneratorInterface
*/
public function setBudgets(Collection $budgets): ReportGeneratorInterface
{
$this->budgets = $budgets;
return $this;
}
/**
* Unused category setter.
*
@ -172,32 +200,4 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $journals;
}
/**
* Set the involved budgets.
*
* @param Collection $budgets
*
* @return ReportGeneratorInterface
*/
public function setBudgets(Collection $budgets): ReportGeneratorInterface
{
$this->budgets = $budgets;
return $this;
}
/**
* Set the involved accounts.
*
* @param Collection $accounts
*
* @return ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface
{
$this->accounts = $accounts;
return $this;
}
}

View File

@ -82,6 +82,20 @@ class MonthReportGenerator implements ReportGeneratorInterface
}
}
/**
* Set the involved accounts.
*
* @param Collection $accounts
*
* @return ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface
{
$this->accounts = $accounts;
return $this;
}
/**
* Empty budget setter.
*
@ -94,6 +108,20 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $this;
}
/**
* Set the categories involved in this report.
*
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
$this->categories = $categories;
return $this;
}
/**
* Set the end date for this report.
*
@ -171,34 +199,6 @@ class MonthReportGenerator implements ReportGeneratorInterface
return $transactions;
}
/**
* Set the categories involved in this report.
*
* @param Collection $categories
*
* @return ReportGeneratorInterface
*/
public function setCategories(Collection $categories): ReportGeneratorInterface
{
$this->categories = $categories;
return $this;
}
/**
* Set the involved accounts.
*
* @param Collection $accounts
*
* @return ReportGeneratorInterface
*/
public function setAccounts(Collection $accounts): ReportGeneratorInterface
{
$this->accounts = $accounts;
return $this;
}
/**
* Get the income for this report.
*

View File

@ -37,8 +37,8 @@ use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
use Ramsey\Uuid\Uuid;
use Symfony\Component\HttpFoundation\ParameterBag;
@ -81,38 +81,62 @@ class StandardMessageGenerator implements MessageGeneratorInterface
}
/**
* @inheritDoc
*/
public function getVersion(): int
{
return $this->version;
}
/**
* @param Collection $objects
*/
public function setObjects(Collection $objects): void
{
$this->objects = $objects;
}
/**
* @param int $trigger
*/
public function setTrigger(int $trigger): void
{
$this->trigger = $trigger;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @inheritDoc
*/
public function setWebhooks(Collection $webhooks): void
{
$this->webhooks = $webhooks;
}
/**
* @param TransactionGroup $transactionGroup
*
* @return Collection
*/
private function getWebhooks(): Collection
private function collectAccounts(TransactionGroup $transactionGroup): Collection
{
return $this->user->webhooks()->where('active', true)->where('trigger', $this->trigger)->get(['webhooks.*']);
$accounts = new Collection();
/** @var TransactionJournal $journal */
foreach ($transactionGroup->transactionJournals as $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$accounts->push($transaction->account);
}
}
/**
*
*/
private function run(): void
{
Log::debug('Now in StandardMessageGenerator::run');
/** @var Webhook $webhook */
foreach ($this->webhooks as $webhook) {
$this->runWebhook($webhook);
}
Log::debug('Done with StandardMessageGenerator::run');
}
/**
* @param Webhook $webhook
* @throws FireflyException
* @throws JsonException
*/
private function runWebhook(Webhook $webhook): void
{
Log::debug(sprintf('Now in runWebhook(#%d)', $webhook->id));
/** @var Model $object */
foreach ($this->objects as $object) {
$this->generateMessage($webhook, $object);
}
return $accounts->unique();
}
/**
@ -188,30 +212,38 @@ class StandardMessageGenerator implements MessageGeneratorInterface
}
/**
* @inheritDoc
* @return Collection
*/
public function getVersion(): int
private function getWebhooks(): Collection
{
return $this->version;
return $this->user->webhooks()->where('active', true)->where('trigger', $this->trigger)->get(['webhooks.*']);
}
/**
* @param TransactionGroup $transactionGroup
*
* @return Collection
*/
private function collectAccounts(TransactionGroup $transactionGroup): Collection
private function run(): void
{
$accounts = new Collection();
/** @var TransactionJournal $journal */
foreach ($transactionGroup->transactionJournals as $journal) {
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
$accounts->push($transaction->account);
Log::debug('Now in StandardMessageGenerator::run');
/** @var Webhook $webhook */
foreach ($this->webhooks as $webhook) {
$this->runWebhook($webhook);
}
Log::debug('Done with StandardMessageGenerator::run');
}
return $accounts->unique();
/**
* @param Webhook $webhook
* @throws FireflyException
* @throws JsonException
*/
private function runWebhook(Webhook $webhook): void
{
Log::debug(sprintf('Now in runWebhook(#%d)', $webhook->id));
/** @var Model $object */
foreach ($this->objects as $object) {
$this->generateMessage($webhook, $object);
}
}
/**
@ -231,36 +263,4 @@ class StandardMessageGenerator implements MessageGeneratorInterface
$webhookMessage->save();
Log::debug(sprintf('Stored new webhook message #%d', $webhookMessage->id));
}
/**
* @param Collection $objects
*/
public function setObjects(Collection $objects): void
{
$this->objects = $objects;
}
/**
* @param int $trigger
*/
public function setTrigger(int $trigger): void
{
$this->trigger = $trigger;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* @inheritDoc
*/
public function setWebhooks(Collection $webhooks): void
{
$this->webhooks = $webhooks;
}
}

View File

@ -26,9 +26,9 @@ namespace FireflyIII\Handlers\Events;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Notifications\User\NewAccessToken;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Laravel\Passport\Events\AccessTokenCreated;
use Illuminate\Support\Facades\Log;
/**
* Class APIEventHandler

View File

@ -29,8 +29,8 @@ use FireflyIII\Models\TransactionGroup;
use FireflyIII\Notifications\User\TransactionCreation;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Transformers\TransactionGroupTransformer;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
/**
* Class AutomationHandler

View File

@ -52,16 +52,6 @@ class BudgetLimitHandler
$this->updateAvailableBudget($event->budgetLimit);
}
/**
* @param Updated $event
* @return void
*/
public function updated(Updated $event): void
{
Log::debug(sprintf('BudgetLimitHandler::updated(#%s)', $event->budgetLimit->id));
$this->updateAvailableBudget($event->budgetLimit);
}
/**
* @param Deleted $event
* @return void
@ -74,6 +64,16 @@ class BudgetLimitHandler
$this->updateAvailableBudget($event->budgetLimit);
}
/**
* @param Updated $event
* @return void
*/
public function updated(Updated $event): void
{
Log::debug(sprintf('BudgetLimitHandler::updated(#%s)', $event->budgetLimit->id));
$this->updateAvailableBudget($event->budgetLimit);
}
/**
* @param AvailableBudget $availableBudget
* @return void

View File

@ -47,8 +47,8 @@ use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Facades\FireflyConfig;
use FireflyIII\User;
use Illuminate\Auth\Events\Login;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Mail;
/**

View File

@ -32,9 +32,9 @@ use Illuminate\Contracts\Encryption\EncryptException;
use Illuminate\Contracts\Filesystem\Filesystem;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\MessageBag;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\File\UploadedFile;
/**
@ -211,6 +211,39 @@ class AttachmentHelper implements AttachmentHelperInterface
return true;
}
/**
* Check if a model already has this file attached.
*
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function hasFile(UploadedFile $file, Model $model): bool
{
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = 0;
// ignore lines about polymorphic calls.
if ($model instanceof PiggyBank) {
$count = $model->account->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
}
if ($model instanceof PiggyBank) {
$count = $model->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count(
); // @phpstan-ignore-line
}
$result = false;
if ($count > 0) {
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
$this->errors->add('attachments', $msg);
Log::error($msg);
$result = true;
}
return $result;
}
/**
* Process the upload of a file.
*
@ -268,39 +301,6 @@ class AttachmentHelper implements AttachmentHelperInterface
return $attachment;
}
/**
* Verify if the file was uploaded correctly.
*
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function validateUpload(UploadedFile $file, Model $model): bool
{
Log::debug('Now in validateUpload()');
$result = true;
if (!$this->validMime($file)) {
$result = false;
}
if (0 === $file->getSize()) {
Log::error('Cannot upload empty file.');
$result = false;
}
// can't seem to reach this point.
if (true === $result && !$this->validSize($file)) {
$result = false;
}
if (true === $result && $this->hasFile($file, $model)) {
$result = false;
}
return $result;
}
/**
* Verify if the mime of a file is valid.
*
@ -353,33 +353,33 @@ class AttachmentHelper implements AttachmentHelperInterface
}
/**
* Check if a model already has this file attached.
* Verify if the file was uploaded correctly.
*
* @param UploadedFile $file
* @param Model $model
*
* @return bool
*/
protected function hasFile(UploadedFile $file, Model $model): bool
protected function validateUpload(UploadedFile $file, Model $model): bool
{
$md5 = md5_file($file->getRealPath());
$name = $file->getClientOriginalName();
$class = get_class($model);
$count = 0;
// ignore lines about polymorphic calls.
if ($model instanceof PiggyBank) {
$count = $model->account->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count();
}
if ($model instanceof PiggyBank) {
$count = $model->user->attachments()->where('md5', $md5)->where('attachable_id', $model->id)->where('attachable_type', $class)->count(
); // @phpstan-ignore-line
}
$result = false;
if ($count > 0) {
$msg = (string)trans('validation.file_already_attached', ['name' => $name]);
$this->errors->add('attachments', $msg);
Log::error($msg);
Log::debug('Now in validateUpload()');
$result = true;
if (!$this->validMime($file)) {
$result = false;
}
if (0 === $file->getSize()) {
Log::error('Cannot upload empty file.');
$result = false;
}
// can't seem to reach this point.
if (true === $result && !$this->validSize($file)) {
$result = false;
}
if (true === $result && $this->hasFile($file, $model)) {
$result = false;
}
return $result;

View File

@ -53,25 +53,6 @@ trait MetaCollection
return $this;
}
/**
* Will include bill name + ID, if any.
*
* @return GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface
{
if (false === $this->hasBillInformation) {
// join bill table
$this->query->leftJoin('bills', 'bills.id', '=', 'transaction_journals.bill_id');
// add fields
$this->fields[] = 'bills.id as bill_id';
$this->fields[] = 'bills.name as bill_name';
$this->hasBillInformation = true;
}
return $this;
}
/**
* Exclude a specific budget.
*
@ -91,27 +72,6 @@ trait MetaCollection
return $this;
}
/**
* Will include budget ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface
{
if (false === $this->hasBudgetInformation) {
// join link table
$this->query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id');
// add fields
$this->fields[] = 'budgets.id as budget_id';
$this->fields[] = 'budgets.name as budget_name';
$this->hasBudgetInformation = true;
}
return $this;
}
/**
* @inheritDoc
*/
@ -144,27 +104,6 @@ trait MetaCollection
return $this;
}
/**
* Will include category ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface
{
if (false === $this->hasCatInformation) {
// join link table
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id');
// add fields
$this->fields[] = 'categories.id as category_id';
$this->fields[] = 'categories.name as category_name';
$this->hasCatInformation = true;
}
return $this;
}
/**
* Exclude a specific category.
*
@ -196,19 +135,6 @@ trait MetaCollection
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinMetaDataTables(): void
{
if (false === $this->hasJoinedMetaTables) {
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
$this->fields[] = 'journal_meta.name as meta_name';
$this->fields[] = 'journal_meta.data as meta_data';
}
}
/**
* @inheritDoc
*/
@ -425,37 +351,6 @@ trait MetaCollection
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface
{
$this->fields[] = 'tags.id as tag_id';
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinTagTables(): void
{
if (false === $this->hasJoinedTagTables) {
// join some extra tables:
$this->hasJoinedTagTables = true;
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
$this->query->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id');
}
}
/**
* @inheritDoc
*/
@ -541,29 +436,6 @@ trait MetaCollection
return $this;
}
/**
* @inheritDoc
*/
public function withNotes(): GroupCollectorInterface
{
if (false === $this->hasNotesInformation) {
// join bill table
$this->query->leftJoin(
'notes',
static function (JoinClause $join) {
$join->on('notes.noteable_id', '=', 'transaction_journals.id');
$join->where('notes.noteable_type', '=', 'FireflyIII\Models\TransactionJournal');
$join->whereNull('notes.deleted_at');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
return $this;
}
/**
* @param string $value
*
@ -906,6 +778,25 @@ trait MetaCollection
return $this;
}
/**
* Will include bill name + ID, if any.
*
* @return GroupCollectorInterface
*/
public function withBillInformation(): GroupCollectorInterface
{
if (false === $this->hasBillInformation) {
// join bill table
$this->query->leftJoin('bills', 'bills.id', '=', 'transaction_journals.bill_id');
// add fields
$this->fields[] = 'bills.id as bill_id';
$this->fields[] = 'bills.name as bill_name';
$this->hasBillInformation = true;
}
return $this;
}
/**
* Limit results to a transactions without a budget..
*
@ -919,6 +810,27 @@ trait MetaCollection
return $this;
}
/**
* Will include budget ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withBudgetInformation(): GroupCollectorInterface
{
if (false === $this->hasBudgetInformation) {
// join link table
$this->query->leftJoin('budget_transaction_journal', 'budget_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('budgets', 'budget_transaction_journal.budget_id', '=', 'budgets.id');
// add fields
$this->fields[] = 'budgets.id as budget_id';
$this->fields[] = 'budgets.name as budget_name';
$this->hasBudgetInformation = true;
}
return $this;
}
/**
* Limit results to a transactions without a category.
*
@ -932,6 +844,27 @@ trait MetaCollection
return $this;
}
/**
* Will include category ID + name, if any.
*
* @return GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface
{
if (false === $this->hasCatInformation) {
// join link table
$this->query->leftJoin('category_transaction_journal', 'category_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
// join cat table
$this->query->leftJoin('categories', 'category_transaction_journal.category_id', '=', 'categories.id');
// add fields
$this->fields[] = 'categories.id as category_id';
$this->fields[] = 'categories.name as category_name';
$this->hasCatInformation = true;
}
return $this;
}
/**
* @inheritDoc
*/
@ -956,6 +889,47 @@ trait MetaCollection
return $this;
}
/**
* @inheritDoc
*/
public function withNotes(): GroupCollectorInterface
{
if (false === $this->hasNotesInformation) {
// join bill table
$this->query->leftJoin(
'notes',
static function (JoinClause $join) {
$join->on('notes.noteable_id', '=', 'transaction_journals.id');
$join->where('notes.noteable_type', '=', 'FireflyIII\Models\TransactionJournal');
$join->whereNull('notes.deleted_at');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
return $this;
}
/**
* @return GroupCollectorInterface
*/
public function withTagInformation(): GroupCollectorInterface
{
$this->fields[] = 'tags.id as tag_id';
$this->fields[] = 'tags.tag as tag_name';
$this->fields[] = 'tags.date as tag_date';
$this->fields[] = 'tags.description as tag_description';
$this->fields[] = 'tags.latitude as tag_latitude';
$this->fields[] = 'tags.longitude as tag_longitude';
$this->fields[] = 'tags.zoomLevel as tag_zoom_level';
$this->joinTagTables();
return $this;
}
/**
* Limit results to a transactions without a bill.
*
@ -1062,4 +1036,30 @@ trait MetaCollection
return $this;
}
/**
* Join table to get tag information.
*/
protected function joinMetaDataTables(): void
{
if (false === $this->hasJoinedMetaTables) {
$this->hasJoinedMetaTables = true;
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
$this->fields[] = 'journal_meta.name as meta_name';
$this->fields[] = 'journal_meta.data as meta_data';
}
}
/**
* Join table to get tag information.
*/
protected function joinTagTables(): void
{
if (false === $this->hasJoinedTagTables) {
// join some extra tables:
$this->hasJoinedTagTables = true;
$this->query->leftJoin('tag_transaction_journal', 'tag_transaction_journal.transaction_journal_id', '=', 'transaction_journals.id');
$this->query->leftJoin('tags', 'tag_transaction_journal.tag_id', '=', 'tags.id');
}
}
}

View File

@ -102,18 +102,6 @@ trait TimeCollection
return $this;
}
/**
* @inheritDoc
*/
public function withMetaDate(string $field): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', $field);
$this->query->whereNotNull('journal_meta.data');
return $this;
}
/**
* @param Carbon $start
* @param Carbon $end
@ -798,6 +786,18 @@ trait TimeCollection
return $this;
}
/**
* @inheritDoc
*/
public function withMetaDate(string $field): GroupCollectorInterface
{
$this->joinMetaDataTables();
$this->query->where('journal_meta.name', '=', $field);
$this->query->whereNotNull('journal_meta.data');
return $this;
}
/**
* @param string $year
* @return GroupCollectorInterface

View File

@ -504,6 +504,312 @@ class GroupCollector implements GroupCollectorInterface
return $collection;
}
/**
* Same as getGroups but everything is in a paginator.
*
* @return LengthAwarePaginator
*/
public function getPaginatedGroups(): LengthAwarePaginator
{
$set = $this->getGroups();
if (0 === $this->limit) {
$this->setLimit(50);
}
return new LengthAwarePaginator($set, $this->total, $this->limit, $this->page);
}
/**
* @inheritDoc
*/
public function isNotReconciled(): GroupCollectorInterface
{
$this->query->where('source.reconciled', 0)->where('destination.reconciled', 0);
return $this;
}
/**
* @inheritDoc
*/
public function isReconciled(): GroupCollectorInterface
{
$this->query->where('source.reconciled', 1)->where('destination.reconciled', 1);
return $this;
}
/**
* Limit results to a specific currency, either foreign or normal one.
*
* @param TransactionCurrency $currency
*
* @return GroupCollectorInterface
*/
public function setCurrency(TransactionCurrency $currency): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($currency) {
$q->where('source.transaction_currency_id', $currency->id);
$q->orWhere('source.foreign_currency_id', $currency->id);
}
);
return $this;
}
/**
* @inheritDoc
*/
public function setForeignCurrency(TransactionCurrency $currency): GroupCollectorInterface
{
$this->query->where('source.foreign_currency_id', $currency->id);
return $this;
}
/**
* Limit the result to a set of specific transaction groups.
*
* @param array $groupIds
*
* @return GroupCollectorInterface
*/
public function setIds(array $groupIds): GroupCollectorInterface
{
$this->query->whereIn('transaction_groups.id', $groupIds);
return $this;
}
/**
* Limit the result to a set of specific journals.
*
* @param array $journalIds
*
* @return GroupCollectorInterface
*/
public function setJournalIds(array $journalIds): GroupCollectorInterface
{
if (0 !== count($journalIds)) {
// make all integers.
$integerIDs = array_map('intval', $journalIds);
$this->query->whereIn('transaction_journals.id', $integerIDs);
}
return $this;
}
/**
* Limit the number of returned entries.
*
* @param int $limit
*
* @return GroupCollectorInterface
*/
public function setLimit(int $limit): GroupCollectorInterface
{
$this->limit = $limit;
app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
return $this;
}
/**
* Set the page to get.
*
* @param int $page
*
* @return GroupCollectorInterface
*/
public function setPage(int $page): GroupCollectorInterface
{
$page = 0 === $page ? 1 : $page;
$this->page = $page;
app('log')->debug(sprintf('GroupCollector: page is now %d', $page));
return $this;
}
/**
* Search for words in descriptions.
*
* @param array $array
*
* @return GroupCollectorInterface
*/
public function setSearchWords(array $array): GroupCollectorInterface
{
if (0 === count($array)) {
return $this;
}
$this->query->where(
static function (EloquentBuilder $q) use ($array) {
$q->where(
static function (EloquentBuilder $q1) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word);
$q1->where('transaction_journals.description', 'LIKE', $keyword);
}
}
);
$q->orWhere(
static function (EloquentBuilder $q2) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word);
$q2->where('transaction_groups.title', 'LIKE', $keyword);
}
}
);
}
);
return $this;
}
/**
* Limit the search to one specific transaction group.
*
* @param TransactionGroup $transactionGroup
*
* @return GroupCollectorInterface
*/
public function setTransactionGroup(TransactionGroup $transactionGroup): GroupCollectorInterface
{
$this->query->where('transaction_groups.id', $transactionGroup->id);
return $this;
}
/**
* Limit the included transaction types.
*
* @param array $types
*
* @return GroupCollectorInterface
*/
public function setTypes(array $types): GroupCollectorInterface
{
$this->query->whereIn('transaction_types.type', $types);
return $this;
}
/**
* Set the user object and start the query.
*
* @param User $user
*
* @return GroupCollectorInterface
*/
public function setUser(User $user): GroupCollectorInterface
{
if (null === $this->user) {
$this->user = $user;
$this->startQuery();
}
return $this;
}
/**
* Automatically include all stuff required to make API calls work.
*
* @return GroupCollectorInterface
*/
public function withAPIInformation(): GroupCollectorInterface
{
// include source + destination account name and type.
$this->withAccountInformation()
// include category ID + name (if any)
->withCategoryInformation()
// include budget ID + name (if any)
->withBudgetInformation()
// include bill ID + name (if any)
->withBillInformation();
return $this;
}
/**
* Convert a selected set of fields to arrays.
*
* @param array $array
*
* @return array
*/
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
}
return $array;
}
/**
* @param array $array
* @return array
*/
private function convertToStrings(array $array): array
{
foreach ($this->stringFields as $field) {
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string)$array[$field] : null;
}
return $array;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeAttachments(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int)$newJournal['attachment_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
];
}
return $existingJournal;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeTags(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int)$newJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($newArray['tag_date']);
} catch (InvalidFormatException $e) {
Log::debug(sprintf('Could not parse date: %s', $e->getMessage()));
}
$existingJournal['tags'][$tagId] = [
'id' => (int)$newArray['tag_id'],
'name' => $newArray['tag_name'],
'date' => $tagDate,
'description' => $newArray['tag_description'],
];
}
return $existingJournal;
}
/**
* @param Collection $collection
*
@ -645,85 +951,6 @@ class GroupCollector implements GroupCollectorInterface
return $result;
}
/**
* Convert a selected set of fields to arrays.
*
* @param array $array
*
* @return array
*/
private function convertToInteger(array $array): array
{
foreach ($this->integerFields as $field) {
$array[$field] = array_key_exists($field, $array) ? (int)$array[$field] : null;
}
return $array;
}
/**
* @param array $array
* @return array
*/
private function convertToStrings(array $array): array
{
foreach ($this->stringFields as $field) {
$array[$field] = array_key_exists($field, $array) && null !== $array[$field] ? (string)$array[$field] : null;
}
return $array;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeTags(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('tag_id', $newArray)) { // assume the other fields are present as well.
$tagId = (int)$newJournal['tag_id'];
$tagDate = null;
try {
$tagDate = Carbon::parse($newArray['tag_date']);
} catch (InvalidFormatException $e) {
Log::debug(sprintf('Could not parse date: %s', $e->getMessage()));
}
$existingJournal['tags'][$tagId] = [
'id' => (int)$newArray['tag_id'],
'name' => $newArray['tag_name'],
'date' => $tagDate,
'description' => $newArray['tag_description'],
];
}
return $existingJournal;
}
/**
* @param array $existingJournal
* @param TransactionJournal $newJournal
*
* @return array
*/
private function mergeAttachments(array $existingJournal, TransactionJournal $newJournal): array
{
$newArray = $newJournal->toArray();
if (array_key_exists('attachment_id', $newArray)) {
$attachmentId = (int)$newJournal['attachment_id'];
$existingJournal['attachments'][$attachmentId] = [
'id' => $attachmentId,
];
}
return $existingJournal;
}
/**
* @param array $groups
*
@ -801,214 +1028,6 @@ class GroupCollector implements GroupCollectorInterface
return $currentCollection;
}
/**
* Same as getGroups but everything is in a paginator.
*
* @return LengthAwarePaginator
*/
public function getPaginatedGroups(): LengthAwarePaginator
{
$set = $this->getGroups();
if (0 === $this->limit) {
$this->setLimit(50);
}
return new LengthAwarePaginator($set, $this->total, $this->limit, $this->page);
}
/**
* Limit the number of returned entries.
*
* @param int $limit
*
* @return GroupCollectorInterface
*/
public function setLimit(int $limit): GroupCollectorInterface
{
$this->limit = $limit;
app('log')->debug(sprintf('GroupCollector: The limit is now %d', $limit));
return $this;
}
/**
* @inheritDoc
*/
public function isNotReconciled(): GroupCollectorInterface
{
$this->query->where('source.reconciled', 0)->where('destination.reconciled', 0);
return $this;
}
/**
* @inheritDoc
*/
public function isReconciled(): GroupCollectorInterface
{
$this->query->where('source.reconciled', 1)->where('destination.reconciled', 1);
return $this;
}
/**
* Limit results to a specific currency, either foreign or normal one.
*
* @param TransactionCurrency $currency
*
* @return GroupCollectorInterface
*/
public function setCurrency(TransactionCurrency $currency): GroupCollectorInterface
{
$this->query->where(
static function (EloquentBuilder $q) use ($currency) {
$q->where('source.transaction_currency_id', $currency->id);
$q->orWhere('source.foreign_currency_id', $currency->id);
}
);
return $this;
}
/**
* @inheritDoc
*/
public function setForeignCurrency(TransactionCurrency $currency): GroupCollectorInterface
{
$this->query->where('source.foreign_currency_id', $currency->id);
return $this;
}
/**
* Limit the result to a set of specific transaction groups.
*
* @param array $groupIds
*
* @return GroupCollectorInterface
*/
public function setIds(array $groupIds): GroupCollectorInterface
{
$this->query->whereIn('transaction_groups.id', $groupIds);
return $this;
}
/**
* Limit the result to a set of specific journals.
*
* @param array $journalIds
*
* @return GroupCollectorInterface
*/
public function setJournalIds(array $journalIds): GroupCollectorInterface
{
if (0 !== count($journalIds)) {
// make all integers.
$integerIDs = array_map('intval', $journalIds);
$this->query->whereIn('transaction_journals.id', $integerIDs);
}
return $this;
}
/**
* Set the page to get.
*
* @param int $page
*
* @return GroupCollectorInterface
*/
public function setPage(int $page): GroupCollectorInterface
{
$page = 0 === $page ? 1 : $page;
$this->page = $page;
app('log')->debug(sprintf('GroupCollector: page is now %d', $page));
return $this;
}
/**
* Search for words in descriptions.
*
* @param array $array
*
* @return GroupCollectorInterface
*/
public function setSearchWords(array $array): GroupCollectorInterface
{
if (0 === count($array)) {
return $this;
}
$this->query->where(
static function (EloquentBuilder $q) use ($array) {
$q->where(
static function (EloquentBuilder $q1) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word);
$q1->where('transaction_journals.description', 'LIKE', $keyword);
}
}
);
$q->orWhere(
static function (EloquentBuilder $q2) use ($array) {
foreach ($array as $word) {
$keyword = sprintf('%%%s%%', $word);
$q2->where('transaction_groups.title', 'LIKE', $keyword);
}
}
);
}
);
return $this;
}
/**
* Limit the search to one specific transaction group.
*
* @param TransactionGroup $transactionGroup
*
* @return GroupCollectorInterface
*/
public function setTransactionGroup(TransactionGroup $transactionGroup): GroupCollectorInterface
{
$this->query->where('transaction_groups.id', $transactionGroup->id);
return $this;
}
/**
* Limit the included transaction types.
*
* @param array $types
*
* @return GroupCollectorInterface
*/
public function setTypes(array $types): GroupCollectorInterface
{
$this->query->whereIn('transaction_types.type', $types);
return $this;
}
/**
* Set the user object and start the query.
*
* @param User $user
*
* @return GroupCollectorInterface
*/
public function setUser(User $user): GroupCollectorInterface
{
if (null === $this->user) {
$this->user = $user;
$this->startQuery();
}
return $this;
}
/**
* Build the query.
*/
@ -1051,23 +1070,4 @@ class GroupCollector implements GroupCollectorInterface
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
}
/**
* Automatically include all stuff required to make API calls work.
*
* @return GroupCollectorInterface
*/
public function withAPIInformation(): GroupCollectorInterface
{
// include source + destination account name and type.
$this->withAccountInformation()
// include category ID + name (if any)
->withCategoryInformation()
// include budget ID + name (if any)
->withBudgetInformation()
// include bill ID + name (if any)
->withBillInformation();
return $this;
}
}

View File

@ -25,7 +25,6 @@ namespace FireflyIII\Helpers\Fiscal;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -23,7 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Update;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Services\FireflyIIIOrg\Update\UpdateRequestInterface;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;

View File

@ -25,8 +25,8 @@ namespace FireflyIII\Helpers\Webhook;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\WebhookMessage;
use JsonException;
use Illuminate\Support\Facades\Log;
use JsonException;
/**
* Class Sha3SignatureGenerator

View File

@ -34,8 +34,8 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -32,9 +32,9 @@ use FireflyIII\Support\Http\Controllers\BasicDataSupport;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use JsonException;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -38,9 +38,9 @@ use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use JsonException;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -29,8 +29,8 @@ use FireflyIII\Http\Middleware\IsDemoUser;
use FireflyIII\Http\Requests\ConfigurationRequest;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -33,8 +33,8 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -32,8 +32,8 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
* Class LinkController.

View File

@ -36,8 +36,8 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -31,8 +31,8 @@ use Illuminate\Contracts\View\Factory;
use Illuminate\Foundation\Auth\SendsPasswordResetEmails;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;

View File

@ -38,8 +38,8 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Redirector;
use Illuminate\Validation\ValidationException;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@ -128,37 +128,6 @@ class LoginController extends Controller
$this->sendFailedLoginResponse($request);
}
/**
* Get the login username to be used by the controller.
*
* @return string
*/
public function username()
{
return $this->username;
}
/**
* Get the failed login response instance.
*
* @param Request $request
*
* @return void
*
* @throws ValidationException
*/
protected function sendFailedLoginResponse(Request $request)
{
$exception = ValidationException::withMessages(
[
$this->username() => [trans('auth.failed')],
]
);
$exception->redirectTo = route('login');
throw $exception;
}
/**
* Log the user out of the application.
*
@ -244,4 +213,35 @@ class LoginController extends Controller
return view('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'title', 'usernameField'));
}
/**
* Get the login username to be used by the controller.
*
* @return string
*/
public function username()
{
return $this->username;
}
/**
* Get the failed login response instance.
*
* @param Request $request
*
* @return void
*
* @throws ValidationException
*/
protected function sendFailedLoginResponse(Request $request)
{
$exception = ValidationException::withMessages(
[
$this->username() => [trans('auth.failed')],
]
);
$exception->redirectTo = route('login');
throw $exception;
}
}

View File

@ -35,9 +35,9 @@ use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
@ -117,30 +117,6 @@ class RegisterController extends Controller
return redirect($this->redirectPath());
}
/**
* @return bool
* @throws FireflyException
*/
protected function allowedToRegister(): bool
{
// is allowed to register?
$allowRegistration = true;
try {
$singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
} catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
$singleUserMode = true;
}
$userCount = User::count();
$guard = config('auth.defaults.guard');
if (true === $singleUserMode && $userCount > 0 && 'web' === $guard) {
$allowRegistration = false;
}
if ('web' !== $guard) {
$allowRegistration = false;
}
return $allowRegistration;
}
/**
* Show the application registration form if the invitation code is valid.
*
@ -201,4 +177,28 @@ class RegisterController extends Controller
return view('auth.register', compact('isDemoSite', 'email', 'pageTitle'));
}
/**
* @return bool
* @throws FireflyException
*/
protected function allowedToRegister(): bool
{
// is allowed to register?
$allowRegistration = true;
try {
$singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
} catch (ContainerExceptionInterface|NotFoundExceptionInterface $e) {
$singleUserMode = true;
}
$userCount = User::count();
$guard = config('auth.defaults.guard');
if (true === $singleUserMode && $userCount > 0 && 'web' === $guard) {
$allowRegistration = false;
}
if ('web' !== $guard) {
$allowRegistration = false;
}
return $allowRegistration;
}
}

View File

@ -99,26 +99,20 @@ class TwoFactorController extends Controller
}
/**
* Each MFA history has a timestamp and a code, saving the MFA entries for 5 minutes. So if the
* submitted MFA code has been submitted in the last 5 minutes, it won't work despite being valid.
*
* @param string $mfaCode
* @param array $mfaHistory
*
* @return bool
*/
private function inMFAHistory(string $mfaCode, array $mfaHistory): bool
private function addToMFAHistory(string $mfaCode): void
{
$now = time();
foreach ($mfaHistory as $entry) {
$time = $entry['time'];
$code = $entry['code'];
if ($code === $mfaCode && $now - $time <= 300) {
return true;
}
}
/** @var array $mfaHistory */
$mfaHistory = Preferences::get('mfa_history', [])->data;
$entry = [
'time' => time(),
'code' => $mfaCode,
];
$mfaHistory[] = $entry;
return false;
Preferences::set('mfa_history', $mfaHistory);
$this->filterMFAHistory();
}
/**
@ -144,20 +138,26 @@ class TwoFactorController extends Controller
}
/**
* Each MFA history has a timestamp and a code, saving the MFA entries for 5 minutes. So if the
* submitted MFA code has been submitted in the last 5 minutes, it won't work despite being valid.
*
* @param string $mfaCode
* @param array $mfaHistory
*
* @return bool
*/
private function addToMFAHistory(string $mfaCode): void
private function inMFAHistory(string $mfaCode, array $mfaHistory): bool
{
/** @var array $mfaHistory */
$mfaHistory = Preferences::get('mfa_history', [])->data;
$entry = [
'time' => time(),
'code' => $mfaCode,
];
$mfaHistory[] = $entry;
$now = time();
foreach ($mfaHistory as $entry) {
$time = $entry['time'];
$code = $entry['code'];
if ($code === $mfaCode && $now - $time <= 300) {
return true;
}
}
Preferences::set('mfa_history', $mfaHistory);
$this->filterMFAHistory();
return false;
}
/**

View File

@ -135,49 +135,26 @@ class IndexController extends Controller
}
/**
* @param array $bills
* Set the order of a bill.
*
* @return array
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @param Request $request
* @param Bill $bill
*
* @return JsonResponse
*/
private function getSums(array $bills): array
public function setOrder(Request $request, Bill $bill): JsonResponse
{
$sums = [];
$range = app('navigation')->getViewRange(false);
/** @var array $group */
foreach ($bills as $groupOrder => $group) {
/** @var array $bill */
foreach ($group['bills'] as $bill) {
if (false === $bill['active']) {
continue;
$objectGroupTitle = (string)$request->get('objectGroupTitle');
$newOrder = (int)$request->get('order');
$this->repository->setOrder($bill, $newOrder);
if ('' !== $objectGroupTitle) {
$this->repository->setObjectGroup($bill, $objectGroupTitle);
}
if ('' === $objectGroupTitle) {
$this->repository->removeObjectGroup($bill);
}
$currencyId = $bill['currency_id'];
$sums[$groupOrder][$currencyId] = $sums[$groupOrder][$currencyId] ?? [
'currency_id' => $currencyId,
'currency_code' => $bill['currency_code'],
'currency_name' => $bill['currency_name'],
'currency_symbol' => $bill['currency_symbol'],
'currency_decimal_places' => $bill['currency_decimal_places'],
'avg' => '0',
'period' => $range,
'per_period' => '0',
];
// only fill in avg when bill is active.
if (count($bill['pay_dates']) > 0) {
$avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2');
$avg = bcmul($avg, (string)count($bill['pay_dates']));
$sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg);
}
// fill in per period regardless:
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
}
}
return $sums;
return response()->json(['data' => 'OK']);
}
/**
@ -227,6 +204,52 @@ class IndexController extends Controller
return $perPeriod;
}
/**
* @param array $bills
*
* @return array
* @throws FireflyException
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
private function getSums(array $bills): array
{
$sums = [];
$range = app('navigation')->getViewRange(false);
/** @var array $group */
foreach ($bills as $groupOrder => $group) {
/** @var array $bill */
foreach ($group['bills'] as $bill) {
if (false === $bill['active']) {
continue;
}
$currencyId = $bill['currency_id'];
$sums[$groupOrder][$currencyId] = $sums[$groupOrder][$currencyId] ?? [
'currency_id' => $currencyId,
'currency_code' => $bill['currency_code'],
'currency_name' => $bill['currency_name'],
'currency_symbol' => $bill['currency_symbol'],
'currency_decimal_places' => $bill['currency_decimal_places'],
'avg' => '0',
'period' => $range,
'per_period' => '0',
];
// only fill in avg when bill is active.
if (count($bill['pay_dates']) > 0) {
$avg = bcdiv(bcadd((string)$bill['amount_min'], (string)$bill['amount_max']), '2');
$avg = bcmul($avg, (string)count($bill['pay_dates']));
$sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg);
}
// fill in per period regardless:
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
}
}
return $sums;
}
/**
* @param array $sums
*
@ -264,27 +287,4 @@ class IndexController extends Controller
return $totals;
}
/**
* Set the order of a bill.
*
* @param Request $request
* @param Bill $bill
*
* @return JsonResponse
*/
public function setOrder(Request $request, Bill $bill): JsonResponse
{
$objectGroupTitle = (string)$request->get('objectGroupTitle');
$newOrder = (int)$request->get('order');
$this->repository->setOrder($bill, $newOrder);
if ('' !== $objectGroupTitle) {
$this->repository->setObjectGroup($bill, $objectGroupTitle);
}
if ('' === $objectGroupTitle) {
$this->repository->removeObjectGroup($bill);
}
return response()->json(['data' => 'OK']);
}
}

View File

@ -26,7 +26,6 @@ namespace FireflyIII\Http\Controllers\Budget;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\AvailableBudget;
use FireflyIII\Models\Budget;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Models\TransactionCurrency;
@ -41,8 +40,8 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;
/**
*

View File

@ -173,6 +173,29 @@ class IndexController extends Controller
);
}
/**
* @param Request $request
* @param BudgetRepositoryInterface $repository
*
* @return JsonResponse
*/
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
{
$budgetIds = $request->get('budgetIds');
foreach ($budgetIds as $index => $budgetId) {
$budgetId = (int)$budgetId;
$budget = $repository->find($budgetId);
if (null !== $budget) {
Log::debug(sprintf('Set budget #%d ("%s") to position %d', $budget->id, $budget->name, $index + 1));
$repository->setBudgetOrder($budget, $index + 1);
}
}
app('preferences')->mark();
return response()->json(['OK']);
}
/**
* @param Carbon $start
* @param Carbon $end
@ -328,27 +351,4 @@ class IndexController extends Controller
return $sums;
}
/**
* @param Request $request
* @param BudgetRepositoryInterface $repository
*
* @return JsonResponse
*/
public function reorder(Request $request, BudgetRepositoryInterface $repository): JsonResponse
{
$budgetIds = $request->get('budgetIds');
foreach ($budgetIds as $index => $budgetId) {
$budgetId = (int)$budgetId;
$budget = $repository->find($budgetId);
if (null !== $budget) {
Log::debug(sprintf('Set budget #%d ("%s") to position %d', $budget->id, $budget->name, $index + 1));
$repository->setBudgetOrder($budget, $index + 1);
}
}
app('preferences')->mark();
return response()->json(['OK']);
}
}

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