Merge branch 'release/5.3.0-alpha.1'

This commit is contained in:
James Cole 2020-06-22 18:17:59 +02:00
commit 2c69a2eda2
684 changed files with 66996 additions and 30586 deletions

View File

@ -57,10 +57,10 @@ APP_LOG_LEVEL=notice
# Database credentials. Make sure the database exists. I recommend a dedicated user for Firefly III
# For other database types, please see the FAQ: https://docs.firefly-iii.org/support/faq
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
# Use "mysql" for MySQL and MariaDB. Use "sqlite" for SQLite.
DB_CONNECTION=pgsql
# Use "pgsql" for PostgreSQL and MariaDB. Use "sqlite" for SQLite.
DB_CONNECTION=mysql
DB_HOST=fireflyiiidb
DB_PORT=5432
DB_PORT=3306
DB_DATABASE=firefly
DB_USERNAME=firefly
DB_PASSWORD=secret_firefly_password
@ -167,6 +167,23 @@ FIXER_API_KEY=
# If you use Docker or similar, you can set this variable from a file by appending it with _FILE
LOGIN_PROVIDER=eloquent
#
# It's also possible to change the way users are authenticated. You could use Authelia for example.
# Authentication via the REMOTE_USER header is supported. Change the value below to "remote_user_guard".
#
# If you do this please read the documentation for instructions and warnings:
# https://docs.firefly-iii.org/advanced-installation/authentication
#
# This function is available in Firefly III v5.3.0 and higher.
AUTHENTICATION_GUARD=web
#
# Likewise, it's impossible to log out users who's authentication is handled by an external system.
# Enter a custom URL here that will force a logout (your authentication provider can tell you).
# Setting this variable only works when AUTHENTICATION_GUARD != web
#
CUSTOM_LOGOUT_URI=
# LDAP connection configuration
# OpenLDAP, FreeIPA or ActiveDirectory
# # If you use Docker or similar, you can set this variable from a file by appending it with _FILE
@ -289,7 +306,7 @@ DEMO_PASSWORD=
USE_ENCRYPTION=false
IS_SANDSTORM=false
IS_HEROKU=false
BUNQ_USE_SANDBOX=false
FIREFLY_III_LAYOUT=v1
#
# If you have trouble configuring your Firefly III installation, DON'T BOTHER setting this variable.

1
.gitignore vendored
View File

@ -1,5 +1,6 @@
/node_modules
/frontend/node_modules
/frontend/fonts
/public/hot
/public/storage
/storage/*.key

View File

@ -1,181 +0,0 @@
<?php
/**
* ImportController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Http\Api\TransactionFilter;
use FireflyIII\Transformers\ImportJobTransformer;
use FireflyIII\Transformers\TransactionGroupTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
/**
* Class ImportController
*
* @deprecated
* @codeCoverageIgnore
*/
class ImportController extends Controller
{
use TransactionFilter;
/** @var ImportJobRepositoryInterface Import job repository. */
private $repository;
/**
* ImportController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* @return JsonResponse
* @codeCoverageIgnore
*/
public function listAll(): JsonResponse
{
// create some objects:
$manager = $this->getManager();
$pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$importJobs = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($importJobs, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.import.list') . $this->buildParams());
/** @var ImportJobTransformer $transformer */
$transformer = app(ImportJobTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($importJobs, $transformer, 'import_jobs');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* @param ImportJob $importJob
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function show(ImportJob $importJob): JsonResponse
{
$manager = $this->getManager();
/** @var ImportJobTransformer $transformer */
$transformer = app(ImportJobTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($importJob, $transformer, 'import_jobs');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show all transactions
*
* @param Request $request
* @param ImportJob $importJob
*
* @return JsonResponse
* @codeCoverageIgnore
*/
public function transactions(Request $request, ImportJob $importJob): JsonResponse
{
$pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
$type = $request->get('type') ?? 'default';
$this->parameters->set('type', $type);
$types = $this->mapTransactionTypes($this->parameters->get('type'));
$manager = $this->getManager();
$tag = $importJob->tag;
$transactions = new Collection();
$paginator = new LengthAwarePaginator($transactions, 0, $pageSize);
$paginator->setPath(route('api.v1.import.transactions', [$importJob->key]) . $this->buildParams());
if (null !== $tag) {
/** @var User $admin */
$admin = auth()->user();
// use new group collector:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector
->setUser($admin)
// filter on tag.
->setTag($tag)
// all info needed for the API:
->withAPIInformation()
// set page size:
->setLimit($pageSize)
// set page to retrieve
->setPage($this->parameters->get('page'))
// set types of transactions to return.
->setTypes($types);
if (null !== $this->parameters->get('start') && null !== $this->parameters->get('end')) {
$collector->setRange($this->parameters->get('start'), $this->parameters->get('end'));
}
$paginator = $collector->getPaginatedGroups();
$paginator->setPath(route('api.v1.transactions.index') . $this->buildParams());
$transactions = $paginator->getCollection();
}
/** @var TransactionGroupTransformer $transformer */
$transformer = app(TransactionGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($transactions, $transformer, 'transactions');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -0,0 +1,196 @@
<?php
/**
* GroupController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\ObjectGroupUpdateRequest;
use FireflyIII\Models\Account;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
use FireflyIII\Transformers\ObjectGroupTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
use League\Fractal\Resource\Collection as FractalCollection;
use League\Fractal\Resource\Item;
/**
* Class GroupController.
*
*/
class ObjectGroupController extends Controller
{
private ObjectGroupRepositoryInterface $repository;
/**
* ObjectGroupController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
/** @var User $user */
$user = auth()->user();
$this->repository = app(ObjectGroupRepositoryInterface::class);
$this->repository->setUser($user);
return $next($request);
}
);
}
/**
* Remove the specified resource from storage.
*
* @param ObjectGroup $objectGroup
*
* @codeCoverageIgnore
* @return JsonResponse
*/
public function delete(ObjectGroup $objectGroup): JsonResponse
{
$this->repository->destroy($objectGroup);
return response()->json([], 204);
}
/**
* Display a listing of the resource.
*
* @param Request $request
*
* @codeCoverageIgnore
* @return JsonResponse
*/
public function index(Request $request): JsonResponse
{
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of accounts. Count it and split it.
$collection = $this->repository->get();
$count = $collection->count();
$objectGroups = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($objectGroups, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.object-groups.index') . $this->buildParams());
/** @var ObjectGroupTransformer $transformer */
$transformer = app(ObjectGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($objectGroups, $transformer, 'object_groups');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* List all piggies under the object group.
*
* @param ObjectGroup $objectGroup
*
* @return JsonResponse
* @codeCoverageIgnore
*
*/
public function piggyBanks(ObjectGroup $objectGroup): JsonResponse
{
// create some objects:
$manager = $this->getManager();
// types to get, page size:
$pageSize = (int) app('preferences')->getForUser(auth()->user(), 'listPageSize', 50)->data;
// get list of piggy banks. Count it and split it.
$collection = $this->repository->getPiggyBanks($objectGroup);
$count = $collection->count();
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
// make paginator:
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
$paginator->setPath(route('api.v1.object-groups.piggy_banks', [$objectGroup->id]) . $this->buildParams());
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new FractalCollection($piggyBanks, $transformer, 'piggy_banks');
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Show single instance.
*
* @param ObjectGroup $objectGroup
*
* @return JsonResponse
*/
public function show(ObjectGroup $objectGroup): JsonResponse
{
$manager = $this->getManager();
/** @var ObjectGroupTransformer $transformer */
$transformer = app(ObjectGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($objectGroup, $transformer, 'object_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
/**
* Update object.
*
* @param ObjectGroupUpdateRequest $request
* @param Account $account
*
* @return JsonResponse
*/
public function update(ObjectGroupUpdateRequest $request, ObjectGroup $objectGroup): JsonResponse
{
$data = $request->getUpdateData();
$this->repository->update($objectGroup, $data);
$this->repository->sort();
$manager = $this->getManager();
/** @var ObjectGroupTransformer $transformer */
$transformer = app(ObjectGroupTransformer::class);
$transformer->setParameters($this->parameters);
$resource = new Item($objectGroup, $transformer, 'object_groups');
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
}
}

View File

@ -24,6 +24,7 @@ declare(strict_types=1);
namespace FireflyIII\Api\V1\Controllers;
use FireflyIII\Api\V1\Requests\PiggyBankRequest;
use FireflyIII\Api\V1\Requests\PiggyBankStoreRequest;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
@ -204,12 +205,12 @@ class PiggyBankController extends Controller
/**
* Store new object.
*
* @param PiggyBankRequest $request
* @param PiggyBankStoreRequest $request
*
* @throws FireflyException
* @return JsonResponse
*/
public function store(PiggyBankRequest $request): JsonResponse
public function store(PiggyBankStoreRequest $request): JsonResponse
{
$piggyBank = $this->repository->store($request->getAll());
$manager = $this->getManager();

View File

@ -1,6 +1,7 @@
<?php
/**
* RabobankDescription.php
* ObjectGroupUpdateRequest.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
@ -18,52 +19,53 @@
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
namespace FireflyIII\Api\V1\Requests;
/**
* Class RabobankDescription.
* Class AccountObjectGroupUpdateRequestUpdateRequest
*
* @codeCoverageIgnore
* @deprecated
*/
class RabobankDescription implements SpecificInterface
class ObjectGroupUpdateRequest extends Request
{
/**
* Description of this specific.
* Authorize logged in users.
*
* @return string
* @codeCoverageIgnore
* @return bool
*/
public static function getDescription(): string
public function authorize(): bool
{
return 'import.specific_rabo_descr';
// Only allow authenticated users
return auth()->check();
}
/**
* Name of this specific.
*
* @return string
* @codeCoverageIgnore
* @return array
*/
public static function getName(): string
public function getUpdateData(): array
{
return 'import.specific_rabo_name';
return [
'title' => $this->string('title'),
'order' => $this->integer('order'),
];
}
/**
* Run the specific.
*
* @param array $row
* The rules that the incoming request must be matched against.
*
* @return array
*
*/
public function run(array $row): array
public function rules(): array
{
$row = array_values($row);
$objectGroup = $this->route()->parameter('objectGroup');
return $row;
return [
'title' => sprintf('min:1|uniqueObjectGroup:%d', $objectGroup->id),
'order' => 'numeric',
];
}
}

View File

@ -0,0 +1,86 @@
<?php
/**
* PiggyBankStoreRequest.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
use FireflyIII\Rules\ZeroOrMore;
/**
*
* Class PiggyBankStoreRequest
*
* @codeCoverageIgnore
*/
class PiggyBankStoreRequest extends Request
{
/**
* Authorize logged in users.
*
* @return bool
*/
public function authorize(): bool
{
// Only allow authenticated users
return auth()->check();
}
/**
* Get all data from the request.
*
* @return array
*/
public function getAll(): array
{
return [
'name' => $this->string('name'),
'account_id' => $this->integer('account_id'),
'targetamount' => $this->string('target_amount'),
'current_amount' => $this->string('current_amount'),
'startdate' => $this->date('start_date'),
'targetdate' => $this->date('target_date'),
'notes' => $this->nlString('notes'),
'object_group_id' => $this->integer('object_group_id'),
'object_group' => $this->string('object_group_name'),
];
}
/**
* The rules that the incoming request must be matched against.
*
* @return array
*/
public function rules(): array
{
return [
'name' => 'required|between:1,255|uniquePiggyBankForUser',
'current_amount' => ['numeric', new ZeroOrMore, 'lte:target_amount'],
'account_id' => 'required|numeric|belongsToUser:accounts,id',
'object_group_id' => 'numeric|belongsToUser:object_groups,id',
'target_amount' => ['numeric', new ZeroOrMore, 'lte:target_amount', 'required'],
'start_date' => 'date|nullable',
'target_date' => 'date|nullable|after:start_date',
'notes' => 'max:65000',
];
}
}

View File

@ -55,9 +55,9 @@ class FixRecurringTransactions extends Command
/**
* Execute the console command.
*
* @return mixed
* @return int
*/
public function handle()
public function handle(): int
{
$start = microtime(true);
$this->stupidLaravel();

View File

@ -50,9 +50,9 @@ class CreateDatabase extends Command
/**
* Execute the console command.
*
* @return mixed
* @return int
*/
public function handle()
public function handle(): int
{
if ('mysql' !== env('DB_CONNECTION')) {
$this->info(sprintf('CreateDB does not apply to "%s", skipped.', env('DB_CONNECTION')));

View File

@ -159,7 +159,7 @@ class DecryptDatabase extends Command
if ('The MAC is invalid.' === $e->getMessage()) {
throw new FireflyException($e->getMessage()); // @codeCoverageIgnore
}
Log::debug(sprintf('Could not decrypt. %s', $e->getMessage()));
//Log::debug(sprintf('Could not decrypt. %s', $e->getMessage()));
}
return $value;

View File

@ -1,76 +0,0 @@
<?php
/**
* CreateCSVImport.php
* Copyright (c) 2020 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/** @noinspection MultipleReturnStatementsInspection */
declare(strict_types=1);
namespace FireflyIII\Console\Commands\Import;
use Exception;
use FireflyIII\Console\Commands\VerifiesAccessToken;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\Routine\RoutineInterface;
use FireflyIII\Import\Storage\ImportArrayStorage;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\User;
use Illuminate\Console\Command;
use Log;
/**
* Class CreateCSVImport.
*
* @deprecated
* @codeCoverageIgnore
*/
class CreateCSVImport extends Command
{
use VerifiesAccessToken;
/**
* The console command description.
*
* @var string
*/
protected $description = 'Use this command to create a new CSV file import.';
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature
= 'firefly-iii:csv-import
{file? : The CSV file to import.}
{configuration? : The configuration file to use for the import.}
{--user=1 : The user ID that the import should import for.}
{--token= : The user\'s access token.}';
/**
* Run the command.
*/
public function handle(): int
{
$this->error('This command is disabled.');
return 1;
}
}

View File

@ -60,7 +60,7 @@ class ApplyRules extends Command
*/
protected $signature
= 'firefly-iii:apply-rules
{--user=1 : The user ID that the import should import for.}
{--user=1 : The user ID.}
{--token= : The user\'s access token.}
{--accounts= : A comma-separated list of asset accounts or liabilities to apply your rules to.}
{--rule_groups= : A comma-separated list of rule groups to apply. Take the ID\'s of these rule groups from the Firefly III interface.}

View File

@ -38,6 +38,7 @@ use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Log;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
/**
* Class GracefulNotFoundHandler
@ -53,7 +54,7 @@ class GracefulNotFoundHandler extends ExceptionHandler
* @throws Exception
* @return mixed
*/
public function render($request, Exception $exception)
public function render($request, Throwable $exception)
{
$route = $request->route();
if (null === $route) {
@ -136,12 +137,12 @@ class GracefulNotFoundHandler extends ExceptionHandler
/**
* @param Request $request
* @param Exception $exception
* @param Throwable $exception
*
* @throws Exception
* @return Redirector|Response
*/
private function handleAccount(Request $request, Exception $exception)
private function handleAccount(Request $request, Throwable $exception)
{
Log::debug('404 page is probably a deleted account. Redirect to overview of account types.');
/** @var User $user */
@ -164,12 +165,12 @@ class GracefulNotFoundHandler extends ExceptionHandler
/**
* @param Request $request
* @param Exception $exception
* @param Throwable $exception
*
* @throws Exception
* @return RedirectResponse|Redirector|Response
*/
private function handleAttachment(Request $request, Exception $exception)
private function handleAttachment(Request $request, Throwable $exception)
{
Log::debug('404 page is probably a deleted attachment. Redirect to parent object.');
/** @var User $user */
@ -208,13 +209,13 @@ class GracefulNotFoundHandler extends ExceptionHandler
}
/**
* @param Request $request
* @param Throwable $request
* @param Exception $exception
*
* @throws Exception
* @return RedirectResponse|\Illuminate\Http\Response|Redirector|Response
*/
private function handleGroup(Request $request, Exception $exception)
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 */

View File

@ -33,9 +33,9 @@ use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException as LaravelValidationException;
use League\OAuth2\Server\Exception\OAuthServerException;
use Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Illuminate\Http\Request;
use Throwable;
/**
* Class Handler
*
@ -51,7 +51,7 @@ class Handler extends ExceptionHandler
*
* @return mixed
*/
public function render($request, Exception $exception)
public function render($request, Throwable $exception)
{
if ($exception instanceof LaravelValidationException && $request->expectsJson()) {
// ignore it: controller will handle it.
@ -119,7 +119,7 @@ class Handler extends ExceptionHandler
*
* @return void
*/
public function report(Exception $exception)
public function report(Throwable $exception)
{
$doMailError = config('firefly.send_error_message');
// if the user wants us to mail:
@ -143,13 +143,13 @@ class Handler extends ExceptionHandler
'line' => $exception->getLine(),
'code' => $exception->getCode(),
'version' => config('firefly.version'),
'url' => Request::fullUrl(),
'userAgent' => Request::userAgent(),
'json' => Request::acceptsJson(),
'url' => request()->fullUrl(),
'userAgent' => request()->userAgent(),
'json' => request()->acceptsJson(),
];
// create job that will mail.
$ipAddress = Request::ip() ?? '0.0.0.0';
$ipAddress = request()->ip() ?? '0.0.0.0';
$job = new MailError($userData, (string) config('firefly.site_owner'), $ipAddress, $data);
dispatch($job);
}

View File

@ -36,6 +36,8 @@ trait CollectorProperties
private $hasAccountInfo;
/** @var bool Will be true if query result includes bill information. */
private $hasBillInformation;
/** @var bool */
private $hasNotesInformation;
/** @var bool Will be true if query result contains budget info. */
private $hasBudgetInformation;
/** @var bool Will be true if query result contains category info. */

View File

@ -28,6 +28,7 @@ use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Tag;
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Collection;
/**
@ -36,6 +37,27 @@ use Illuminate\Support\Collection;
trait MetaCollection
{
/**
* @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');
}
);
// add fields
$this->fields[] = 'notes.text as notes';
$this->hasNotesInformation = true;
}
return $this;
}
/**
* Limit the search to a specific bill.

View File

@ -62,6 +62,7 @@ class GroupCollector implements GroupCollectorInterface
$this->hasCatInformation = false;
$this->hasBudgetInformation = false;
$this->hasBillInformation = false;
$this->hasNotesInformation = false;
$this->hasJoinedTagTables = false;
$this->hasJoinedAttTables = false;
$this->integerFields = [
@ -552,9 +553,14 @@ class GroupCollector implements GroupCollectorInterface
$result['tags'] = [];
$result['attachments'] = [];
try {
$result['date'] = new Carbon($result['date']);
$result['created_at'] = new Carbon($result['created_at']);
$result['updated_at'] = new Carbon($result['updated_at']);
$result['date'] = new Carbon($result['date'], 'UTC');
$result['created_at'] = new Carbon($result['created_at'], 'UTC');
$result['updated_at'] = new Carbon($result['updated_at'], 'UTC');
// this is going to happen a lot:
$result['date']->setTimezone(env('TZ'));
$result['created_at']->setTimezone(env('TZ'));
$result['updated_at']->setTimezone(env('TZ'));
} catch (Exception $e) {
Log::error($e->getMessage());
}
@ -681,4 +687,5 @@ class GroupCollector implements GroupCollectorInterface
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
}
}

View File

@ -398,6 +398,13 @@ interface GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface;
/**
* Will include notes.
*
* @return GroupCollectorInterface
*/
public function withNotes(): GroupCollectorInterface;
/**
* Add tag info.
*

View File

@ -49,8 +49,7 @@ class EditController extends Controller
/** @var AccountRepositoryInterface The account repository */
private $repository;
/** @var AttachmentHelperInterface Helper for attachments. */
private $attachments;
private AttachmentHelperInterface $attachments;
/**
* EditController constructor.
@ -67,7 +66,7 @@ class EditController extends Controller
$this->repository = app(AccountRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
return $next($request);
}

View File

@ -130,7 +130,6 @@ class ReconcileController extends Controller
$startDate = clone $start;
$startDate->subDay();
$startBalance = round(app('steam')->balance($account, $startDate), $currency->decimal_places);
$endBalance = round(app('steam')->balance($account, $end), $currency->decimal_places);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $account->accountType->type));
$subTitle = (string) trans('firefly.reconcile_account', ['account' => $account->name]);

View File

@ -46,10 +46,8 @@ class ShowController extends Controller
{
use UserNavigation, PeriodOverview;
/** @var CurrencyRepositoryInterface The currency repository */
private $currencyRepos;
/** @var AccountRepositoryInterface The account repository */
private $repository;
private CurrencyRepositoryInterface $currencyRepos;
private AccountRepositoryInterface $repository;
/**
* ShowController constructor.

View File

@ -176,4 +176,35 @@ class LoginController extends Controller
throw $exception;
}
/**
* Log the user out of the application.
*
* @param \Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$authGuard = config('firefly.authentication_guard');
$logoutUri = config('firefly.custom_logout_uri');
if ('remote_user_guard' === $authGuard && '' !== $logoutUri) {
return redirect($logoutUri);
}
$this->guard()->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
if ($response = $this->loggedOut($request)) {
return $response;
}
return $request->wantsJson()
? new \Illuminate\Http\Response('', 204)
: redirect('/');
}
}

View File

@ -211,14 +211,20 @@ class BillController extends Controller
/** @var Collection $bills */
$bills = $unfiltered->map(
function (Bill $bill) use ($transformer, $defaultCurrency) {
$return = $transformer->transform($bill);
$currency = $bill->transactionCurrency ?? $defaultCurrency;
$return['currency_id'] = $currency->id;
$return['currency_name'] = $currency->name;
$return['currency_symbol'] = $currency->symbol;
$return['currency_code'] = $currency->code;
$return['currency_decimal_places'] = $currency->decimal_places;
$return['attachments'] = $this->billRepository->getAttachments($bill);
$return = $transformer->transform($bill);
$nextExpectedMatch = new Carbon($return['next_expected_match']);
$return['next_expected_match_diff'] = $nextExpectedMatch->isToday()
? trans('firefly.today')
: $nextExpectedMatch->diffForHumans(
today(), Carbon::DIFF_RELATIVE_TO_NOW
);
$currency = $bill->transactionCurrency ?? $defaultCurrency;
$return['currency_id'] = $currency->id;
$return['currency_name'] = $currency->name;
$return['currency_symbol'] = $currency->symbol;
$return['currency_code'] = $currency->code;
$return['currency_decimal_places'] = $currency->decimal_places;
$return['attachments'] = $this->billRepository->getAttachments($bill);
return $return;
}

View File

@ -39,13 +39,13 @@ class Controller extends BaseController
use AuthorizesRequests, DispatchesJobs, ValidatesRequests, UserNavigation, RequestInformation;
/** @var string Format for date and time. */
protected $dateTimeFormat;
protected string $dateTimeFormat;
/** @var string Format for "23 Feb, 2016". */
protected $monthAndDayFormat;
protected string $monthAndDayFormat;
/** @var string Format for "March 2018" */
protected $monthFormat;
protected string $monthFormat;
/** @var string Redirect user */
protected $redirectUri = '/';
protected string $redirectUri = '/';
/**
* Controller constructor.
@ -55,7 +55,7 @@ class Controller extends BaseController
public function __construct()
{
// is site a demo site?
$isDemoSite = app('fireflyconfig')->get('is_demo_site', config('firefly.configuration.is_demo_site',),)->data;
$isDemoSite = app('fireflyconfig')->get('is_demo_site', config('firefly.configuration.is_demo_site', false,),)->data;
app('view')->share('IS_DEMO_SITE', $isDemoSite,);
app('view')->share('DEMO_USERNAME', config('firefly.demo_username'));
app('view')->share('DEMO_PASSWORD', config('firefly.demo_password'));

View File

@ -138,6 +138,8 @@ class DebugController extends Controller
$appLogLevel = config('logging.level');
$cacheDriver = config('cache.default');
$loginProvider = config('auth.providers.users.driver');
$bcscale = bcscale();
$layout = env('FIREFLY_III_LAYOUT');
// some new vars.
$telemetry = true === config('firefly.send_telemetry') && true === config('firefly.feature_flags.telemetry');
@ -195,6 +197,8 @@ class DebugController extends Controller
'drivers',
'currentDriver',
'loginProvider',
'bcscale',
'layout',
'userAgent',
'displayErrors',
'installationId',
@ -224,15 +228,14 @@ class DebugController extends Controller
{
$set = RouteFacade::getRoutes();
$ignore = ['chart.', 'javascript.', 'json.', 'report-data.', 'popup.', 'debugbar.', 'attachments.download', 'attachments.preview',
'bills.rescan', 'budgets.income', 'currencies.def', 'error', 'flush', 'help.show', 'import.file',
'bills.rescan', 'budgets.income', 'currencies.def', 'error', 'flush', 'help.show',
'login', 'logout', 'password.reset', 'profile.confirm-email-change', 'profile.undo-email-change',
'register', 'report.options', 'routes', 'rule-groups.down', 'rule-groups.up', 'rules.up', 'rules.down',
'rules.select', 'search.search', 'test-flash', 'transactions.link.delete', 'transactions.link.switch',
'two-factor.lost', 'reports.options', 'debug', 'import.create-job', 'import.download', 'import.start', 'import.status.json',
'two-factor.lost', 'reports.options', 'debug',
'preferences.delete-code', 'rules.test-triggers', 'piggy-banks.remove-money', 'piggy-banks.add-money',
'accounts.reconcile.transactions', 'accounts.reconcile.overview',
'transactions.clone', 'two-factor.index', 'api.v1', 'installer.', 'attachments.view', 'import.create',
'import.job.download', 'import.job.start', 'import.job.status.json', 'import.job.store', 'recurring.events',
'transactions.clone', 'two-factor.index', 'api.v1', 'installer.', 'attachments.view', 'recurring.events',
'recurring.suggest',
];
$return = '&nbsp;';

View File

@ -1,82 +0,0 @@
<?php
/**
* CallbackController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Import;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Log;
/**
* Class CallbackController
*
* @deprecated
* @codeCoverageIgnore
*/
class CallbackController extends Controller
{
/**
* Callback specifically for YNAB logins.
*
* @param Request $request
*
* @param ImportJobRepositoryInterface $repository
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function ynab(Request $request, ImportJobRepositoryInterface $repository)
{
$code = (string) $request->get('code');
$jobKey = (string) $request->get('state');
if ('' === $code) {
return view('error')->with('message', 'You Need A Budget did not reply with a valid authorization code. Firefly III cannot continue.');
}
$importJob = $repository->findByKey($jobKey);
if ('' === $jobKey || null === $importJob) {
return view('error')->with('message', 'You Need A Budget did not reply with the correct state identifier. Firefly III cannot continue.');
}
Log::debug(sprintf('Got a code from YNAB: %s', $code));
// we have a code. Make the job ready for the next step, and then redirect the user.
$configuration = $repository->getConfiguration($importJob);
$configuration['auth_code'] = $code;
$repository->setConfiguration($importJob, $configuration);
// set stage to make the import routine take the correct action:
$repository->setStatus($importJob, 'ready_to_run');
$repository->setStage($importJob, 'get_access_token');
return redirect(route('import.job.status.index', [$importJob->key]));
}
}

View File

@ -1,198 +0,0 @@
<?php
/**
* IndexController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Import;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Import\Prerequisites\PrerequisitesInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\User\UserRepositoryInterface;
use FireflyIII\Support\Binder\ImportProvider;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response as LaravelResponse;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Log;
/**
*
* Class IndexController
*
* @deprecated
* @codeCoverageIgnore
*/
class IndexController extends Controller
{
/** @var array All available providers */
public $providers;
/** @var ImportJobRepositoryInterface The import job repository */
public $repository;
/** @var UserRepositoryInterface The user repository */
public $userRepository;
/**
* IndexController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-archive');
app('view')->share('title', (string) trans('firefly.import_index_title'));
$this->repository = app(ImportJobRepositoryInterface::class);
$this->userRepository = app(UserRepositoryInterface::class);
$this->providers = ImportProvider::getProviders();
return $next($request);
}
);
}
/**
* Creates a new import job for $importProvider.
*
* @param string $importProvider
*
* @return RedirectResponse|Redirector
*
*/
public function create(string $importProvider)
{
$hasPreReq = (bool) config(sprintf('import.has_prereq.%s', $importProvider));
$hasConfig = (bool) config(sprintf('import.has_job_config.%s', $importProvider));
$allowedForDemo = (bool) config(sprintf('import.allowed_for_demo.%s', $importProvider));
$isDemoUser = $this->userRepository->hasRole(auth()->user(), 'demo');
Log::debug(sprintf('Will create job for provider "%s"', $importProvider));
Log::debug(sprintf('Is demo user? %s', var_export($isDemoUser, true)));
Log::debug(sprintf('Is allowed for user? %s', var_export($allowedForDemo, true)));
Log::debug(sprintf('Has prerequisites? %s', var_export($hasPreReq, true)));
Log::debug(sprintf('Has config? %s', var_export($hasConfig, true)));
// @codeCoverageIgnoreStart
if ($isDemoUser && !$allowedForDemo) {
Log::debug('User is demo and this provider doesnt work for demo users.');
return redirect(route('import.index'));
}
// @codeCoverageIgnoreEnd
$importJob = $this->repository->create($importProvider);
Log::debug(sprintf('Created job #%d for provider %s', $importJob->id, $importProvider));
// no prerequisites but job has config:
if (false === $hasPreReq && false !== $hasConfig) {
Log::debug('Provider has no prerequisites. Continue.');
$this->repository->setStatus($importJob, 'has_prereq');
Log::debug('Redirect to configuration.');
return redirect(route('import.job.configuration.index', [$importJob->key]));
}
// job has prerequisites:
Log::debug('Job provider has prerequisites.');
/** @var PrerequisitesInterface $providerPre */
$providerPre = app((string) config(sprintf('import.prerequisites.%s', $importProvider)));
$providerPre->setUser($importJob->user);
// and are not filled in:
if (!$providerPre->isComplete()) {
Log::debug('Job provider prerequisites are not yet filled in. Redirect to prerequisites-page.');
// redirect to global prerequisites
return redirect(route('import.prerequisites.index', [$importProvider, $importJob->key]));
}
Log::debug('Prerequisites are complete.');
// but are filled in:
$this->repository->setStatus($importJob, 'has_prereq');
// and has no config:
if (false === $hasConfig) {
// @codeCoverageIgnoreStart
Log::debug('Provider has no configuration. Job is ready to start.');
$this->repository->setStatus($importJob, 'ready_to_run');
Log::debug('Redirect to status-page.');
return redirect(route('import.job.status.index', [$importJob->key]));
// @codeCoverageIgnoreEnd
}
// but also needs config:
Log::debug('Job has configuration. Redirect to job-config.');
// Otherwise just redirect to job configuration.
return redirect(route('import.job.configuration.index', [$importJob->key]));
}
/**
* Generate a JSON file of the job's configuration and send it to the user.
*
* @param ImportJob $job
*
* @return LaravelResponse
*/
public function download(ImportJob $job): LaravelResponse
{
Log::debug('Now in download()', ['job' => $job->key]);
$config = $this->repository->getConfiguration($job);
// This is CSV import specific:
$config['delimiter'] = $config['delimiter'] ?? ',';
$config['delimiter'] = "\t" === $config['delimiter'] ? 'tab' : $config['delimiter'];
$result = json_encode($config, JSON_PRETTY_PRINT);
$name = sprintf('"%s"', addcslashes('import-configuration-' . date('Y-m-d') . '.json', '"\\'));
/** @var LaravelResponse $response */
$response = response($result);
$response->header('Content-disposition', 'attachment; filename=' . $name)
->header('Content-Type', 'application/json')
->header('Content-Description', 'File Transfer')
->header('Connection', 'Keep-Alive')
->header('Expires', '0')
->header('Cache-Control', 'must-revalidate, post-check=0, pre-check=0')
->header('Pragma', 'public')
->header('Content-Length', strlen($result));
return $response;
}
/**
* General import index.
*
* @return Factory|View
*/
public function index()
{
$providers = $this->providers;
$subTitle = (string) trans('import.index_breadcrumb');
$subTitleIcon = 'fa-home';
$isDemoUser = $this->userRepository->hasRole(auth()->user(), 'demo');
return view('import.index', compact('subTitle', 'subTitleIcon', 'providers', 'isDemoUser'));
}
}

View File

@ -1,169 +0,0 @@
<?php
/**
* JobConfigurationController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Import;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Http\Controllers\CreateStuff;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Routing\Redirector;
use Illuminate\Support\MessageBag;
use Illuminate\View\View;
use Log;
/**
* Class JobConfigurationController
*
* @deprecated
* @codeCoverageIgnore
*/
class JobConfigurationController extends Controller
{
use CreateStuff;
/** @var ImportJobRepositoryInterface The import job repository */
public $repository;
/**
* JobConfigurationController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-archive');
app('view')->share('title', (string) trans('firefly.import_index_title'));
$this->repository = app(ImportJobRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Configure the job. This method is returned to until job is deemed "configured".
*
* @param ImportJob $importJob
*
* @throws FireflyException
*
* @return Factory|RedirectResponse|Redirector|View
*
*/
public function index(ImportJob $importJob)
{
Log::debug('Now in JobConfigurationController::index()');
$allowed = ['has_prereq', 'need_job_config'];
if (null !== $importJob && !in_array($importJob->status, $allowed, true)) {
Log::error(sprintf('Job has state "%s", but we only accept %s', $importJob->status, json_encode($allowed)));
session()->flash('error', (string) trans('import.bad_job_status', ['status' => e($importJob->status)]));
return redirect(route('import.index'));
}
Log::debug(sprintf('Now in JobConfigurationController::index() with job "%s" and status "%s"', $importJob->key, $importJob->status));
// if provider has no config, just push it through:
$importProvider = $importJob->provider;
if (!(bool) config(sprintf('import.has_job_config.%s', $importProvider))) {
// @codeCoverageIgnoreStart
Log::debug('Job needs no config, is ready to run!');
$this->repository->setStatus($importJob, 'ready_to_run');
return redirect(route('import.job.status.index', [$importJob->key]));
// @codeCoverageIgnoreEnd
}
$configurator = $this->makeConfigurator($importJob);
if ($configurator->configurationComplete()) {
Log::debug('Config is complete, set status to ready_to_run.');
$this->repository->setStatus($importJob, 'ready_to_run');
return redirect(route('import.job.status.index', [$importJob->key]));
}
$view = $configurator->getNextView();
$data = $configurator->getNextData();
$subTitle = (string) trans('import.job_configuration_breadcrumb', ['key' => $importJob->key]);
$subTitleIcon = 'fa-wrench';
return view($view, compact('data', 'importJob', 'subTitle', 'subTitleIcon'));
}
/**
* Store the configuration. Returns to "configure" method until job is configured.
*
* @param Request $request
* @param ImportJob $importJob
*
* @throws FireflyException
* @return RedirectResponse|Redirector
*
*/
public function post(Request $request, ImportJob $importJob)
{
// catch impossible status:
$allowed = ['has_prereq', 'need_job_config'];
if (null !== $importJob && !in_array($importJob->status, $allowed, true)) {
session()->flash('error', (string) trans('import.bad_job_status', ['status' => e($importJob->status)]));
return redirect(route('import.index'));
}
Log::debug('Now in postConfigure()', ['job' => $importJob->key]);
$configurator = $this->makeConfigurator($importJob);
// is the job already configured?
if ($configurator->configurationComplete()) {
$this->repository->setStatus($importJob, 'ready_to_run');
return redirect(route('import.job.status.index', [$importJob->key]));
}
// uploaded files are attached to the job.
// the configurator can then handle them.
$result = new MessageBag;
/** @var UploadedFile $upload */
foreach ($request->allFiles() as $name => $upload) {
$result = $this->repository->storeFileUpload($importJob, $name, $upload);
}
$data = $request->all();
$messages = $configurator->configureJob($data);
$result->merge($messages);
if ($messages->count() > 0) {
$request->session()->flash('warning', $messages->first());
}
// return to configure
return redirect(route('import.job.configuration.index', [$importJob->key]));
}
}

View File

@ -1,240 +0,0 @@
<?php
/**
* JobStatusController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Import;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Import\Routine\RoutineInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Http\Controllers\CreateStuff;
use Illuminate\Http\JsonResponse;
use Log;
/**
* Class JobStatusController
*
* @deprecated
* @codeCoverageIgnore
*/
class JobStatusController extends Controller
{
use CreateStuff;
/** @var ImportJobRepositoryInterface The import job repository */
private $repository;
/**
* JobStatusController constructor.
*/
public function __construct()
{
parent::__construct();
// set time limit to zero to prevent timeouts.
set_time_limit(0);
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-archive');
app('view')->share('title', (string) trans('firefly.import_index_title'));
$this->repository = app(ImportJobRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Index for job status.
*
* @param ImportJob $importJob
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index(ImportJob $importJob)
{
$subTitleIcon = 'fa-gear';
$subTitle = (string) trans('import.job_status_breadcrumb', ['key' => $importJob->key]);
return view('import.status', compact('importJob', 'subTitle', 'subTitleIcon'));
}
/**
* JSON overview of job status.
*
* @param ImportJob $importJob
*
* @return JsonResponse
*/
public function json(ImportJob $importJob): JsonResponse
{
$count = $this->repository->countTransactions($importJob);
$json = [
'status' => $importJob->status,
'errors' => $importJob->errors,
'count' => $count,
'tag_id' => $importJob->tag_id,
'tag_name' => null === $importJob->tag_id ? null : $importJob->tag->tag,
'report_txt' => (string) trans('import.unknown_import_result'),
'download_config' => false,
'download_config_text' => '',
];
if ('file' === $importJob->provider) {
$json['download_config'] = true;
$json['download_config_text']
= trans('import.should_download_config', ['route' => route('import.job.download', [$importJob->key])]) . ' '
. trans('import.share_config_file');
}
// if count is zero:
if (null !== $importJob->tag_id) {
$count = $this->repository->countByTag($importJob);
}
if (0 === $count) {
$json['report_txt'] = (string) trans('import.result_no_transactions');
}
if (1 === $count && null !== $importJob->tag_id) {
$json['report_txt'] = trans(
'import.result_one_transaction',
['route' => route('tags.show', [$importJob->tag_id, 'all']), 'tag' => $importJob->tag->tag]
);
}
if ($count > 1 && null !== $importJob->tag_id) {
$json['report_txt'] = trans(
'import.result_many_transactions',
['count' => $count, 'route' => route('tags.show', [$importJob->tag_id, 'all']), 'tag' => $importJob->tag->tag]
);
}
return response()->json($json);
}
/**
* Calls to start the job.
*
* @param ImportJob $importJob
*
* @return JsonResponse
*/
public function start(ImportJob $importJob): JsonResponse
{
Log::info('Now in JobStatusController::start');
// catch impossible status:
$allowed = ['ready_to_run', 'need_job_config'];
if (null !== $importJob && !in_array($importJob->status, $allowed, true)) {
Log::error(sprintf('Job is not ready. Status should be in array, but is %s', $importJob->status), $allowed);
$this->repository->setStatus($importJob, 'error');
return response()->json(
['status' => 'NOK', 'message' => sprintf('JobStatusController::start expects status "ready_to_run" instead of "%s".', $importJob->status)]
);
}
$importProvider = $importJob->provider;
$key = sprintf('import.routine.%s', $importProvider);
$className = config($key);
if (null === $className || !class_exists($className)) {
// @codeCoverageIgnoreStart
$message = sprintf('Cannot find import routine class for job of type "%s".', $importProvider);
Log::error($message);
return response()->json(
['status' => 'NOK', 'message' => $message]
);
// @codeCoverageIgnoreEnd
}
/** @var RoutineInterface $routine */
$routine = app($className);
$routine->setImportJob($importJob);
Log::debug(sprintf('Created class of type %s', $className));
try {
Log::debug(sprintf('Try to call %s:run()', $className));
$routine->run();
} catch (FireflyException|Exception $e) {
$message = 'The import routine crashed: ' . $e->getMessage();
Log::error($message);
Log::error($e->getTraceAsString());
// set job errored out:
$this->repository->setStatus($importJob, 'error');
return response()->json(['status' => 'NOK', 'message' => $message]);
}
// expect nothing from routine, just return OK to user.
Log::info('Now finished with JobStatusController::start');
return response()->json(['status' => 'OK', 'message' => 'stage_finished']);
}
/**
* Store does three things:
*
* - Store the transactions.
* - Add them to a tag.
*
* @param ImportJob $importJob
*
* @return JsonResponse
*/
public function store(ImportJob $importJob): JsonResponse
{
Log::info('Now in JobStatusController::store');
// catch impossible status:
$allowed = ['provider_finished', 'storing_data'];
if (null !== $importJob && !in_array($importJob->status, $allowed, true)) {
Log::error(sprintf('Job is not ready. Status should be in array, but is %s', $importJob->status), $allowed);
return response()->json(
['status' => 'NOK', 'message' => sprintf('JobStatusController::start expects status "provider_finished" instead of "%s".', $importJob->status)]
);
}
// set job to be storing data:
$this->repository->setStatus($importJob, 'storing_data');
try {
$this->storeTransactions($importJob);
} catch (FireflyException $e) {
$message = 'The import storage routine crashed: ' . $e->getMessage();
Log::error($message);
Log::error($e->getTraceAsString());
// set job errored out:
$this->repository->setStatus($importJob, 'error');
return response()->json(['status' => 'NOK', 'message' => $message]);
}
// set storage to be finished:
$this->repository->setStatus($importJob, 'storage_finished');
Log::info('Now finished with JobStatusController::start');
// expect nothing from routine, just return OK to user.
return response()->json(['status' => 'OK', 'message' => 'storage_finished']);
}
}

View File

@ -1,177 +0,0 @@
<?php
/**
* PrerequisitesController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Import;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Import\Prerequisites\PrerequisitesInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\User;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
use Log;
/**
* Class PrerequisitesController
*
* @deprecated
* @codeCoverageIgnore
*/
class PrerequisitesController extends Controller
{
/** @var ImportJobRepositoryInterface The import job repository */
private $repository;
/**
* PrerequisitesController constructor.
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-archive');
app('view')->share('title', (string) trans('firefly.import_index_title'));
app('view')->share('subTitleIcon', 'fa-check');
$this->repository = app(ImportJobRepositoryInterface::class);
return $next($request);
}
);
}
/**
* This method will process and store import provider global prerequisites
* such as API keys.
*
* @param string $importProvider
* @param ImportJob $importJob
*
* @return Factory|RedirectResponse|Redirector|View
*/
public function index(string $importProvider, ImportJob $importJob = null)
{
// catch impossible status:
$allowed = ['new'];
if (null !== $importJob && !in_array($importJob->status, $allowed, true)) {
Log::error(sprintf('Job has state "%s" but this Prerequisites::index() only accepts %s', $importJob->status, json_encode($allowed)));
session()->flash('error', (string) trans('import.bad_job_status', ['status' => e($importJob->status)]));
return redirect(route('import.index'));
}
app('view')->share('subTitle', (string) trans('import.prerequisites_breadcrumb_' . $importProvider));
$class = (string) config(sprintf('import.prerequisites.%s', $importProvider));
/** @var User $user */
$user = auth()->user();
/** @var PrerequisitesInterface $object */
$object = app($class);
$object->setUser($user);
if (null !== $importJob && $object->isComplete()) {
// update job:
$this->repository->setStatus($importJob, 'has_prereq');
// redirect to job config:
return redirect(route('import.job.configuration.index', [$importJob->key]));
}
$view = $object->getView();
$parameters = ['title' => (string) trans('firefly.import_index_title'), 'mainTitleIcon' => 'fa-archive', 'importJob' => $importJob];
$parameters = array_merge($object->getViewParameters(), $parameters);
return view($view, $parameters);
}
/**
* This method processes the prerequisites the user has entered in the previous step.
*
* Whatever storePrerequisites does, it should make sure that the system is ready to continue immediately. So
* no extra calls or stuff, except maybe to open a session
*
* @param Request $request
* @param string $importProvider
* @param ImportJob $importJob
*
* @return RedirectResponse|Redirector
* @see PrerequisitesInterface::storePrerequisites
*
*/
public function post(Request $request, string $importProvider, ImportJob $importJob = null)
{
Log::debug(sprintf('Now in postPrerequisites for %s', $importProvider));
// catch impossible status:
$allowed = ['new'];
if (null !== $importJob && !in_array($importJob->status, $allowed, true)) {
Log::error(sprintf('Job has state "%s" but this Prerequisites::post() only accepts %s', $importJob->status, json_encode($allowed)));
session()->flash('error', (string) trans('import.bad_job_status', ['status' => e($importJob->status)]));
return redirect(route('import.index'));
}
$class = (string) config(sprintf('import.prerequisites.%s', $importProvider));
/** @var User $user */
$user = auth()->user();
/** @var PrerequisitesInterface $object */
$object = app($class);
$object->setUser($user);
Log::debug('Going to store entered prerequisites.');
// store post data
$data = $request->all();
$result = $object->storePrerequisites($data);
Log::debug(sprintf('Result of storePrerequisites has message count: %d', $result->count()));
if ($result->count() > 0) {
$request->session()->flash('error', e($result->first()));
// redirect back to job, if has job:
return redirect(route('import.prerequisites.index', [$importProvider, $importJob->key ?? '']))->withInput();
}
// session flash!
$request->session()->flash('success', (string) trans('import.prerequisites_saved_for_' . $importProvider));
// if has job, redirect to global config for provider
// if no job, back to index!
if (null === $importJob) {
return redirect(route('import.index'));
}
// update job:
$this->repository->setStatus($importJob, 'has_prereq');
// redirect to job config:
return redirect(route('import.job.configuration.index', [$importJob->key]));
}
}

View File

@ -22,6 +22,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\TransactionCurrency;
@ -95,6 +96,30 @@ class JavascriptController extends Controller
->header('Content-Type', 'text/javascript');
}
/**
* Bit of a hack but OK.
*
* @param Request $request
*
* @return Response
*/
public function variablesV2(Request $request): Response
{
/** @var Carbon $start */
$start = clone session('start', Carbon::now()->startOfMonth());
/** @var Carbon $end */
$end = clone session('end', Carbon::now()->endOfMonth());
$data = [
'start' => $start->format('Y-m-d'),
'end' => $end->format('Y-m-d'),
];
return response()
->view('javascript.variables', $data)
->header('Content-Type', 'text/javascript');
}
/**
* Show some common variables to be used in scripts.
*

View File

@ -27,6 +27,7 @@ use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
@ -35,6 +36,7 @@ use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
@ -342,6 +344,34 @@ class AutoCompleteController extends Controller
return response()->json($return);
}
/**
* An auto-complete specifically for expense accounts, used when mass updating mostly.
*
* @param Request $request
*
* @return JsonResponse
*/
public function objectGroups(Request $request): JsonResponse
{
$search = $request->get('search');
/** @var ObjectGroupRepositoryInterface $repository */
$repository = app(ObjectGroupRepositoryInterface::class);
$return = [];
$result = $repository->search((string) $search);
/** @var ObjectGroup $account */
foreach ($result as $objectGroup) {
$return[] = [
'id' => $objectGroup->id,
'title' => $objectGroup->title,
];
}
return response()->json($return);
}
/**
* @return JsonResponse
* @codeCoverageIgnore

View File

@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\ObjectGroup;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
use Illuminate\Http\RedirectResponse;
/**
* Class DeleteController
*/
class DeleteController extends Controller
{
private ObjectGroupRepositoryInterface $repository;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-envelope-o');
app('view')->share('title', (string) trans('firefly.object_groups_page_title'));
$this->repository = app(ObjectGroupRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Delete a piggy bank.
*
* @param ObjectGroup $objectGroup
*/
public function delete(ObjectGroup $objectGroup)
{
$subTitle = (string) trans('firefly.delete_object_group', ['title' => $objectGroup->title]);
$piggyBanks = $objectGroup->piggyBanks()->count();
// put previous url in session
$this->rememberPreviousUri('object-groups.delete.uri');
return view('object-groups.delete', compact('objectGroup', 'subTitle', 'piggyBanks'));
}
/**
* Destroy the piggy bank.
*
* @param ObjectGroup $objectGroup
*/
public function destroy(ObjectGroup $objectGroup): RedirectResponse
{
session()->flash('success', (string) trans('firefly.deleted_object_group', ['title' => $objectGroup->title]));
app('preferences')->mark();
$this->repository->destroy($objectGroup);
return redirect($this->getPreviousUri('object-groups.delete.uri'));
}
}

View File

@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\ObjectGroup;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\ObjectGroupFormRequest;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
/**
* Class EditController
*/
class EditController extends Controller
{
private ObjectGroupRepositoryInterface $repository;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-envelope-o');
app('view')->share('title', (string) trans('firefly.object_groups_page_title'));
$this->repository = app(ObjectGroupRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Edit an object group.
*
* @param ObjectGroup $objectGroup
*/
public function edit(ObjectGroup $objectGroup)
{
$subTitle = (string) trans('firefly.edit_object_group', ['title' => $objectGroup->title]);
$subTitleIcon = 'fa-pencil';
$targetDate = null;
$startDate = null;
if (true !== session('object-groups.edit.fromUpdate')) {
$this->rememberPreviousUri('object-groups.edit.uri');
}
session()->forget('object-groups.edit.fromUpdate');
return view('object-groups.edit', compact('subTitle', 'subTitleIcon', 'objectGroup'));
}
/**
* Update a piggy bank.
*
* @param ObjectGroupFormRequest $request
* @param ObjectGroup $objectGroup
*/
public function update(ObjectGroupFormRequest $request, ObjectGroup $objectGroup)
{
$data = $request->getObjectGroupData();
$piggyBank = $this->repository->update($objectGroup, $data);
session()->flash('success', (string) trans('firefly.updated_object_group', ['title' => $objectGroup->title]));
app('preferences')->mark();
$redirect = redirect($this->getPreviousUri('object-groups.edit.uri'));
if (1 === (int) $request->get('return_to_edit')) {
// @codeCoverageIgnoreStart
session()->put('object-groups.edit.fromUpdate', true);
$redirect = redirect(route('object-groups.edit', [$piggyBank->id]));
// @codeCoverageIgnoreEnd
}
return $redirect;
}
}

View File

@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\ObjectGroup;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\ObjectGroup;
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
use Illuminate\Http\Request;
use Log;
/**
* Class IndexController
*/
class IndexController extends Controller
{
private ObjectGroupRepositoryInterface $repository;
/**
* IndexController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
// translations:
$this->middleware(
function ($request, $next) {
app('view')->share('mainTitleIcon', 'fa-envelope-o');
app('view')->share('title', (string) trans('firefly.object_groups_page_title'));
$this->repository = app(ObjectGroupRepositoryInterface::class);
return $next($request);
}
);
}
/**
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function index()
{
$this->repository->sort();
$subTitle = (string) trans('firefly.object_groups_index');
$objectGroups = $this->repository->get();
return view('object-groups.index', compact('subTitle', 'objectGroups'));
}
/**
* @param ObjectGroup $objectGroup
*/
public function setOrder(Request $request, ObjectGroup $objectGroup)
{
Log::debug(sprintf('Found object group #%d "%s"', $objectGroup->id, $objectGroup->title));
$newOrder = (int) $request->get('order');
$this->repository->setOrder($objectGroup, $newOrder);
return response()->json([]);
}
}

View File

@ -0,0 +1,201 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Log;
/**
* Class AmountController
*/
class AmountController extends Controller
{
private AccountRepositoryInterface $accountRepos;
private PiggyBankRepositoryInterface $piggyRepos;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
$this->accountRepos = app(AccountRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Add money to piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function add(PiggyBank $piggyBank)
{
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, new Carbon);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.add', compact('piggyBank', 'maxAmount', 'currency'));
}
/**
* Add money to piggy bank (for mobile devices).
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function addMobile(PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', new Carbon);
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount', 'currency'));
}
/**
* Add money to piggy bank.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return RedirectResponse
*/
public function postAdd(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$amount = $request->get('amount') ?? '0';
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
// if amount is negative, make positive and continue:
if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1');
}
if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) {
$this->piggyRepos->addAmount($piggyBank, $amount);
session()->flash(
'success',
(string) trans(
'firefly.added_amount_to_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
);
app('preferences')->mark();
return redirect(route('piggy-banks.index'));
}
Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.');
session()->flash(
'error',
(string) trans(
'firefly.cannot_add_amount_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)]
)
);
return redirect(route('piggy-banks.index'));
}
/**
* Remove money from piggy bank.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return RedirectResponse
*/
public function postRemove(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$amount = $request->get('amount') ?? '0';
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
// if amount is negative, make positive and continue:
if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1');
}
if ($this->piggyRepos->canRemoveAmount($piggyBank, $amount)) {
$this->piggyRepos->removeAmount($piggyBank, $amount);
session()->flash(
'success',
(string) trans(
'firefly.removed_amount_from_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
);
app('preferences')->mark();
return redirect(route('piggy-banks.index'));
}
$amount = (string) round($request->get('amount'), 12);
session()->flash(
'error',
(string) trans(
'firefly.cannot_remove_from_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)]
)
);
return redirect(route('piggy-banks.index'));
}
/**
* Remove money from piggy bank form.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function remove(PiggyBank $piggyBank)
{
$repetition = $this->piggyRepos->getRepetition($piggyBank);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.remove', compact('piggyBank', 'repetition', 'currency'));
}
/**
* Remove money from piggy bank (for mobile devices).
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function removeMobile(PiggyBank $piggyBank)
{
$repetition = $this->piggyRepos->getRepetition($piggyBank);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.remove-mobile', compact('piggyBank', 'repetition', 'currency'));
}
}

View File

@ -0,0 +1,112 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
/**
* Class CreateController
*/
class CreateController extends Controller
{
private AttachmentHelperInterface $attachments;
private PiggyBankRepositoryInterface $piggyRepos;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->attachments = app(AttachmentHelperInterface::class);
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Create a piggy bank.
*
* @return Factory|View
*/
public function create()
{
$subTitle = (string) trans('firefly.new_piggy_bank');
$subTitleIcon = 'fa-plus';
// put previous url in session if not redirect from store (not "create another").
if (true !== session('piggy-banks.create.fromStore')) {
$this->rememberPreviousUri('piggy-banks.create.uri');
}
session()->forget('piggy-banks.create.fromStore');
return view('piggy-banks.create', compact('subTitle', 'subTitleIcon'));
}
/**
* Store a new piggy bank.
*
* @param PiggyBankFormRequest $request
*
* @return RedirectResponse|Redirector
*/
public function store(PiggyBankFormRequest $request)
{
$data = $request->getPiggyBankData();
if (null === $data['startdate']) {
$data['startdate'] = new Carbon;
}
$piggyBank = $this->piggyRepos->store($data);
session()->flash('success', (string) trans('firefly.stored_piggy_bank', ['name' => $piggyBank->name]));
app('preferences')->mark();
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info', (string) trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
$redirect = redirect($this->getPreviousUri('piggy-banks.create.uri'));
if (1 === (int) $request->get('create_another')) {
// @codeCoverageIgnoreStart
session()->put('piggy-banks.create.fromStore', true);
$redirect = redirect(route('piggy-banks.create'))->withInput();
// @codeCoverageIgnoreEnd
}
return $redirect;
}
}

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\PiggyBank;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
/**
* Class DeleteController
*/
class DeleteController extends Controller
{
private PiggyBankRepositoryInterface $piggyRepos;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Delete a piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function delete(PiggyBank $piggyBank)
{
$subTitle = (string) trans('firefly.delete_piggy_bank', ['name' => $piggyBank->name]);
// put previous url in session
$this->rememberPreviousUri('piggy-banks.delete.uri');
return view('piggy-banks.delete', compact('piggyBank', 'subTitle'));
}
/**
* Destroy the piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return RedirectResponse
*/
public function destroy(PiggyBank $piggyBank): RedirectResponse
{
session()->flash('success', (string) trans('firefly.deleted_piggy_bank', ['name' => $piggyBank->name]));
app('preferences')->mark();
$this->piggyRepos->destroy($piggyBank);
return redirect($this->getPreviousUri('piggy-banks.delete.uri'));
}
}

View File

@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\PiggyBank;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\RedirectResponse;
use Illuminate\Routing\Redirector;
use Illuminate\View\View;
/**
* Class EditController
*/
class EditController extends Controller
{
private AttachmentHelperInterface $attachments;
private PiggyBankRepositoryInterface $piggyRepos;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->attachments = app(AttachmentHelperInterface::class);
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Edit a piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function edit(PiggyBank $piggyBank)
{
$subTitle = (string) trans('firefly.update_piggy_title', ['name' => $piggyBank->name]);
$subTitleIcon = 'fa-pencil';
$targetDate = null;
$startDate = null;
$note = $piggyBank->notes()->first();
// Flash some data to fill the form.
if (null !== $piggyBank->targetdate) {
$targetDate = $piggyBank->targetdate->format('Y-m-d');
}
if (null !== $piggyBank->startdate) {
$startDate = $piggyBank->startdate->format('Y-m-d');
}
$preFilled = ['name' => $piggyBank->name,
'account_id' => $piggyBank->account_id,
'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate,
'startdate' => $startDate,
'object_group' => $piggyBank->objectGroups->first() ? $piggyBank->objectGroups->first()->title : '',
'notes' => null === $note ? '' : $note->text,
];
session()->flash('preFilled', $preFilled);
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('piggy-banks.edit.fromUpdate')) {
$this->rememberPreviousUri('piggy-banks.edit.uri');
}
session()->forget('piggy-banks.edit.fromUpdate');
return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'preFilled'));
}
/**
* Update a piggy bank.
*
* @param PiggyBankFormRequest $request
* @param PiggyBank $piggyBank
*
* @return RedirectResponse|Redirector
*/
public function update(PiggyBankFormRequest $request, PiggyBank $piggyBank)
{
$data = $request->getPiggyBankData();
$piggyBank = $this->piggyRepos->update($piggyBank, $data);
session()->flash('success', (string) trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name]));
app('preferences')->mark();
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info', (string) trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
$redirect = redirect($this->getPreviousUri('piggy-banks.edit.uri'));
if (1 === (int) $request->get('return_to_edit')) {
// @codeCoverageIgnoreStart
session()->put('piggy-banks.edit.fromUpdate', true);
$redirect = redirect(route('piggy-banks.edit', [$piggyBank->id]));
// @codeCoverageIgnoreEnd
}
return $redirect;
}
}

View File

@ -0,0 +1,189 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\ObjectGroup\OrganisesObjectGroups;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class IndexController
*/
class IndexController extends Controller
{
use OrganisesObjectGroups;
private PiggyBankRepositoryInterface $piggyRepos;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Show overview of all piggy banks.
* TODO complicated
*
* @param Request $request
*
* @return Factory|View
*/
public function index(Request $request)
{
$this->cleanupObjectGroups();
$this->piggyRepos->correctOrder();
$collection = $this->piggyRepos->getPiggyBanks();
$accounts = [];
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
// transform piggies using the transformer:
$parameters = new ParameterBag;
$parameters->set('end', $end);
// make piggy bank groups:
$piggyBanks = [
0 => [ // the index is the order, not the ID.
'object_group_id' => 0,
'object_group_title' => (string) trans('firefly.default_group_title_name'),
'piggy_banks' => [],
],
];
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters(new ParameterBag);
/** @var AccountTransformer $accountTransformer */
$accountTransformer = app(AccountTransformer::class);
$accountTransformer->setParameters($parameters);
/** @var PiggyBank $piggy */
foreach ($collection as $piggy) {
$array = $transformer->transform($piggy);
$groupOrder = (int) $array['object_group_order'];
// make group array if necessary:
$piggyBanks[$groupOrder] = $piggyBanks[$groupOrder] ?? [
'object_group_id' => $array['object_group_id'],
'object_group_title' => $array['object_group_title'],
'piggy_banks' => [],
];
$account = $accountTransformer->transform($piggy->account);
$accountId = (int) $account['id'];
$array['attachments'] = $this->piggyRepos->getAttachments($piggy);
if (!isset($accounts[$accountId])) {
// create new:
$accounts[$accountId] = $account;
// add some interesting details:
$accounts[$accountId]['left'] = $accounts[$accountId]['current_balance'];
$accounts[$accountId]['saved'] = 0;
$accounts[$accountId]['target'] = 0;
$accounts[$accountId]['to_save'] = 0;
}
// calculate new interesting fields:
$accounts[$accountId]['left'] -= $array['current_amount'];
$accounts[$accountId]['saved'] += $array['current_amount'];
$accounts[$accountId]['target'] += $array['target_amount'];
$accounts[$accountId]['to_save'] += ($array['target_amount'] - $array['current_amount']);
$array['account_name'] = $account['name'];
$piggyBanks[$groupOrder]['piggy_banks'][] = $array;
}
// do a bunch of summaries.
$piggyBanks = $this->makeSums($piggyBanks);
ksort($piggyBanks);
return view('piggy-banks.index', compact('piggyBanks', 'accounts'));
}
/**
* @param array $piggyBanks
*
* @return array
*/
private function makeSums(array $piggyBanks): array
{
$sums = [];
foreach ($piggyBanks as $groupOrder => $group) {
$groupId = $group['object_group_id'];
foreach ($group['piggy_banks'] as $piggy) {
$currencyId = $piggy['currency_id'];
$sums[$groupId][$currencyId] = $sums[$groupId][$currencyId] ?? [
'target' => '0',
'saved' => '0',
'left_to_save' => '0',
'save_per_month' => '0',
'currency_id' => $currencyId,
'currency_code' => $piggy['currency_code'],
'currency_symbol' => $piggy['currency_symbol'],
'currency_decimal_places' => $piggy['currency_decimal_places'],
];
// target_amount
// current_amount
// left_to_save
// save_per_month
$sums[$groupId][$currencyId]['target'] = bcadd($sums[$groupId][$currencyId]['target'], (string) $piggy['target_amount']);
$sums[$groupId][$currencyId]['saved'] = bcadd($sums[$groupId][$currencyId]['saved'], (string) $piggy['current_amount']);
$sums[$groupId][$currencyId]['left_to_save'] = bcadd($sums[$groupId][$currencyId]['left_to_save'], (string) $piggy['left_to_save']);
$sums[$groupId][$currencyId]['save_per_month'] = bcadd($sums[$groupId][$currencyId]['save_per_month'], (string) $piggy['save_per_month']);
}
}
foreach ($piggyBanks as $groupOrder => $group) {
$groupId = $group['object_group_id'];
$piggyBanks[$groupOrder]['sums'] = $sums[$groupId];
}
return $piggyBanks;
}
/**
* Set the order of a piggy bank.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function setOrder(Request $request, PiggyBank $piggyBank): JsonResponse
{
$objectGroupTitle = $request->get('objectGroupTitle');
$newOrder = (int) $request->get('order');
$this->piggyRepos->setOrder($piggyBank, $newOrder);
if ('' !== $objectGroupTitle) {
$this->piggyRepos->setObjectGroup($piggyBank, $objectGroupTitle);
}
if ('' === $objectGroupTitle) {
$this->piggyRepos->removeObjectGroup($piggyBank);
}
return response()->json(['data' => 'OK']);
}
}

View File

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\PiggyBank;
use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\PiggyBankTransformer;
use Illuminate\Contracts\View\Factory;
use Illuminate\View\View;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class ShowController
*/
class ShowController extends Controller
{
private PiggyBankRepositoryInterface $piggyRepos;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Show a single piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function show(PiggyBank $piggyBank)
{
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
// transform piggies using the transformer:
$parameters = new ParameterBag;
$parameters->set('end', $end);
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($parameters);
$piggy = $transformer->transform($piggyBank);
$events = $this->piggyRepos->getEvents($piggyBank);
$subTitle = $piggyBank->name;
$attachments = $this->piggyRepos->getAttachments($piggyBank);
return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle', 'piggy', 'attachments'));
}
}

View File

@ -1,525 +0,0 @@
<?php
/**
* PiggyBankController.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use Carbon\Carbon;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Requests\PiggyBankFormRequest;
use FireflyIII\Models\PiggyBank;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
use FireflyIII\Transformers\AccountTransformer;
use FireflyIII\Transformers\PiggyBankTransformer;
use Illuminate\Contracts\View\Factory;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Routing\Redirector;
use Illuminate\Support\Collection;
use Illuminate\View\View;
use Log;
use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class PiggyBankController.
*
*/
class PiggyBankController extends Controller
{
/** @var AccountRepositoryInterface The account repository */
private $accountRepos;
/** @var CurrencyRepositoryInterface The currency repository */
private $currencyRepos;
/** @var PiggyBankRepositoryInterface Piggy bank repository. */
private $piggyRepos;
/** @var AttachmentHelperInterface Helper for attachments. */
private $attachments;
/**
* PiggyBankController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
{
parent::__construct();
$this->middleware(
function ($request, $next) {
app('view')->share('title', (string) trans('firefly.piggyBanks'));
app('view')->share('mainTitleIcon', 'fa-bullseye');
$this->attachments = app(AttachmentHelperInterface::class);
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
$this->currencyRepos = app(CurrencyRepositoryInterface::class);
$this->accountRepos = app(AccountRepositoryInterface::class);
return $next($request);
}
);
}
/**
* Add money to piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function add(PiggyBank $piggyBank)
{
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, new Carbon);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.add', compact('piggyBank', 'maxAmount', 'currency'));
}
/**
* Add money to piggy bank (for mobile devices).
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function addMobile(PiggyBank $piggyBank)
{
/** @var Carbon $date */
$date = session('end', new Carbon);
$leftOnAccount = $this->piggyRepos->leftOnAccount($piggyBank, $date);
$savedSoFar = $this->piggyRepos->getCurrentAmount($piggyBank);
$leftToSave = bcsub($piggyBank->targetamount, $savedSoFar);
$maxAmount = min($leftOnAccount, $leftToSave);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.add-mobile', compact('piggyBank', 'maxAmount', 'currency'));
}
/**
* Create a piggy bank.
*
* @return Factory|View
*/
public function create()
{
$subTitle = (string) trans('firefly.new_piggy_bank');
$subTitleIcon = 'fa-plus';
// put previous url in session if not redirect from store (not "create another").
if (true !== session('piggy-banks.create.fromStore')) {
$this->rememberPreviousUri('piggy-banks.create.uri');
}
session()->forget('piggy-banks.create.fromStore');
return view('piggy-banks.create', compact('subTitle', 'subTitleIcon'));
}
/**
* Delete a piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function delete(PiggyBank $piggyBank)
{
$subTitle = (string) trans('firefly.delete_piggy_bank', ['name' => $piggyBank->name]);
// put previous url in session
$this->rememberPreviousUri('piggy-banks.delete.uri');
return view('piggy-banks.delete', compact('piggyBank', 'subTitle'));
}
/**
* Destroy the piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return RedirectResponse
*/
public function destroy(PiggyBank $piggyBank): RedirectResponse
{
session()->flash('success', (string) trans('firefly.deleted_piggy_bank', ['name' => $piggyBank->name]));
app('preferences')->mark();
$this->piggyRepos->destroy($piggyBank);
return redirect($this->getPreviousUri('piggy-banks.delete.uri'));
}
/**
* Edit a piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function edit(PiggyBank $piggyBank)
{
$subTitle = (string) trans('firefly.update_piggy_title', ['name' => $piggyBank->name]);
$subTitleIcon = 'fa-pencil';
$targetDate = null;
$startDate = null;
$note = $piggyBank->notes()->first();
// Flash some data to fill the form.
if (null !== $piggyBank->targetdate) {
$targetDate = $piggyBank->targetdate->format('Y-m-d');
}
if (null !== $piggyBank->startdate) {
$startDate = $piggyBank->startdate->format('Y-m-d');
}
$preFilled = ['name' => $piggyBank->name,
'account_id' => $piggyBank->account_id,
'targetamount' => $piggyBank->targetamount,
'targetdate' => $targetDate,
'startdate' => $startDate,
'notes' => null === $note ? '' : $note->text,
];
session()->flash('preFilled', $preFilled);
// put previous url in session if not redirect from store (not "return_to_edit").
if (true !== session('piggy-banks.edit.fromUpdate')) {
$this->rememberPreviousUri('piggy-banks.edit.uri');
}
session()->forget('piggy-banks.edit.fromUpdate');
return view('piggy-banks.edit', compact('subTitle', 'subTitleIcon', 'piggyBank', 'preFilled'));
}
/**
* Show overview of all piggy banks.
*
* @param Request $request
*
* @return Factory|View
*/
public function index(Request $request)
{
$this->piggyRepos->correctOrder();
$collection = $this->piggyRepos->getPiggyBanks();
$total = $collection->count();
$page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
$accounts = [];
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
// transform piggies using the transformer:
$parameters = new ParameterBag;
$parameters->set('end', $end);
$transformed = new Collection;
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters(new ParameterBag);
/** @var AccountTransformer $accountTransformer */
$accountTransformer = app(AccountTransformer::class);
$accountTransformer->setParameters($parameters);
/** @var PiggyBank $piggy */
foreach ($collection as $piggy) {
$array = $transformer->transform($piggy);
$account = $accountTransformer->transform($piggy->account);
$accountId = (int) $account['id'];
$array['attachments'] = $this->piggyRepos->getAttachments($piggy);
if (!isset($accounts[$accountId])) {
// create new:
$accounts[$accountId] = $account;
// add some interesting details:
$accounts[$accountId]['left'] = $accounts[$accountId]['current_balance'];
$accounts[$accountId]['saved'] = 0;
$accounts[$accountId]['target'] = 0;
$accounts[$accountId]['to_save'] = 0;
}
// calculate new interesting fields:
$accounts[$accountId]['left'] -= $array['current_amount'];
$accounts[$accountId]['saved'] += $array['current_amount'];
$accounts[$accountId]['target'] += $array['target_amount'];
$accounts[$accountId]['to_save'] += ($array['target_amount'] - $array['current_amount']);
$array['account_name'] = $account['name'];
$transformed->push($array);
}
$transformed = $transformed->slice(($page - 1) * $pageSize, $pageSize);
$piggyBanks = new LengthAwarePaginator($transformed, $total, $pageSize, $page);
$piggyBanks->setPath(route('piggy-banks.index'));
return view('piggy-banks.index', compact('piggyBanks', 'accounts'));
}
/**
* Add money to piggy bank.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return RedirectResponse
*/
public function postAdd(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$amount = $request->get('amount') ?? '0';
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
// if amount is negative, make positive and continue:
if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1');
}
if ($this->piggyRepos->canAddAmount($piggyBank, $amount)) {
$this->piggyRepos->addAmount($piggyBank, $amount);
session()->flash(
'success',
(string) trans(
'firefly.added_amount_to_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
);
app('preferences')->mark();
return redirect(route('piggy-banks.index'));
}
Log::error('Cannot add ' . $amount . ' because canAddAmount returned false.');
session()->flash(
'error',
(string) trans(
'firefly.cannot_add_amount_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)]
)
);
return redirect(route('piggy-banks.index'));
}
/**
* Remove money from piggy bank.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return RedirectResponse
*/
public function postRemove(Request $request, PiggyBank $piggyBank): RedirectResponse
{
$amount = $request->get('amount') ?? '0';
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
// if amount is negative, make positive and continue:
if (-1 === bccomp($amount, '0')) {
$amount = bcmul($amount, '-1');
}
if ($this->piggyRepos->canRemoveAmount($piggyBank, $amount)) {
$this->piggyRepos->removeAmount($piggyBank, $amount);
session()->flash(
'success',
(string) trans(
'firefly.removed_amount_from_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => $piggyBank->name]
)
);
app('preferences')->mark();
return redirect(route('piggy-banks.index'));
}
$amount = (string) round($request->get('amount'), 12);
session()->flash(
'error',
(string) trans(
'firefly.cannot_remove_from_piggy',
['amount' => app('amount')->formatAnything($currency, $amount, false), 'name' => e($piggyBank->name)]
)
);
return redirect(route('piggy-banks.index'));
}
/**
* Remove money from piggy bank form.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function remove(PiggyBank $piggyBank)
{
$repetition = $this->piggyRepos->getRepetition($piggyBank);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.remove', compact('piggyBank', 'repetition', 'currency'));
}
/**
* Remove money from piggy bank (for mobile devices).
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function removeMobile(PiggyBank $piggyBank)
{
$repetition = $this->piggyRepos->getRepetition($piggyBank);
$currency = $this->accountRepos->getAccountCurrency($piggyBank->account) ?? app('amount')->getDefaultCurrency();
return view('piggy-banks.remove-mobile', compact('piggyBank', 'repetition', 'currency'));
}
/**
* Set the order of a piggy bank.
*
* @param Request $request
* @param PiggyBank $piggyBank
*
* @return JsonResponse
*/
public function setOrder(Request $request, PiggyBank $piggyBank): JsonResponse
{
$newOrder = (int) $request->get('order');
$this->piggyRepos->setOrder($piggyBank, $newOrder);
return response()->json(['data' => 'OK']);
}
/**
* Show a single piggy bank.
*
* @param PiggyBank $piggyBank
*
* @return Factory|View
*/
public function show(PiggyBank $piggyBank)
{
/** @var Carbon $end */
$end = session('end', Carbon::now()->endOfMonth());
// transform piggies using the transformer:
$parameters = new ParameterBag;
$parameters->set('end', $end);
/** @var PiggyBankTransformer $transformer */
$transformer = app(PiggyBankTransformer::class);
$transformer->setParameters($parameters);
$piggy = $transformer->transform($piggyBank);
$events = $this->piggyRepos->getEvents($piggyBank);
$subTitle = $piggyBank->name;
$attachments = $this->piggyRepos->getAttachments($piggyBank);
return view('piggy-banks.show', compact('piggyBank', 'events', 'subTitle', 'piggy', 'attachments'));
}
/**
* Store a new piggy bank.
*
* @param PiggyBankFormRequest $request
*
* @return RedirectResponse|Redirector
*/
public function store(PiggyBankFormRequest $request)
{
$data = $request->getPiggyBankData();
if (null === $data['startdate']) {
$data['startdate'] = new Carbon;
}
$piggyBank = $this->piggyRepos->store($data);
session()->flash('success', (string) trans('firefly.stored_piggy_bank', ['name' => $piggyBank->name]));
app('preferences')->mark();
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
$redirect = redirect($this->getPreviousUri('piggy-banks.create.uri'));
if (1 === (int) $request->get('create_another')) {
// @codeCoverageIgnoreStart
session()->put('piggy-banks.create.fromStore', true);
$redirect = redirect(route('piggy-banks.create'))->withInput();
// @codeCoverageIgnoreEnd
}
return $redirect;
}
/**
* Update a piggy bank.
*
* @param PiggyBankFormRequest $request
* @param PiggyBank $piggyBank
*
* @return RedirectResponse|Redirector
*/
public function update(PiggyBankFormRequest $request, PiggyBank $piggyBank)
{
$data = $request->getPiggyBankData();
$piggyBank = $this->piggyRepos->update($piggyBank, $data);
session()->flash('success', (string) trans('firefly.updated_piggy_bank', ['name' => $piggyBank->name]));
app('preferences')->mark();
// store new attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($piggyBank, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
$redirect = redirect($this->getPreviousUri('piggy-banks.edit.uri'));
if (1 === (int) $request->get('return_to_edit')) {
// @codeCoverageIgnoreStart
session()->put('piggy-banks.edit.fromUpdate', true);
$redirect = redirect(route('piggy-banks.edit', [$piggyBank->id]));
// @codeCoverageIgnoreEnd
}
return $redirect;
}
}

View File

@ -61,6 +61,8 @@ class ProfileController extends Controller
{
use RequestInformation, CreateStuff;
protected bool $externalIdentity;
/**
* ProfileController constructor.
*
@ -78,6 +80,9 @@ class ProfileController extends Controller
return $next($request);
}
);
$loginProvider = config('firefly.login_provider');
$authGuard = config('firefly.authentication_guard');
$this->externalIdentity = 'eloquent' === $loginProvider || 'remote_user_guard' === $authGuard;
$this->middleware(IsDemoUser::class)->except(['index']);
$this->middleware(IsSandStormUser::class)->except('index');
@ -92,13 +97,10 @@ class ProfileController extends Controller
*/
public function changeEmail(Request $request)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
// @codeCoverageIgnoreStart
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)]));
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
// @codeCoverageIgnoreEnd
}
$title = auth()->user()->email;
@ -118,13 +120,10 @@ class ProfileController extends Controller
*/
public function changePassword(Request $request)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
// @codeCoverageIgnoreStart
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)]));
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
// @codeCoverageIgnoreEnd
}
$title = auth()->user()->email;
@ -137,10 +136,17 @@ class ProfileController extends Controller
/**
* View that generates a 2FA code for the user.
*
* @param Request $request
*
* @return Factory|View
*/
public function code()
public function code(Request $request)
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
$domain = $this->getDomain();
$secret = null;
@ -192,10 +198,9 @@ class ProfileController extends Controller
*/
public function confirmEmailChange(UserRepositoryInterface $repository, string $token)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
if ($this->externalIdentity) {
// @codeCoverageIgnoreStart
throw new FireflyException('Cannot confirm email change when authentication provider is not local.');
throw new FireflyException(trans('firefly.external_user_mgt_disabled'));
// @codeCoverageIgnoreEnd
}
// find preference with this token value.
@ -229,15 +234,14 @@ class ProfileController extends Controller
*
* @param Request $request
*
* @return Factory|View
* @return \Illuminate\Contracts\Foundation\Application|RedirectResponse|Redirector
*/
public function deleteAccount(Request $request)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
// @codeCoverageIgnoreStart
$request->session()->flash('warning', trans('firefly.delete_local_info_only', ['login_provider' => e($loginProvider)]));
// @codeCoverageIgnoreEnd
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
$title = auth()->user()->email;
$subTitle = (string) trans('firefly.delete_account');
@ -251,8 +255,13 @@ class ProfileController extends Controller
*
* @return RedirectResponse|Redirector
*/
public function deleteCode()
public function deleteCode(Request $request)
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
/** @var UserRepositoryInterface $repository */
$repository = app(UserRepositoryInterface::class);
@ -271,8 +280,14 @@ class ProfileController extends Controller
*
* @return RedirectResponse|Redirector
*/
public function enable2FA()
public function enable2FA(Request $request)
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
/** @var User $user */
$user = auth()->user();
$enabledMFA = null !== $user->mfa_secret;
@ -329,6 +344,12 @@ class ProfileController extends Controller
*/
public function newBackupCodes()
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
// generate recovery codes:
$recovery = app(Recovery::class);
$recoveryCodes = $recovery->lowercase()
@ -354,13 +375,10 @@ class ProfileController extends Controller
*/
public function postChangeEmail(EmailFormRequest $request, UserRepositoryInterface $repository)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
// @codeCoverageIgnoreStart
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)]));
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
// @codeCoverageIgnoreEnd
}
/** @var User $user */
@ -408,13 +426,10 @@ class ProfileController extends Controller
*/
public function postChangePassword(ProfileFormRequest $request, UserRepositoryInterface $repository)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
// @codeCoverageIgnoreStart
$request->session()->flash('error', trans('firefly.login_provider_local_only', ['login_provider' => e($loginProvider)]));
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
// @codeCoverageIgnoreEnd
}
// the request has already validated both new passwords must be equal.
@ -446,6 +461,12 @@ class ProfileController extends Controller
*/
public function postCode(TokenFormRequest $request)
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
/** @var User $user */
$user = auth()->user();
/** @var UserRepositoryInterface $repository */
@ -485,6 +506,12 @@ class ProfileController extends Controller
*/
public function postDeleteAccount(UserRepositoryInterface $repository, DeleteAccountFormRequest $request)
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
if (!Hash::check($request->get('password'), auth()->user()->password)) {
session()->flash('error', (string) trans('firefly.invalid_password'));
@ -506,8 +533,14 @@ class ProfileController extends Controller
*
* @return RedirectResponse|Redirector
*/
public function regenerate()
public function regenerate(Request $request)
{
if ($this->externalIdentity) {
$request->session()->flash('error', trans('firefly.external_user_mgt_disabled'));
return redirect(route('profile.index'));
}
/** @var User $user */
$user = auth()->user();
$token = $user->generateAccessToken();
@ -530,11 +563,8 @@ class ProfileController extends Controller
*/
public function undoEmailChange(UserRepositoryInterface $repository, string $token, string $hash)
{
$loginProvider = config('firefly.login_provider');
if ('eloquent' !== $loginProvider) {
// @codeCoverageIgnoreStart
throw new FireflyException('Cannot confirm email change when authentication provider is not local.');
// @codeCoverageIgnoreEnd
if ($this->externalIdentity) {
throw new FireflyException(trans('firefly.external_user_mgt_disabled'));
}
// find preference with this token value.

View File

@ -25,6 +25,7 @@ namespace FireflyIII\Http\Controllers\Recurring;
use Carbon\Carbon;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\RecurrenceFormRequest;
use FireflyIII\Models\RecurrenceRepetition;
@ -47,6 +48,8 @@ class CreateController extends Controller
/** @var RecurringRepositoryInterface Recurring repository */
private $recurring;
private AttachmentHelperInterface $attachments;
/**
* CreateController constructor.
*
@ -63,8 +66,9 @@ class CreateController extends Controller
app('view')->share('title', (string) trans('firefly.recurrences'));
app('view')->share('subTitle', (string) trans('firefly.create_new_recurrence'));
$this->recurring = app(RecurringRepositoryInterface::class);
$this->budgets = app(BudgetRepositoryInterface::class);
$this->recurring = app(RecurringRepositoryInterface::class);
$this->budgets = app(BudgetRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
return $next($request);
}
@ -140,6 +144,21 @@ class CreateController extends Controller
$request->session()->flash('success', (string) trans('firefly.stored_new_recurrence', ['title' => $recurrence->title]));
app('preferences')->mark();
// store attachment(s):
/** @var array $files */
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($recurrence, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info', (string) trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
$redirect = redirect($this->getPreviousUri('recurring.create.uri'));
if (1 === (int) $request->get('create_another')) {
// set value so create routine will not overwrite URL:

View File

@ -25,6 +25,7 @@ namespace FireflyIII\Http\Controllers\Recurring;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\RecurrenceFormRequest;
use FireflyIII\Models\Recurrence;
@ -48,7 +49,8 @@ class EditController extends Controller
/** @var BudgetRepositoryInterface The budget repository */
private $budgets;
/** @var RecurringRepositoryInterface Recurring repository */
private $recurring;
private $recurring;
private AttachmentHelperInterface $attachments;
/**
* EditController constructor.
@ -66,9 +68,9 @@ class EditController extends Controller
app('view')->share('title', (string) trans('firefly.recurrences'));
app('view')->share('subTitle', (string) trans('firefly.recurrences'));
$this->recurring = app(RecurringRepositoryInterface::class);
$this->budgets = app(BudgetRepositoryInterface::class);
$this->recurring = app(RecurringRepositoryInterface::class);
$this->budgets = app(BudgetRepositoryInterface::class);
$this->attachments = app(AttachmentHelperInterface::class);
return $next($request);
}
);
@ -159,6 +161,21 @@ class EditController extends Controller
$this->recurring->update($recurrence, $data);
$request->session()->flash('success', (string) trans('firefly.updated_recurrence', ['title' => $recurrence->title]));
// store new attachment(s):
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
if (null !== $files && !auth()->user()->hasRole('demo')) {
$this->attachments->saveAttachmentsForModel($recurrence, $files);
}
if (null !== $files && auth()->user()->hasRole('demo')) {
session()->flash('info', (string) trans('firefly.no_att_demo_user'));
}
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
app('preferences')->mark();
$redirect = redirect($this->getPreviousUri('recurrences.edit.uri'));
if (1 === (int) $request->get('return_to_edit')) {

View File

@ -111,6 +111,8 @@ class IndexController extends Controller
$array['first_date'] = new Carbon($array['first_date']);
$array['repeat_until'] = null === $array['repeat_until'] ? null : new Carbon($array['repeat_until']);
$array['latest_date'] = null === $array['latest_date'] ? null : new Carbon($array['latest_date']);
// lazy but OK
$array['attachments'] = $recurrence->attachments()->count();
// make carbon objects out of occurrences
foreach ($array['repetitions'] as $repIndex => $repetition) {

View File

@ -263,7 +263,7 @@ class ReportController extends Controller
public function index(AccountRepositoryInterface $repository)
{
/** @var Carbon $start */
$start = clone session('first');
$start = clone session('first', new Carbon);
$months = $this->helper->listOfMonths($start);
$customFiscalYear = app('preferences')->get('customFiscalYear', 0)->data;
$accounts = $repository->getAccountsByType(

View File

@ -128,6 +128,10 @@ class SelectController extends Controller
*/
public function selectTransactions(Rule $rule)
{
if(false===$rule->active) {
session()->flash('warning',trans('firefly.cannot_fire_inactive_rules'));
return redirect(route('rules.index'));
}
// does the user have shared accounts?
$first = session('first', Carbon::now()->subYear())->format('Y-m-d');
$today = Carbon::now()->format('Y-m-d');

View File

@ -0,0 +1,75 @@
<?php
/**
* ObjectGroupFormRequest.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Http\Requests;
use FireflyIII\Models\ObjectGroup;
/**
* Class ObjectGroupFormRequest.
*/
class ObjectGroupFormRequest extends Request
{
/**
* Verify the request.
*
* @return bool
*/
public function authorize(): bool
{
// Only allow logged in users
return auth()->check();
}
/**
* Returns the data required by the controller.
*
* @return array
*/
public function getObjectGroupData(): array
{
return [
'title' => $this->string('title'),
];
}
/**
* Rules for this request.
*
* @return array
*/
public function rules(): array
{
/** @var ObjectGroup $piggy */
$objectGroup = $this->route()->parameter('objectGroup');
$titleRule = 'required|between:1,255|uniqueObjectGroup';
if (null !== $objectGroup) {
$titleRule = sprintf('required|between:1,255|uniqueObjectGroup:%d', $objectGroup->id);
}
return [
'title' => $titleRule,
];
}
}

View File

@ -54,6 +54,7 @@ class PiggyBankFormRequest extends Request
'targetamount' => $this->string('targetamount'),
'targetdate' => $this->date('targetdate'),
'notes' => $this->nlString('notes'),
'object_group' => $this->string('object_group'),
];
}

View File

@ -1,234 +0,0 @@
<?php
/**
* Amount.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Converter;
use Log;
/**
* Class Amount.
*
* @deprecated
* @codeCoverageIgnore
*/
class Amount implements ConverterInterface
{
/**
* Some people, when confronted with a problem, think "I know, I'll use regular expressions." Now they have two problems.
* - Jamie Zawinski.
*
* @param $value
*
* @return string
*/
public function convert($value): string
{
if (null === $value) {
return '0';
}
Log::debug(sprintf('Start with amount "%s"', $value));
$original = $value;
$value = $this->stripAmount((string) $value);
$decimal = null;
if ($this->decimalIsDot($value)) {
$decimal = '.';
Log::debug(sprintf('Decimal character in "%s" seems to be a dot.', $value));
}
if ($this->decimalIsComma($value)) {
$decimal = ',';
Log::debug(sprintf('Decimal character in "%s" seems to be a comma.', $value));
}
// decimal character is null? find out if "0.1" or ".1" or "0,1" or ",1"
if ($this->alternativeDecimalSign($value)) {
$decimal = $this->getAlternativeDecimalSign($value);
}
// decimal character still null? Search from the left for '.',',' or ' '.
if (null === $decimal) {
$decimal = $this->findFromLeft($value);
}
// if decimal is dot, replace all comma's and spaces with nothing
if (null !== $decimal) {
$value = $this->replaceDecimal($decimal, $value);
Log::debug(sprintf('Converted amount from "%s" to "%s".', $original, $value));
}
if (null === $decimal) {
// replace all:
$search = ['.', ' ', ','];
$value = str_replace($search, '', $value);
Log::debug(sprintf('No decimal character found. Converted amount from "%s" to "%s".', $original, $value));
}
if (strpos($value, '.') === 0) {
$value = '0' . $value;
}
if (is_numeric($value)) {
Log::debug(sprintf('Final NUMERIC value is: "%s"', $value));
return $value;
}
// @codeCoverageIgnoreStart
Log::debug(sprintf('Final value is: "%s"', $value));
$formatted = sprintf('%01.12f', $value);
Log::debug(sprintf('Is formatted to : "%s"', $formatted));
return $formatted;
// @codeCoverageIgnoreEnd
}
/**
* Check if the value has a dot or comma on an alternative place,
* catching strings like ",1" or ".5".
*
* @param string $value
*
* @return bool
*/
private function alternativeDecimalSign(string $value): bool
{
$length = strlen($value);
$altPosition = $length - 2;
return $length > 1 && ('.' === $value[$altPosition] || ',' === $value[$altPosition]);
}
/**
* Helper function to see if the decimal separator is a comma.
*
* @param string $value
*
* @return bool
*/
private function decimalIsComma(string $value): bool
{
$length = strlen($value);
$decimalPosition = $length - 3;
return $length > 2 && ',' === $value[$decimalPosition];
}
/**
* Helper function to see if the decimal separator is a dot.
*
* @param string $value
*
* @return bool
*/
private function decimalIsDot(string $value): bool
{
$length = strlen($value);
$decimalPosition = $length - 3;
return ($length > 2 && '.' === $value[$decimalPosition]) || ($length > 2 && strpos($value, '.') > $decimalPosition);
}
/**
* Search from the left for decimal sign.
*
* @param string $value
*
* @return string
*/
private function findFromLeft(string $value): ?string
{
$decimal = null;
Log::debug('Decimal is still NULL, probably number with >2 decimals. Search for a dot.');
$res = strrpos($value, '.');
if (!(false === $res)) {
// blandly assume this is the one.
Log::debug(sprintf('Searched from the left for "." in amount "%s", assume this is the decimal sign.', $value));
$decimal = '.';
}
return $decimal;
}
/**
* Returns the alternative decimal point used, such as a dot or a comma,
* from strings like ",1" or "0.5".
*
* @param string $value
*
* @return string
*/
private function getAlternativeDecimalSign(string $value): string
{
$length = strlen($value);
$altPosition = $length - 2;
return $value[$altPosition];
}
/**
* Replaces other characters like thousand separators with nothing to make the decimal separator the only special
* character in the string.
*
* @param string $decimal
* @param string $value
*
* @return string
*/
private function replaceDecimal(string $decimal, string $value): string
{
$search = [',', ' ']; // default when decimal sign is a dot.
if (',' === $decimal) {
$search = ['.', ' '];
}
$value = str_replace($search, '', $value);
/** @noinspection CascadeStringReplacementInspection */
$value = str_replace(',', '.', $value);
return $value;
}
/**
* Strip amount from weird characters.
*
* @param string $value
*
* @return string
*/
private function stripAmount(string $value): string
{
if (0 === strpos($value, '--')) {
$value = substr($value, 2);
}
// have to strip the € because apparantly the Postbank (DE) thinks "1.000,00 €" is a normal way to format a number.
$value = trim((string) str_replace(['€'], '', $value));
$str = preg_replace('/[^\-\(\)\.\,0-9 ]/', '', $value);
$len = strlen($str);
if ('(' === $str[0] && ')' === $str[$len - 1]) {
$str = '-' . substr($str, 1, $len - 2);
}
Log::debug(sprintf('Stripped "%s" away to "%s"', $value, $str));
return $str;
}
}

View File

@ -1,49 +0,0 @@
<?php
/**
* AmountCredit.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Converter;
/**
* Class AmountCredit
*
* @deprecated
* @codeCoverageIgnore
*/
class AmountCredit implements ConverterInterface
{
/**
* Convert an amount, always return positive.
*
* @param $value
*
* @return string
*/
public function convert($value): string
{
/** @var ConverterInterface $converter */
$converter = app(Amount::class);
$result = $converter->convert($value);
$result = app('steam')->positive($result);
return $result;
}
}

View File

@ -1,50 +0,0 @@
<?php
/**
* AmountDebit.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Converter;
/**
* Class AmountDebit
*
* @deprecated
* @codeCoverageIgnore
*/
class AmountDebit implements ConverterInterface
{
/**
* Convert amount, always return positive.
*
* @param $value
*
* @return string
*/
public function convert($value): string
{
/** @var ConverterInterface $converter */
$converter = app(Amount::class);
$result = $converter->convert($value);
$result = app('steam')->positive($result);
$result = bcmul($result, '-1');
return $result;
}
}

View File

@ -1,49 +0,0 @@
<?php
/**
* AmountNegated.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Converter;
/**
* Class AmountNegated
*
* @deprecated
* @codeCoverageIgnore
*/
class AmountNegated implements ConverterInterface
{
/**
* Negate amount.
*
* @param $value
*
* @return string
*/
public function convert($value): string
{
/** @var ConverterInterface $converter */
$converter = app(Amount::class);
$result = $converter->convert($value);
$result = bcmul($result, '-1');
return $result;
}
}

View File

@ -1,64 +0,0 @@
<?php
/**
* BankDebitCredit.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Converter;
use Log;
/**
*
* Class BankDebitCredit
*
* @deprecated
* @codeCoverageIgnore
*/
class BankDebitCredit implements ConverterInterface
{
/**
* Convert a value.
*
* @param $value
*
* @return int
*/
public function convert($value): int
{
Log::debug('Going to convert ', ['value' => $value]);
$negative = [
'D', // Old style Rabobank (NL). Short for "Debit"
'A', // New style Rabobank (NL). Short for "Af"
'DR', // https://old.reddit.com/r/FireflyIII/comments/bn2edf/generic_debitcredit_indicator/
'Af', // ING (NL).
'Debet', // Triodos (NL)
'S', // "Soll", German term for debit
'Debit', // Community America (US)
];
if (in_array(trim($value), $negative, true)) {
return -1;
}
return 1;
}
}

View File

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

View File

@ -1,136 +0,0 @@
<?php
/**
* BunqJobConfiguration.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\JobConfiguration\Bunq\BunqJobConfigurationInterface;
use FireflyIII\Support\Import\JobConfiguration\Bunq\ChooseAccountsHandler;
use FireflyIII\Support\Import\JobConfiguration\Bunq\NewBunqJobHandler;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class BunqJobConfiguration
*
* @deprecated
* @codeCoverageIgnore
*/
class BunqJobConfiguration implements JobConfigurationInterface
{
/** @var BunqJobConfigurationInterface Bunq job interface */
private $handler;
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function configurationComplete(): bool
{
return $this->handler->configurationComplete();
}
/**
* Store any data from the $data array into the job. Anything in the message bag will be flashed
* as an error to the user, regardless of its content.
*
* @param array $data
*
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
return $this->handler->configureJob($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @return array
*/
public function getNextData(): array
{
return $this->handler->getNextData();
}
/**
* Returns the view of the next step in the job configuration.
*
* @return string
*/
public function getNextView(): string
{
return $this->handler->getNextView();
}
/**
* Set import job.
*
* @param ImportJob $importJob
*
* @throws FireflyException
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
$this->handler = $this->getHandler();
}
/**
* Get correct handler.
*
* @throws FireflyException
* @return BunqJobConfigurationInterface
*/
private function getHandler(): BunqJobConfigurationInterface
{
Log::debug(sprintf('Now in BunqJobConfiguration::getHandler() with stage "%s"', $this->importJob->stage));
$handler = null;
switch ($this->importJob->stage) {
case 'new':
$handler = app(NewBunqJobHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'choose-accounts':
/** @var ChooseAccountsHandler $handler */
$handler = app(ChooseAccountsHandler::class);
$handler->setImportJob($this->importJob);
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(sprintf('Firefly III cannot create a configuration handler for stage "%s"', $this->importJob->stage));
// @codeCoverageIgnoreEnd
}
return $handler;
}
}

View File

@ -1,169 +0,0 @@
<?php
/**
* FakeJobConfiguration.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use Illuminate\Support\MessageBag;
/**
* Class FakeJobConfiguration
*
* @deprecated
* @codeCoverageIgnore
*/
class FakeJobConfiguration implements JobConfigurationInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* Returns true when the initial configuration for this job is complete.
* configuration array of job must have two values:
* 'artist' must be 'david bowie', case insensitive
* 'song' must be 'golden years', case insensitive.
* if stage is not "new", then album must be 'station to station'
*
* @return bool
*
*/
public function configurationComplete(): bool
{
$config = $this->importJob->configuration;
if ('new' === $this->importJob->stage) {
return
isset($config['artist'], $config['song'], $config['apply-rules'])
&& 'david bowie' === strtolower($config['artist'])
&& 'golden years' === strtolower($config['song']);
}
return isset($config['album']) && 'station to station' === strtolower($config['album']);
}
/**
* Store any data from the $data array into the job.
*
* @param array $data
*
* @return MessageBag
*
*/
public function configureJob(array $data): MessageBag
{
$artist = strtolower($data['artist'] ?? '');
$song = strtolower($data['song'] ?? '');
$album = strtolower($data['album'] ?? '');
$applyRules = isset($data['apply_rules']) ? 1 === (int) $data['apply_rules'] : null;
$configuration = $this->importJob->configuration;
if ('david bowie' === $artist) {
// store artist
$configuration['artist'] = $artist;
}
if ('golden years' === $song) {
// store song
$configuration['song'] = $song;
}
if ('station to station' === $album) {
// store album
$configuration['album'] = $album;
}
if (null !== $applyRules) {
$configuration['apply-rules'] = $applyRules;
}
$this->repository->setConfiguration($this->importJob, $configuration);
$messages = new MessageBag();
if (3 !== count($configuration)) {
$messages->add('some_key', 'Ignore this error: ' . count($configuration));
}
return $messages;
}
/**
* Return the data required for the next step in the job configuration.
*
* @codeCoverageIgnore
* @return array
*/
public function getNextData(): array
{
return [
'rulesOptions' => [
1 => (string) trans('firefly.yes'),
0 => (string) trans('firefly.no'),
],
];
}
/**
* Returns the view of the next step in the job configuration.
*
* @return string
*
*/
public function getNextView(): string
{
// first configure artist:
$config = $this->importJob->configuration;
$artist = $config['artist'] ?? '';
$song = $config['song'] ?? '';
$album = $config['album'] ?? '';
$applyRules = $config['apply-rules'] ?? null;
if (null === $applyRules) {
return 'import.fake.apply-rules';
}
if ('david bowie' !== strtolower($artist)) {
return 'import.fake.enter-artist';
}
if ('golden years' !== strtolower($song)) {
return 'import.fake.enter-song';
}
if ('new' !== $this->importJob->stage && 'station to station' !== strtolower($album)) {
return 'import.fake.enter-album';
}
return 'impossible-view'; // @codeCoverageIgnore
}
/**
* Set import job.
*
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
}

View File

@ -1,161 +0,0 @@
<?php
/**
* FileJobConfiguration.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\JobConfiguration\File\ConfigureMappingHandler;
use FireflyIII\Support\Import\JobConfiguration\File\ConfigureRolesHandler;
use FireflyIII\Support\Import\JobConfiguration\File\ConfigureUploadHandler;
use FireflyIII\Support\Import\JobConfiguration\File\FileConfigurationInterface;
use FireflyIII\Support\Import\JobConfiguration\File\NewFileJobHandler;
use Illuminate\Support\MessageBag;
/**
* Class FileJobConfiguration
*
* @deprecated
* @codeCoverageIgnore
*/
class FileJobConfiguration implements JobConfigurationInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function configurationComplete(): bool
{
return 'ready_to_run' === $this->importJob->stage;
}
/**
* Store any data from the $data array into the job. Anything in the message bag will be flashed
* as an error to the user, regardless of its content.
*
* @param array $data
*
* @throws FireflyException
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
$configurator = $this->getConfigurationObject();
$configurator->setImportJob($this->importJob);
return $configurator->configureJob($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @throws FireflyException
* @return array
*/
public function getNextData(): array
{
$configurator = $this->getConfigurationObject();
$configurator->setImportJob($this->importJob);
return $configurator->getNextData();
}
/**
* Returns the view of the next step in the job configuration.
*
* @throws FireflyException
* @return string
*
*/
public function getNextView(): string
{
switch ($this->importJob->stage) {
case 'new':
return 'import.file.new';
case 'configure-upload':
return 'import.file.configure-upload';
case 'roles':
return 'import.file.roles';
case 'map':
return 'import.file.map';
default:
// @codeCoverageIgnoreStart
throw new FireflyException(
sprintf('FileJobConfiguration::getNextView() cannot handle stage "%s"', $this->importJob->stage)
);
// @codeCoverageIgnoreEnd
}
}
/**
* Set import job.
*
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
/**
* Get the configuration handler for this specific stage.
*
* @throws FireflyException
*
* @return FileConfigurationInterface
*/
private function getConfigurationObject(): FileConfigurationInterface
{
$class = 'DoNotExist';
switch ($this->importJob->stage) {
case 'new': // has nothing, no file upload or anything.
$class = NewFileJobHandler::class;
break;
case 'configure-upload':
$class = ConfigureUploadHandler::class;
break;
case 'roles':
$class = ConfigureRolesHandler::class;
break;
case 'map':
$class = ConfigureMappingHandler::class;
break;
}
if (!class_exists($class)) {
throw new FireflyException(sprintf('Class %s does not exist in getConfigurationClass().', $class)); // @codeCoverageIgnore
}
return app($class);
}
}

View File

@ -1,38 +0,0 @@
<?php
/**
* FinTSConfigurationSteps.php
* Copyright (c) 2019 https://github.com/bnw
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
/**
*
* Class FinTSConfigurationSteps
*
* @deprecated
* @codeCoverageIgnore
*/
abstract class FinTSConfigurationSteps
{
public const NEW = 'new';
public const CHOOSE_ACCOUNT = 'choose_account';
public const GO_FOR_IMPORT = 'go-for-import';
}

View File

@ -1,137 +0,0 @@
<?php
/**
* FinTSJobConfiguration.php
* Copyright (c) 2019 https://github.com/bnw
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Support\Import\JobConfiguration\FinTS\ChooseAccountHandler;
use FireflyIII\Support\Import\JobConfiguration\FinTS\FinTSConfigurationInterface;
use FireflyIII\Support\Import\JobConfiguration\FinTS\NewFinTSJobHandler;
use Illuminate\Support\MessageBag;
/**
*
* Class FinTSJobConfiguration
*
* @deprecated
* @codeCoverageIgnore
*/
class FinTSJobConfiguration implements JobConfigurationInterface
{
/** @var ImportJob */
private $importJob;
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function configurationComplete(): bool
{
return $this->importJob->stage === FinTSConfigurationSteps::GO_FOR_IMPORT;
}
/**
* Store any data from the $data array into the job. Anything in the message bag will be flashed
* as an error to the user, regardless of its content.
*
* @param array $data
*
* @throws FireflyException
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
return $this->getConfigurationObject()->configureJob($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @throws FireflyException
* @return array
*/
public function getNextData(): array
{
return $this->getConfigurationObject()->getNextData();
}
/**
* Returns the view of the next step in the job configuration.
*
* @throws FireflyException
* @return string
*/
public function getNextView(): string
{
switch ($this->importJob->stage) {
case FinTSConfigurationSteps::NEW:
case FinTSConfigurationSteps::CHOOSE_ACCOUNT:
return 'import.fints.' . $this->importJob->stage;
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(
sprintf('FinTSJobConfiguration::getNextView() cannot handle stage "%s"', $this->importJob->stage)
);
// @codeCoverageIgnoreEnd
}
}
/**
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
}
/**
* Get the configuration handler for this specific stage.
*
* @throws FireflyException
* @return FinTSConfigurationInterface
*/
private function getConfigurationObject(): FinTSConfigurationInterface
{
$class = 'DoNotExist';
switch ($this->importJob->stage) {
case FinTSConfigurationSteps::NEW:
$class = NewFinTSJobHandler::class;
break;
case FinTSConfigurationSteps::CHOOSE_ACCOUNT:
$class = ChooseAccountHandler::class;
break;
}
if (!class_exists($class)) {
throw new FireflyException(sprintf('Class %s does not exist in getConfigurationClass().', $class)); // @codeCoverageIgnore
}
$configurator = app($class);
$configurator->setImportJob($this->importJob);
return $configurator;
}
}

View File

@ -1,73 +0,0 @@
<?php
/**
* JobConfigurationInterface.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Models\ImportJob;
use Illuminate\Support\MessageBag;
/**
* Interface JobConfigurationInterface.
*
* @deprecated
* @codeCoverageIgnore
*/
interface JobConfigurationInterface
{
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function configurationComplete(): bool;
/**
* Store any data from the $data array into the job. Anything in the message bag will be flashed
* as an error to the user, regardless of its content.
*
* @param array $data
*
* @return MessageBag
*/
public function configureJob(array $data): MessageBag;
/**
* Return the data required for the next step in the job configuration.
*
* @return array
*/
public function getNextData(): array;
/**
* Returns the view of the next step in the job configuration.
*
* @return string
*/
public function getNextView(): string;
/**
* Set import job.
*
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void;
}

View File

@ -1,156 +0,0 @@
<?php
/**
* SpectreJobConfiguration.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\JobConfiguration\Spectre\AuthenticatedHandler;
use FireflyIII\Support\Import\JobConfiguration\Spectre\ChooseAccountsHandler;
use FireflyIII\Support\Import\JobConfiguration\Spectre\ChooseLoginHandler;
use FireflyIII\Support\Import\JobConfiguration\Spectre\DoAuthenticateHandler;
use FireflyIII\Support\Import\JobConfiguration\Spectre\NewSpectreJobHandler;
use FireflyIII\Support\Import\JobConfiguration\Spectre\SpectreJobConfigurationInterface;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class SpectreJobConfiguration
*
* @deprecated
* @codeCoverageIgnore
*/
class SpectreJobConfiguration implements JobConfigurationInterface
{
/** @var SpectreJobConfigurationInterface The job handler. */
private $handler;
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function configurationComplete(): bool
{
return $this->handler->configurationComplete();
}
/**
* Store any data from the $data array into the job. Anything in the message bag will be flashed
* as an error to the user, regardless of its content.
*
* @param array $data
*
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
return $this->handler->configureJob($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @return array
*/
public function getNextData(): array
{
return $this->handler->getNextData();
}
/**
* Returns the view of the next step in the job configuration.
*
* @return string
*/
public function getNextView(): string
{
return $this->handler->getNextView();
}
/**
* Set the import job.
*
* @param ImportJob $importJob
*
* @throws FireflyException
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
$this->handler = $this->getHandler();
}
/**
* Get correct handler.
*
* @throws FireflyException
*
* @return SpectreJobConfigurationInterface
*/
private function getHandler(): SpectreJobConfigurationInterface
{
Log::debug(sprintf('Now in SpectreJobConfiguration::getHandler() with stage "%s"', $this->importJob->stage));
$handler = null;
switch ($this->importJob->stage) {
case 'new':
/** @var NewSpectreJobHandler $handler */
$handler = app(NewSpectreJobHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'do-authenticate':
/** @var DoAuthenticateHandler $handler */
$handler = app(DoAuthenticateHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'choose-login':
/** @var ChooseLoginHandler $handler */
$handler = app(ChooseLoginHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'authenticated':
/** @var AuthenticatedHandler $handler */
$handler = app(AuthenticatedHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'choose-accounts':
/** @var ChooseAccountsHandler $handler */
$handler = app(ChooseAccountsHandler::class);
$handler->setImportJob($this->importJob);
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(sprintf('Firefly III cannot create a configuration handler for stage "%s"', $this->importJob->stage));
// @codeCoverageIgnoreEnd
}
return $handler;
}
}

View File

@ -1,143 +0,0 @@
<?php
/**
* YnabJobConfiguration.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\JobConfiguration;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\JobConfiguration\Ynab\NewYnabJobHandler;
use FireflyIII\Support\Import\JobConfiguration\Ynab\SelectAccountsHandler;
use FireflyIII\Support\Import\JobConfiguration\Ynab\SelectBudgetHandler;
use FireflyIII\Support\Import\JobConfiguration\Ynab\YnabJobConfigurationInterface;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class YnabJobConfiguration
*
* @deprecated
* @codeCoverageIgnore
*/
class YnabJobConfiguration implements JobConfigurationInterface
{
/** @var YnabJobConfigurationInterface The job handler. */
private $handler;
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* Returns true when the initial configuration for this job is complete.
*
* @return bool
*/
public function configurationComplete(): bool
{
return $this->handler->configurationComplete();
}
/**
* Store any data from the $data array into the job. Anything in the message bag will be flashed
* as an error to the user, regardless of its content.
*
* @param array $data
*
* @return MessageBag
*/
public function configureJob(array $data): MessageBag
{
return $this->handler->configureJob($data);
}
/**
* Return the data required for the next step in the job configuration.
*
* @return array
*/
public function getNextData(): array
{
return $this->handler->getNextData();
}
/**
* Returns the view of the next step in the job configuration.
*
* @return string
*/
public function getNextView(): string
{
return $this->handler->getNextView();
}
/**
* Set import job.
*
* @param ImportJob $importJob
*
* @throws FireflyException
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
$this->handler = $this->getHandler();
}
/**
* Get correct handler.
*
* @throws FireflyException
*
* @return YnabJobConfigurationInterface
*/
private function getHandler(): YnabJobConfigurationInterface
{
Log::debug(sprintf('Now in YnabJobConfiguration::getHandler() with stage "%s"', $this->importJob->stage));
$handler = null;
switch ($this->importJob->stage) {
case 'new':
/** @var NewYnabJobHandler $handler */
$handler = app(NewYnabJobHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'select_budgets':
/** @var SelectBudgetHandler $handler */
$handler = app(SelectBudgetHandler::class);
$handler->setImportJob($this->importJob);
break;
case 'select_accounts':
$handler = app(SelectAccountsHandler::class);
$handler->setImportJob($this->importJob);
break;
default:
// @codeCoverageIgnoreStart
throw new FireflyException(sprintf('Firefly III cannot create a YNAB configuration handler for stage "%s"', $this->importJob->stage));
// @codeCoverageIgnoreEnd
}
return $handler;
}
}

View File

@ -1,85 +0,0 @@
<?php
/**
* AssetAccountIbans.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
/**
* Class AssetAccounts.
*
* @deprecated
* @codeCoverageIgnore
*/
class AssetAccountIbans implements MapperInterface
{
/**
* Get map of asset accounts.
*
* @return array
*/
public function getMap(): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$set = $accountRepository->getAccountsByType(
[AccountType::DEFAULT, AccountType::ASSET,
AccountType::LOAN, AccountType::DEBT,
AccountType::CREDITCARD, AccountType::MORTGAGE,
]
);
$topList = [];
$list = [];
/** @var Account $account */
foreach ($set as $account) {
$iban = $account->iban ?? '';
$accountId = (int) $account->id;
if ('' !== $iban) {
$name = $account->iban . ' (' . $account->name . ')';
// is a liability?
if (in_array($account->accountType->type, [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], true)) {
$name = $name . ' (' . strtolower(trans('import.import_liability_select')) . ')';
}
$topList[$accountId] = $name;
}
if ('' === $iban) {
$name = $account->name;
// is a liability?
if (in_array($account->accountType->type, [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], true)) {
$name = $name . ' (' . strtolower(trans('import.import_liability_select')) . ')';
}
$list[$accountId] = $name;
}
}
/** @noinspection AdditionOperationOnArraysInspection */
$list = $topList + $list;
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,72 +0,0 @@
<?php
/**
* AssetAccounts.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
/**
* Class AssetAccounts.
*
* @deprecated
* @codeCoverageIgnore
*/
class AssetAccounts implements MapperInterface
{
/**
* Get map of asset accounts.
*
* @return array
*/
public function getMap(): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$set = $accountRepository->getAccountsByType(
[AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE,]
);
$list = [];
/** @var Account $account */
foreach ($set as $account) {
$accountId = (int) $account->id;
$name = $account->name;
$iban = $account->iban ?? '';
if ('' !== $iban) {
$name .= ' (' . $iban . ')';
}
// is a liability?
if (in_array($account->accountType->type, [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], true)) {
$name = trans('import.import_liability_select') . ': ' . $name;
}
$list[$accountId] = $name;
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* Bills.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Bill;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
/**
* Class Bills.
*
* @deprecated
* @codeCoverageIgnore
*/
class Bills implements MapperInterface
{
/**
* Get map of bills.
*
* @return array
*/
public function getMap(): array
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$result = $repository->getBills();
$list = [];
/** @var Bill $bill */
foreach ($result as $bill) {
$billId = (int) $bill->id;
$list[$billId] = $bill->name;
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* Budgets.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Budget;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
/**
* Class Budgets.
*
* @deprecated
* @codeCoverageIgnore
*/
class Budgets implements MapperInterface
{
/**
* Get map of budgets.
*
* @return array
*/
public function getMap(): array
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$result = $repository->getActiveBudgets();
$list = [];
/** @var Budget $budget */
foreach ($result as $budget) {
$budgetId = (int) $budget->id;
$list[$budgetId] = $budget->name;
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* Categories.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
/**
* Class Categories.
*
* @deprecated
* @codeCoverageIgnore
*/
class Categories implements MapperInterface
{
/**
* Get map of categories.
*
* @return array
*/
public function getMap(): array
{
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
$result = $repository->getCategories();
$list = [];
/** @var Category $category */
foreach ($result as $category) {
$categoryId = (int) $category->id;
$list[$categoryId] = $category->name;
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,39 +0,0 @@
<?php
/**
* MapperInterface.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
/**
* Interface MapperInterface.
*
* @deprecated
* @codeCoverageIgnore
*/
interface MapperInterface
{
/**
* Get map of objects.
*
* @return array
*/
public function getMap(): array;
}

View File

@ -1,88 +0,0 @@
<?php
/**
* OpposingAccountIbans.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
/**
* Class OpposingAccounts.
*
* @deprecated
* @codeCoverageIgnore
*/
class OpposingAccountIbans implements MapperInterface
{
/**
* Get map of opposing accounts.
*
* @return array
*/
public function getMap(): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$set = $accountRepository->getAccountsByType(
[
AccountType::DEFAULT, AccountType::ASSET,
AccountType::EXPENSE, AccountType::BENEFICIARY,
AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT,
AccountType::CREDITCARD, AccountType::MORTGAGE,
]
);
$topList = [];
$list = [];
/** @var Account $account */
foreach ($set as $account) {
$iban = $account->iban ?? '';
$accountId = (int) $account->id;
if ('' !== $iban) {
$name = $account->iban . ' (' . $account->name . ')';
// is a liability?
if (in_array($account->accountType->type, [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], true)) {
$name = $name . ' (' . strtolower(trans('import.import_liability_select')) . ')';
}
$topList[$accountId] = $name;
}
if ('' === $iban) {
$name = $account->name;
// is a liability?
if (in_array($account->accountType->type, [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], true)) {
$name = $name . ' (' . strtolower(trans('import.import_liability_select')) . ')';
}
$list[$accountId] = $name;
}
}
/** @noinspection AdditionOperationOnArraysInspection */
$list = $topList + $list;
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,76 +0,0 @@
<?php
/**
* OpposingAccounts.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
/**
* Class OpposingAccounts.
*
* @deprecated
* @codeCoverageIgnore
*
*/
class OpposingAccounts implements MapperInterface
{
/**
* Get map of opposing accounts.
*
* @return array
*/
public function getMap(): array
{
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
$set = $accountRepository->getAccountsByType(
[
AccountType::DEFAULT, AccountType::ASSET,
AccountType::EXPENSE, AccountType::BENEFICIARY,
AccountType::REVENUE, AccountType::LOAN, AccountType::DEBT,
AccountType::CREDITCARD, AccountType::MORTGAGE,
]
);
$list = [];
/** @var Account $account */
foreach ($set as $account) {
$accountId = (int) $account->id;
$name = $account->name;
$iban = $account->iban ?? '';
if ('' !== $iban) {
$name .= ' (' . $iban . ')';
}
// is a liability?
if (in_array($account->accountType->type, [AccountType::LOAN, AccountType::DEBT, AccountType::CREDITCARD, AccountType::MORTGAGE], true)) {
$name = trans('import.import_liability_select') . ': ' . $name;
}
$list[$accountId] = $name;
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* Tags.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Models\Tag;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
/**
* Class Tags.
*
* @deprecated
* @codeCoverageIgnore
*/
class Tags implements MapperInterface
{
/**
* Get map of tags.
*
* @return array
*/
public function getMap(): array
{
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$result = $repository->get();
$list = [];
/** @var Tag $tag */
foreach ($result as $tag) {
$tagId = (int) $tag->id;
$list[$tagId] = $tag->tag;
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

@ -1,56 +0,0 @@
<?php
/**
* TransactionCurrencies.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Mapper;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
/**
* Class TransactionCurrencies.
*
* @deprecated
* @codeCoverageIgnore
*/
class TransactionCurrencies implements MapperInterface
{
/**
* Get map of currencies.
*
* @return array
*/
public function getMap(): array
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$currencies = $repository->get();
$list = [];
foreach ($currencies as $currency) {
$currencyId = (int) $currency->id;
$list[$currencyId] = $currency->name . ' (' . $currency->code . ')';
}
asort($list);
$list = [0 => (string) trans('import.map_do_not_map')] + $list;
return $list;
}
}

View File

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

View File

@ -1,48 +0,0 @@
<?php
/**
* TagsComma.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\MapperPreProcess;
/**
* Class TagsComma.
*
* @deprecated
* @codeCoverageIgnore
*/
class TagsComma implements PreProcessorInterface
{
/**
* Explode and filter list of comma separated tags.
*
* @param string $value
*
* @return array
*/
public function run(string $value): array
{
$set = explode(',', $value);
$set = array_map('trim', $set);
$set = array_filter($set, '\strlen');
return array_values($set);
}
}

View File

@ -1,48 +0,0 @@
<?php
/**
* TagsSpace.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\MapperPreProcess;
/**
* Class TagsSpace.
*
* @deprecated
* @codeCoverageIgnore
*/
class TagsSpace implements PreProcessorInterface
{
/**
* Explode and filter list of space separated tags.
*
* @param string $value
*
* @return array
*/
public function run(string $value): array
{
$set = explode(' ', $value);
$set = array_map('trim', $set);
$set = array_filter($set, '\strlen');
return array_values($set);
}
}

View File

@ -1,236 +0,0 @@
<?php
/**
* BunqPrerequisites.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Prerequisites;
use bunq\Util\BunqEnumApiEnvironmentType;
use Exception;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Services\Bunq\ApiContext;
use FireflyIII\Services\IP\IPRetrievalInterface;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Log;
/**
* This class contains all the routines necessary to connect to Bunq.
*
* @deprecated
* @codeCoverageIgnore
*/
class BunqPrerequisites implements PrerequisitesInterface
{
/** @var User The current user */
private $user;
/**
* BunqPrerequisites constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* Returns view name that allows user to fill in prerequisites.
*
* @codeCoverageIgnore
*
* @return string
*/
public function getView(): string
{
return 'import.bunq.prerequisites';
}
/**
* Returns any values required for the prerequisites-view.
*
* @return array
*/
public function getViewParameters(): array
{
Log::debug('Now in BunqPrerequisites::getViewParameters()');
$key = '';
$externalIP = '';
if ($this->hasApiKey()) {
$key = app('preferences')->getForUser($this->user, 'bunq_api_key', null)->data;
}
if ($this->hasExternalIP()) {
$externalIP = app('preferences')->getForUser($this->user, 'bunq_external_ip', null)->data;
}
if (!$this->hasExternalIP()) {
/** @var IPRetrievalInterface $service */
$service = app(IPRetrievalInterface::class);
$externalIP = (string) $service->getIP();
}
return ['api_key' => $key, 'external_ip' => $externalIP];
}
/**
* Indicate if all prerequisites have been met.
*
* @return bool
*/
public function isComplete(): bool
{
return $this->hasApiKey() && $this->hasExternalIP() && $this->hasApiContext();
}
/**
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
*
* @param User $user
*
* @codeCoverageIgnore
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* This method responds to the user's submission of an API key. Should do nothing but store the value.
*
* Errors must be returned in the message bag under the field name they are requested by.
*
* @param array $data
*
* @return MessageBag
*
*/
public function storePrerequisites(array $data): MessageBag
{
$apiKey = $data['api_key'] ?? '';
$externalIP = $data['external_ip'] ?? '';
Log::debug('Storing bunq API key');
app('preferences')->setForUser($this->user, 'bunq_api_key', $apiKey);
app('preferences')->setForUser($this->user, 'bunq_external_ip', $externalIP);
$environment = $this->getBunqEnvironment();
$deviceDescription = 'Firefly III v' . config('firefly.version');
$permittedIps = [$externalIP];
Log::debug(sprintf('Environment for bunq is %s', $environment->getChoiceString()));
try {
/** @var ApiContext $object */
$object = app(ApiContext::class);
$apiContext = $object->create($environment, $apiKey, $deviceDescription, $permittedIps);
} catch (FireflyException $e) {
$messages = new MessageBag();
$messages->add('bunq_error', $e->getMessage());
return $messages;
}
// store context in JSON:
try {
$json = $apiContext->toJson();
// @codeCoverageIgnoreStart
} catch (Exception $e) {
$messages = new MessageBag();
$messages->add('bunq_error', $e->getMessage());
return $messages;
}
// @codeCoverageIgnoreEnd
// and store for user:
app('preferences')->setForUser($this->user, 'bunq_api_context', $json);
return new MessageBag;
}
/**
* Get correct bunq environment.
*
* @return BunqEnumApiEnvironmentType
* @codeCoverageIgnore
*/
private function getBunqEnvironment(): BunqEnumApiEnvironmentType
{
$env = config('firefly.bunq_use_sandbox');
if (null === $env) {
return BunqEnumApiEnvironmentType::PRODUCTION();
}
if (false === $env) {
return BunqEnumApiEnvironmentType::PRODUCTION();
}
return BunqEnumApiEnvironmentType::SANDBOX();
}
/**
* Check if we have API context.
*
* @return bool
*/
private function hasApiContext(): bool
{
$apiContext = app('preferences')->getForUser($this->user, 'bunq_api_context', null);
if (null === $apiContext) {
return false;
}
if ('' === (string) $apiContext->data) {
return false;
}
return true;
}
/**
* Check if we have the API key.
*
* @return bool
*/
private function hasApiKey(): bool
{
$apiKey = app('preferences')->getForUser($this->user, 'bunq_api_key', null);
if (null === $apiKey) {
return false;
}
if ('' === (string) $apiKey->data) {
return false;
}
return true;
}
/**
* Checks if we have an external IP.
*
* @return bool
*/
private function hasExternalIP(): bool
{
$externalIP = app('preferences')->getForUser($this->user, 'bunq_external_ip', null);
if (null === $externalIP) {
return false;
}
if ('' === (string) $externalIP->data) {
return false;
}
return true;
}
}

View File

@ -1,146 +0,0 @@
<?php
/**
* FakePrerequisites.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Prerequisites;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Log;
use function request;
/**
* This class contains all the routines necessary for the fake import provider.
*
* Class FakePrerequisites
*
* @deprecated
* @codeCoverageIgnore
*/
class FakePrerequisites implements PrerequisitesInterface
{
/** @var User The current user */
private $user;
/**
* FakePrerequisites constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* Returns view name that allows user to fill in prerequisites. Currently asks for the API key.
*
* @codeCoverageIgnore
* @return string
*/
public function getView(): string
{
return 'import.fake.prerequisites';
}
/**
* Returns any values required for the prerequisites-view.
*
* @return array
*/
public function getViewParameters(): array
{
$apiKey = '';
if ($this->hasApiKey()) {
$apiKey = app('preferences')->getForUser($this->user, 'fake_api_key', null)->data;
}
$oldKey = (string) request()->old('api_key');
if ('' !== $oldKey) {
$apiKey = request()->old('api_key'); // @codeCoverageIgnore
}
return ['api_key' => $apiKey];
}
/**
* Indicate if all prerequisites have been met.
*
* @return bool
*/
public function isComplete(): bool
{
return $this->hasApiKey();
}
/**
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* Store fake prerequisites.
*
* @param array $data
*
* @return MessageBag
*/
public function storePrerequisites(array $data): MessageBag
{
$apiKey = $data['api_key'] ?? '';
$messageBag = new MessageBag();
if (32 !== strlen($apiKey)) {
$messageBag->add('api_key', 'API key must be 32 chars.');
return $messageBag;
}
app('preferences')->setForUser($this->user, 'fake_api_key', $apiKey);
return $messageBag;
}
/**
* Check if we have an API key.
*
* @return bool
*/
private function hasApiKey(): bool
{
$apiKey = app('preferences')->getForUser($this->user, 'fake_api_key', false);
if (null === $apiKey) {
return false;
}
if (null === $apiKey->data) {
return false;
}
if (32 === strlen((string) $apiKey->data)) {
return true;
}
return false;
}
}

View File

@ -1,102 +0,0 @@
<?php
/**
* FilePrerequisites.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Prerequisites;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Log;
/**
*
* This class contains all the routines necessary to import from a file. Hint: there are none.
*
* @deprecated
* @codeCoverageIgnore
*/
class FilePrerequisites implements PrerequisitesInterface
{
/**
* FilePrerequisites constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* Returns view name that allows user to fill in prerequisites.
*
* @return string
*/
public function getView(): string
{
return '';
}
/**
* Returns any values required for the prerequisites-view.
*
* @return array
*/
public function getViewParameters(): array
{
return [];
}
/**
* Indicate if all prerequisites have been met.
*
* @return bool
*/
public function isComplete(): bool
{
return true;
}
/**
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
*
* @param User $user
*/
public function setUser(User $user): void
{
}
/**
* This method responds to the user's submission of an API key. Should do nothing but store the value.
*
* Errors must be returned in the message bag under the field name they are requested by.
*
* @param array $data
*
* @return MessageBag
*/
public function storePrerequisites(array $data): MessageBag
{
return new MessageBag;
}
}

View File

@ -1,74 +0,0 @@
<?php
/**
* PrerequisitesInterface.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Prerequisites;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
/**
* Interface PrerequisitesInterface
*
* @deprecated
* @codeCoverageIgnore
*/
interface PrerequisitesInterface
{
/**
* Returns view name that allows user to fill in prerequisites.
*
* @return string
*/
public function getView(): string;
/**
* Returns any values required for the prerequisites-view.
*
* @return array
*/
public function getViewParameters(): array;
/**
* Indicate if all prerequisites have been met.
*
* @return bool
*/
public function isComplete(): bool;
/**
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
*
* @param User $user
*/
public function setUser(User $user): void;
/**
* This method responds to the user's submission of an API key. Should do nothing but store the value.
*
* Errors must be returned in the message bag under the field name they are requested by.
*
* @param array $data
*
* @return MessageBag
*/
public function storePrerequisites(array $data): MessageBag;
}

View File

@ -1,206 +0,0 @@
<?php
/**
* SpectrePrerequisites.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Prerequisites;
use FireflyIII\Models\Preference;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Log;
/**
* This class contains all the routines necessary to connect to Spectre.
*
* @deprecated
* @codeCoverageIgnore
*/
class SpectrePrerequisites implements PrerequisitesInterface
{
/** @var User The current user */
private $user;
/**
* SpectrePrerequisites constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* Returns view name that allows user to fill in prerequisites.
*
* @return string
*/
public function getView(): string
{
return 'import.spectre.prerequisites';
}
/**
* Returns any values required for the prerequisites-view.
*
* @return array
*/
public function getViewParameters(): array
{
/** @var Preference $appIdPreference */
$appIdPreference = app('preferences')->getForUser($this->user, 'spectre_app_id', null);
$appId = null === $appIdPreference ? '' : $appIdPreference->data;
/** @var Preference $secretPreference */
$secretPreference = app('preferences')->getForUser($this->user, 'spectre_secret', null);
$secret = null === $secretPreference ? '' : $secretPreference->data;
$publicKey = $this->getPublicKey();
return [
'app_id' => $appId,
'secret' => $secret,
'public_key' => $publicKey,
];
}
/**
* Indicate if all prerequisites have been met.
*
* @return bool
*/
public function isComplete(): bool
{
return $this->hasAppId() && $this->hasSecret();
}
/**
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* This method responds to the user's submission of an API key. Should do nothing but store the value.
*
* Errors must be returned in the message bag under the field name they are requested by.
*
* @param array $data
*
* @return MessageBag
*/
public function storePrerequisites(array $data): MessageBag
{
Log::debug('Storing Spectre API keys..');
app('preferences')->setForUser($this->user, 'spectre_app_id', $data['app_id'] ?? null);
app('preferences')->setForUser($this->user, 'spectre_secret', $data['secret'] ?? null);
Log::debug('Done!');
return new MessageBag;
}
/**
* This method creates a new public/private keypair for the user. This isn't really secure, since the key is generated on the fly with
* no regards for HSM's, smart cards or other things. It would require some low level programming to get this right. But the private key
* is stored encrypted in the database so it's something.
*/
private function createKeyPair(): void
{
Log::debug('Generate new Spectre key pair for user.');
$keyConfig = [
'digest_alg' => 'sha512',
'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA,
];
// Create the private and public key
$res = openssl_pkey_new($keyConfig);
// Extract the private key from $res to $privKey
$privKey = '';
openssl_pkey_export($res, $privKey);
// Extract the public key from $res to $pubKey
$pubKey = openssl_pkey_get_details($res);
app('preferences')->setForUser($this->user, 'spectre_private_key', $privKey);
app('preferences')->setForUser($this->user, 'spectre_public_key', $pubKey['key']);
Log::debug('Created key pair');
}
/**
* Get a public key from the users preferences.
*
* @return string
*/
private function getPublicKey(): string
{
Log::debug('get public key');
$preference = app('preferences')->getForUser($this->user, 'spectre_public_key', null);
if (null === $preference) {
Log::debug('public key is null');
// create key pair
$this->createKeyPair();
}
$preference = app('preferences')->getForUser($this->user, 'spectre_public_key', null);
Log::debug('Return public key for user');
return $preference->data;
}
/**
* Check if we have the App ID.
*
* @return bool
*/
private function hasAppId(): bool
{
$appId = app('preferences')->getForUser($this->user, 'spectre_app_id', null);
if (null === $appId) {
return false;
}
if ('' === (string) $appId->data) {
return false;
}
return true;
}
/**
* Check if we have the secret.
*
* @return bool
*/
private function hasSecret(): bool
{
$secret = app('preferences')->getForUser($this->user, 'spectre_secret', null);
if (null === $secret) {
return false;
}
if ('' === (string) $secret->data) {
return false;
}
return true;
}
}

View File

@ -1,159 +0,0 @@
<?php
/**
* YnabPrerequisites.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Prerequisites;
use FireflyIII\User;
use Illuminate\Support\MessageBag;
use Log;
/**
* Class YnabPrerequisites
*
* @deprecated
* @codeCoverageIgnore
*/
class YnabPrerequisites implements PrerequisitesInterface
{
/** @var User The current user */
private $user;
/**
* YnabPrerequisites constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* Returns view name that allows user to fill in prerequisites.
*
* @return string
*/
public function getView(): string
{
return 'import.ynab.prerequisites';
}
/**
* Returns any values required for the prerequisites-view.
*
* @return array
*/
public function getViewParameters(): array
{
Log::debug('Now in YnabPrerequisites::getViewParameters()');
$clientId = '';
$clientSecret = '';
if ($this->hasClientId()) {
$clientId = app('preferences')->getForUser($this->user, 'ynab_client_id', null)->data;
}
if ($this->hasClientSecret()) {
$clientSecret = app('preferences')->getForUser($this->user, 'ynab_client_secret', null)->data;
}
$callBackUri = route('import.callback.ynab');
$isHttps = 0 === strpos($callBackUri, 'https://');
return ['client_id' => $clientId, 'client_secret' => $clientSecret, 'callback_uri' => $callBackUri, 'is_https' => $isHttps];
}
/**
* Indicate if all prerequisites have been met.
*
* @return bool
*/
public function isComplete(): bool
{
return $this->hasClientId() && $this->hasClientSecret();
}
/**
* Set the user for this Prerequisites-routine. Class is expected to implement and save this.
*
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* This method responds to the user's submission of an API key. Should do nothing but store the value.
*
* Errors must be returned in the message bag under the field name they are requested by.
*
* @param array $data
*
* @return MessageBag
*/
public function storePrerequisites(array $data): MessageBag
{
$clientId = $data['client_id'] ?? '';
$clientSecret = $data['client_secret'] ?? '';
Log::debug('Storing YNAB client data');
app('preferences')->setForUser($this->user, 'ynab_client_id', $clientId);
app('preferences')->setForUser($this->user, 'ynab_client_secret', $clientSecret);
return new MessageBag;
}
/**
* Check if we have the client ID.
*
* @return bool
*/
private function hasClientId(): bool
{
$clientId = app('preferences')->getForUser($this->user, 'ynab_client_id', null);
if (null === $clientId) {
return false;
}
if ('' === (string) $clientId->data) {
return false;
}
return true;
}
/**
* Check if we have the client secret
*
* @return bool
*/
private function hasClientSecret(): bool
{
$clientSecret = app('preferences')->getForUser($this->user, 'ynab_client_secret', null);
if (null === $clientSecret) {
return false;
}
if ('' === (string) $clientSecret->data) {
return false;
}
return true;
}
}

View File

@ -1,118 +0,0 @@
<?php
/**
* BunqRoutine.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Routine\Bunq\StageImportDataHandler;
use FireflyIII\Support\Import\Routine\Bunq\StageNewHandler;
use Log;
/**
* Class BunqRoutine
*
* @deprecated
* @codeCoverageIgnore
*/
class BunqRoutine implements RoutineInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* At the end of each run(), the import routine must set the job to the expected status.
*
* The final status of the routine must be "provider_finished".
*
* @throws FireflyException
*/
public function run(): void
{
Log::info(sprintf('Now in BunqRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
$valid = ['ready_to_run']; // should be only ready_to_run
if (in_array($this->importJob->status, $valid, true)) {
switch ($this->importJob->stage) {
default:
throw new FireflyException(sprintf('BunqRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore
case 'new':
// list all of the users accounts.
$this->repository->setStatus($this->importJob, 'running');
/** @var StageNewHandler $handler */
$handler = app(StageNewHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
// make user choose accounts to import from.
$this->repository->setStage($this->importJob, 'choose-accounts');
$this->repository->setStatus($this->importJob, 'need_job_config');
return;
case 'go-for-import':
// list all of the users accounts.
$this->repository->setStatus($this->importJob, 'running');
/** @var StageImportDataHandler $handler */
$handler = app(StageImportDataHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$transactions = $handler->getTransactions();
// could be that more transactions will arrive in a second run.
if (true === $handler->isStillRunning()) {
Log::debug('Handler indicates that it is still working.');
$this->repository->setStatus($this->importJob, 'ready_to_run');
$this->repository->setStage($this->importJob, 'go-for-import');
}
$this->repository->appendTransactions($this->importJob, $transactions);
if (false === $handler->isStillRunning()) {
Log::info('Handler indicates that its done!');
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
}
return;
}
}
throw new FireflyException(sprintf('bunq import routine cannot handle status "%s"', $this->importJob->status)); // @codeCoverageIgnore
}
/**
* Set the import job.
*
* @param ImportJob $importJob
*
* @return void
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
}

View File

@ -1,111 +0,0 @@
<?php
/**
* FakeRoutine.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Routine\Fake\StageAhoyHandler;
use FireflyIII\Support\Import\Routine\Fake\StageFinalHandler;
use FireflyIII\Support\Import\Routine\Fake\StageNewHandler;
use Log;
/**
* Class FakeRoutine
*
* @deprecated
* @codeCoverageIgnore
*/
class FakeRoutine implements RoutineInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* Fake import routine has three stages:
*
* "new": will quietly log gibberish for 15 seconds, then switch to stage "ahoy".
* will also set status to "ready_to_run" so it will arrive here again.
* "ahoy": will log some nonsense and then drop job into status:"need_job_config" to force it back to the job config routine.
* "final": will do some logging, sleep for 10 seconds and then finish. Generates 5 random transactions.
*
* @throws FireflyException
*
* @return void
*/
public function run(): void
{
Log::debug(sprintf('Now in run() for fake routine with status: %s', $this->importJob->status));
if ('ready_to_run' !== $this->importJob->status) {
throw new FireflyException(sprintf('Fake job should have status "ready_to_run", not "%s"', $this->importJob->status)); // @codeCoverageIgnore
}
switch ($this->importJob->stage) {
default:
throw new FireflyException(sprintf('Fake routine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore
case 'new':
$this->repository->setStatus($this->importJob, 'running');
/** @var StageNewHandler $handler */
$handler = app(StageNewHandler::class);
$handler->run();
$this->repository->setStage($this->importJob, 'ahoy');
// set job finished this step:
$this->repository->setStatus($this->importJob, 'ready_to_run');
return;
case 'ahoy':
$this->repository->setStatus($this->importJob, 'running');
/** @var StageAhoyHandler $handler */
$handler = app(StageAhoyHandler::class);
$handler->run();
$this->repository->setStatus($this->importJob, 'need_job_config');
$this->repository->setStage($this->importJob, 'final');
break;
case 'final':
$this->repository->setStatus($this->importJob, 'running');
/** @var StageFinalHandler $handler */
$handler = app(StageFinalHandler::class);
$handler->setImportJob($this->importJob);
$transactions = $handler->getTransactions();
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
$this->repository->setTransactions($this->importJob, $transactions);
}
}
/**
* Set the import job.
*
* @param ImportJob $importJob
*
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
}

View File

@ -1,99 +0,0 @@
<?php
/**
* FileRoutine.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Routine\File\FileProcessorInterface;
use Log;
/**
* Class FileRoutine
*
* @deprecated
* @codeCoverageIgnore
*/
class FileRoutine implements RoutineInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* At the end of each run(), the import routine must set the job to the expected status.
*
* The final status of the routine must be "provider_finished".
*
* @throws FireflyException
*/
public function run(): void
{
Log::debug(sprintf('Now in run() for file routine with status: %s', $this->importJob->status));
if ('ready_to_run' === $this->importJob->status) {
$this->repository->setStatus($this->importJob, 'running');
// get processor, depending on file type
// is just CSV for now.
$processor = $this->getProcessor();
$processor->setImportJob($this->importJob);
$transactions = $processor->run();
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
$this->repository->setTransactions($this->importJob, $transactions);
return;
}
throw new FireflyException(sprintf('Import routine cannot handle status "%s"', $this->importJob->status)); // @codeCoverageIgnore
}
/**
* Set the import job.
*
* @param ImportJob $importJob
*
* @return void
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
/**
* Return the appropriate file routine handler for
* the file type of the job.
*
* @return FileProcessorInterface
*/
private function getProcessor(): FileProcessorInterface
{
$config = $this->repository->getConfiguration($this->importJob);
$type = $config['file-type'] ?? 'csv';
$class = config(sprintf('import.options.file.processors.%s', $type));
return app($class);
}
}

View File

@ -1,89 +0,0 @@
<?php
/**
* FinTSRoutine.php
* Copyright (c) 2019 https://github.com/bnw
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Import\JobConfiguration\FinTSConfigurationSteps;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Routine\FinTS\StageImportDataHandler;
use Illuminate\Support\Facades\Log;
/**
*
* Class FinTSRoutine
*
* @deprecated
* @codeCoverageIgnore
*/
class FinTSRoutine implements RoutineInterface
{
/** @var ImportJob */
private $importJob;
/** @var ImportJobRepositoryInterface */
private $repository;
/**
* At the end of each run(), the import routine must set the job to the expected status.
*
* The final status of the routine must be "provider_finished".
*
* @throws FireflyException
*/
public function run(): void
{
Log::debug(sprintf('Now in FinTSRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
$valid = ['ready_to_run']; // should be only ready_to_run
if (in_array($this->importJob->status, $valid, true)) {
switch ($this->importJob->stage) {
default:
throw new FireflyException(sprintf('FinTSRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore
case FinTSConfigurationSteps::GO_FOR_IMPORT:
$this->repository->setStatus($this->importJob, 'running');
/** @var StageImportDataHandler $handler */
$handler = app(StageImportDataHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$transactions = $handler->getTransactions();
$this->repository->setTransactions($this->importJob, $transactions);
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
}
}
}
/**
* @param ImportJob $importJob
*
* @return void
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
}

View File

@ -1,53 +0,0 @@
<?php
/**
* RoutineInterface.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
/**
* Interface RoutineInterface
*
* @deprecated
* @codeCoverageIgnore
*/
interface RoutineInterface
{
/**
* At the end of each run(), the import routine must set the job to the expected status.
*
* The final status of the routine must be "provider_finished".
*
* @throws FireflyException
*/
public function run(): void;
/**
* Set the import job.
*
* @param ImportJob $importJob
*
* @return void
*/
public function setImportJob(ImportJob $importJob): void;
}

View File

@ -1,128 +0,0 @@
<?php
/**
* SpectreRoutine.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Routine\Spectre\StageAuthenticatedHandler;
use FireflyIII\Support\Import\Routine\Spectre\StageImportDataHandler;
use FireflyIII\Support\Import\Routine\Spectre\StageNewHandler;
use Log;
/**
* Class SpectreRoutine
*
* @deprecated
* @codeCoverageIgnore
*/
class SpectreRoutine implements RoutineInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* At the end of each run(), the import routine must set the job to the expected status.
*
* The final status of the routine must be "provider_finished".
*
* @throws FireflyException
*
*/
public function run(): void
{
Log::debug(sprintf('Now in SpectreRoutine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
$valid = ['ready_to_run']; // should be only ready_to_run
if (in_array($this->importJob->status, $valid, true)) {
switch ($this->importJob->stage) {
default:
throw new FireflyException(sprintf('SpectreRoutine cannot handle stage "%s".', $this->importJob->stage)); // @codeCoverageIgnore
case 'new':
// list all of the users logins.
$this->repository->setStatus($this->importJob, 'running');
/** @var StageNewHandler $handler */
$handler = app(StageNewHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
// if count logins is zero, go to authenticate stage
if (0 === $handler->getCountLogins()) {
$this->repository->setStage($this->importJob, 'do-authenticate');
$this->repository->setStatus($this->importJob, 'ready_to_run');
return;
}
// or return to config to select login.
$this->repository->setStage($this->importJob, 'choose-login');
$this->repository->setStatus($this->importJob, 'need_job_config');
break;
case 'do-authenticate':
// set job to require config.
$this->repository->setStatus($this->importJob, 'need_job_config');
return;
case 'authenticated':
$this->repository->setStatus($this->importJob, 'running');
// get accounts from login, store in job.
/** @var StageAuthenticatedHandler $handler */
$handler = app(StageAuthenticatedHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
// return to config to select account(s).
$this->repository->setStage($this->importJob, 'choose-accounts');
$this->repository->setStatus($this->importJob, 'need_job_config');
break;
case 'go-for-import':
// user has chosen account mapping. Should now be ready to import data.
$this->repository->setStatus($this->importJob, 'running');
$this->repository->setStage($this->importJob, 'do_import');
/** @var StageImportDataHandler $handler */
$handler = app(StageImportDataHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
}
}
}
/**
* Set the import job.
*
* @param ImportJob $importJob
*
* @return void
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
}

View File

@ -1,146 +0,0 @@
<?php
/**
* YnabRoutine.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Routine;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\ImportJob;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Support\Import\Routine\Ynab\GetAccountsHandler;
use FireflyIII\Support\Import\Routine\Ynab\ImportDataHandler;
use FireflyIII\Support\Import\Routine\Ynab\StageGetAccessHandler;
use FireflyIII\Support\Import\Routine\Ynab\StageGetBudgetsHandler;
use Log;
/**
* Class YnabRoutine
*
* @deprecated
* @codeCoverageIgnore
*/
class YnabRoutine implements RoutineInterface
{
/** @var ImportJob The import job */
private $importJob;
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/**
* At the end of each run(), the import routine must set the job to the expected status.
*
* The final status of the routine must be "provider_finished".
*
* @throws FireflyException
*/
public function run(): void
{
Log::debug(sprintf('Now in YNAB routine::run() with status "%s" and stage "%s".', $this->importJob->status, $this->importJob->stage));
$valid = ['ready_to_run']; // should be only ready_to_run
if (in_array($this->importJob->status, $valid, true)) {
// get access token from YNAB
if ('get_access_token' === $this->importJob->stage) {
// list all of the users accounts.
$this->repository->setStatus($this->importJob, 'running');
/** @var StageGetAccessHandler $handler */
$handler = app(StageGetAccessHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
// back to correct stage:
$this->repository->setStatus($this->importJob, 'ready_to_run');
$this->repository->setStage($this->importJob, 'get_budgets');
return;
}
if ('get_budgets' === $this->importJob->stage) {
$this->repository->setStatus($this->importJob, 'running');
/** @var StageGetBudgetsHandler $handler */
$handler = app(StageGetBudgetsHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
// count budgets in job, to determine next step.
$configuration = $this->repository->getConfiguration($this->importJob);
$budgets = $configuration['budgets'] ?? [];
// if more than 1 budget, select budget first.
if (count($budgets) > 1) {
$this->repository->setStage($this->importJob, 'select_budgets');
$this->repository->setStatus($this->importJob, 'need_job_config');
return;
}
if (1 === count($budgets)) {
$this->repository->setStatus($this->importJob, 'ready_to_run');
$this->repository->setStage($this->importJob, 'get_accounts');
}
return;
}
if ('get_accounts' === $this->importJob->stage) {
$this->repository->setStatus($this->importJob, 'running');
/** @var GetAccountsHandler $handler */
$handler = app(GetAccountsHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$this->repository->setStage($this->importJob, 'select_accounts');
$this->repository->setStatus($this->importJob, 'need_job_config');
return;
}
if ('go-for-import' === $this->importJob->stage) {
$this->repository->setStatus($this->importJob, 'running');
$this->repository->setStage($this->importJob, 'do_import');
/** @var ImportDataHandler $handler */
$handler = app(ImportDataHandler::class);
$handler->setImportJob($this->importJob);
$handler->run();
$this->repository->setStatus($this->importJob, 'provider_finished');
$this->repository->setStage($this->importJob, 'final');
return;
}
throw new FireflyException(sprintf('YNAB import routine cannot handle stage "%s"', $this->importJob->stage));
}
}
/**
* Set the import job.
*
* @param ImportJob $importJob
*
* @return void
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
}
}

View File

@ -1,243 +0,0 @@
<?php
/**
* AbnAmroDescription.php
* Copyright (c) 2019 Robert Horlings
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Class AbnAmroDescription.
*
* @deprecated
* @codeCoverageIgnore
*
* Parses the description from txt files for ABN AMRO bank accounts.
*
* Based on the logic as described in the following Gist:
* https://gist.github.com/vDorst/68d555a6a90f62fec004
*/
class AbnAmroDescription implements SpecificInterface
{
/** @var array The current row. */
public $row;
/**
* Description of this specific fix.
*
* @return string
* @codeCoverageIgnore
*/
public static function getDescription(): string
{
return 'import.specific_abn_descr';
}
/**
* Name of specific fix.
*
* @return string
* @codeCoverageIgnore
*/
public static function getName(): string
{
return 'import.specific_abn_name';
}
/**
* Run the fix.
*
* @param array $row
*
* @return array
*
*/
public function run(array $row): array
{
$this->row = array_values($row);
if (!isset($row[7])) {
return $row;
}
// Try to parse the description in known formats.
$parsed = $this->parseSepaDescription() || $this->parseTRTPDescription() || $this->parseGEABEADescription() || $this->parseABNAMRODescription();
// If the description could not be parsed, specify an unknown opposing
// account, as an opposing account is required
if (!$parsed) {
$this->row[8] = (string) trans('firefly.unknown'); // opposing-account-name
}
return $this->row;
}
/**
* Parses the current description with costs from ABN AMRO itself.
*
* @return bool true if the description is GEA/BEA-format, false otherwise
*/
protected function parseABNAMRODescription(): bool
{
// See if the current description is formatted in ABN AMRO format
if (preg_match('/ABN AMRO.{24} (.*)/', $this->row[7], $matches)) {
$this->row[8] = 'ABN AMRO'; // this one is new (opposing account name)
$this->row[7] = $matches[1]; // this is the description
return true;
}
return false;
}
/**
* Parses the current description in GEA/BEA format.
*
* @return bool true if the description is GEA/BEAformat, false otherwise
*/
protected function parseGEABEADescription(): bool
{
// See if the current description is formatted in GEA/BEA format
if (preg_match('/([BG]EA) +(NR:[a-zA-Z:0-9]+) +([0-9.\/]+) +([^,]*)/', $this->row[7], $matches)) {
// description and opposing account will be the same.
$this->row[8] = $matches[4]; // 'opposing-account-name'
$this->row[7] = $matches[4]; // 'description'
if ('GEA' === $matches[1]) {
$this->row[7] = 'GEA ' . $matches[4]; // 'description'
}
return true;
}
return false;
}
/**
* Parses the current description in SEPA format.
*
* @return bool true if the description is SEPA format, false otherwise
*
*/
protected function parseSepaDescription(): bool
{
// See if the current description is formatted as a SEPA plain description
if (preg_match('/^SEPA(.{28})/', $this->row[7], $matches)) {
$type = $matches[1];
$reference = '';
$name = '';
$newDescription = '';
// SEPA plain descriptions contain several key-value pairs, split by a colon
preg_match_all('/([A-Za-z]+(?=:\s)):\s([A-Za-z 0-9._#-]+(?=\s|$))/', $this->row[7], $matches, PREG_SET_ORDER);
if (is_array($matches)) {
foreach ($matches as $match) {
$key = $match[1];
$value = trim($match[2]);
switch (strtoupper($key)) {
case 'OMSCHRIJVING':
$newDescription = $value;
break;
case 'NAAM':
$this->row[8] = $value;
$name = $value;
break;
case 'KENMERK':
$reference = $value;
break;
case 'IBAN':
$this->row[9] = $value;
break;
default: // @codeCoverageIgnore
// Ignore the rest
}
}
}
// Set a new description for the current transaction. If none was given
// set the description to type, name and reference
$this->row[7] = $newDescription;
if ('' === $newDescription) {
$this->row[7] = sprintf('%s - %s (%s)', $type, $name, $reference);
}
return true;
}
return false;
}
/**
* Parses the current description in TRTP format.
*
* @return bool true if the description is TRTP format, false otherwise
*
*/
protected function parseTRTPDescription(): bool
{
// See if the current description is formatted in TRTP format
if (preg_match_all('!\/([A-Z]{3,4})\/([^/]*)!', $this->row[7], $matches, PREG_SET_ORDER)) {
$type = '';
$name = '';
$reference = '';
$newDescription = '';
// Search for properties specified in the TRTP format. If no description
// is provided, use the type, name and reference as new description
if (is_array($matches)) {
foreach ($matches as $match) {
$key = $match[1];
$value = trim($match[2]);
switch (strtoupper($key)) {
case 'NAME':
$this->row[8] = $value;
break;
case 'REMI':
$newDescription = $value;
break;
case 'IBAN':
$this->row[9] = $value;
break;
case 'EREF':
$reference = $value;
break;
case 'TRTP':
$type = $value;
break;
default: // @codeCoverageIgnore
// Ignore the rest
}
}
// Set a new description for the current transaction. If none was given
// set the description to type, name and reference
$this->row[7] = $newDescription;
if ('' === $newDescription) {
$this->row[7] = sprintf('%s - %s (%s)', $type, $name, $reference);
}
}
return true;
}
return false;
}
}

View File

@ -1,96 +0,0 @@
<?php
/**
* Belfius.php
* Copyright (c) 2019 Sander Kleykens <sander@kleykens.com>
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Class Belfius.
*
* @deprecated
* @codeCoverageIgnore
*
* Fixes Belfius CSV files to:
* - Correct descriptions for recurring transactions so doubles can be detected when the equivalent incoming
* transaction is imported.
*
*/
class Belfius implements SpecificInterface
{
/**
* Description of this specific fix.
*
* @return string
* @codeCoverageIgnore
*/
public static function getDescription(): string
{
return 'import.specific_belfius_descr';
}
/**
* Name of specific fix.
*
* @return string
* @codeCoverageIgnore
*/
public static function getName(): string
{
return 'import.specific_belfius_name';
}
/**
* Fixes the description for outgoing recurring transactions so doubles can be detected when the equivalent incoming
* transaction is imported for another bank account.
*
* @return array the row containing the new description
*/
protected static function processRecurringTransactionDescription(array $row): array
{
if (!isset($row[5]) || !isset($row[14])) {
return $row;
}
$opposingAccountName = $row[5];
$description = $row[14];
preg_match('/DOORLOPENDE OPDRACHT.*\s+' . preg_quote($opposingAccountName, '/') . '\s+(.+)\s+REF.\s*:/', $description, $matches);
if (isset($matches[1])) {
$row[14] = $matches[1];
}
return $row;
}
/**
* Run the fix.
*
* @param array $row
*
* @return array
*
*/
public function run(array $row): array
{
return Belfius::processRecurringTransactionDescription($row);
}
}

View File

@ -1,144 +0,0 @@
<?php
/**
* IngBelgium.php
* Copyright (c) 2019 Sander Kleykens <sander@kleykens.com>
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Class IngBelgium.
*
* @deprecated
* @codeCoverageIgnore
*
* Parses the description and opposing account information (IBAN and name) from CSV files for ING Belgium bank accounts.
*
*/
class IngBelgium implements SpecificInterface
{
/**
* Description of the current specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getDescription(): string
{
return 'import.specific_ingbelgium_descr';
}
/**
* Name of the current specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getName(): string
{
return 'import.specific_ingbelgium_name';
}
/**
* Gets the description from the transaction details and makes sure structured descriptions are in the
* "+++090/9337/55493+++" format.
*
* @return string the description
*/
protected static function description(string $transactionDetails): string
{
$description = IngBelgium::parseInformationFromTransactionDetails($transactionDetails, '/Mededeling:\s*(.+)$/');
return IngBelgium::convertStructuredDescriptionToProperFormat($description);
}
/**
* Gets the opposing account's IBAN from the transaction details.
*
* @return string the opposing account's IBAN
*/
protected static function opposingAccountIban(string $transactionDetails): string
{
return IngBelgium::parseInformationFromTransactionDetails($transactionDetails, '/IBAN:\s*(.+?)(?=\s+)/');
}
/**
* Gets the opposing account name from the transaction details.
*
* @return string the opposing account name
*/
protected static function opposingAccountName(string $transactionDetails): string
{
return IngBelgium::parseInformationFromTransactionDetails($transactionDetails, '/Van:\s*(.+?)(?=\s{2,})/');
}
/**
* Gets the description and opposing account information (IBAN and name) from the transaction details and adds
* them to the row of data.
*
* @return array the row containing the description and opposing account's IBAN
*/
protected static function processTransactionDetails(array $row): array
{
if (isset($row[9])) {
$transactionDetails = $row[9];
$row[11] = IngBelgium::opposingAccountName($transactionDetails);
$row[12] = IngBelgium::opposingAccountIban($transactionDetails);
$row[13] = IngBelgium::description($transactionDetails);
}
return $row;
}
private static function convertStructuredDescriptionToProperFormat(string $description): string
{
preg_match('/^\*\*\*(\d{3}\/\d{4}\/\d{5})\*\*\*$/', $description, $matches);
if (isset($matches[1])) {
return '+++' . $matches[1] . '+++';
}
return $description;
}
private static function parseInformationFromTransactionDetails(string $transactionDetails, string $regex): string
{
if (isset($transactionDetails)) {
preg_match($regex, $transactionDetails, $matches);
if (isset($matches[1])) {
return trim($matches[1]);
}
}
return '';
}
/**
* Run the specific code.
*
* @param array $row
*
* @return array
*
*/
public function run(array $row): array
{
return IngBelgium::processTransactionDetails($row);
}
}

View File

@ -1,173 +0,0 @@
<?php
/**
* IngDescription.php
* Copyright (c) 2019 https://github.com/tomwerf
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Class IngDescription.
*
* @deprecated
* @codeCoverageIgnore
*
* Parses the description from CSV files for Ing bank accounts.
*
* With Mutation 'InternetBankieren', 'Overschrijving', 'Verzamelbetaling' and
* 'Incasso' the Name of Opposing account the Opposing IBAN number are in the
* Description. This class will remove them, and add Name in description by
* 'Betaalautomaat' so those are easily recognizable
*/
class IngDescription implements SpecificInterface
{
/** @var array The current row. */
public $row;
/**
* Description of the current specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getDescription(): string
{
return 'import.specific_ing_descr';
}
/**
* Name of the current specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getName(): string
{
return 'import.specific_ing_name';
}
/**
* Run the specific code.
*
* @param array $row
*
* @return array
*
*/
public function run(array $row): array
{
$this->row = array_values($row);
array_push($this->row); // New column for "Valutadatum"
if (count($this->row) >= 8) { // check if the array is correct
switch ($this->row[4]) { // Get value for the mutation type
case 'GT': // InternetBankieren
case 'OV': // Overschrijving
case 'VZ': // Verzamelbetaling
case 'IC': // Incasso
case 'DV': // Divers
$this->removeIBANIngDescription(); // Remove "IBAN:", because it is already at "Tegenrekening"
$this->removeNameIngDescription(); // Remove "Naam:", because it is already at "Naam/ Omschrijving"
$this->removeIngDescription(); // Remove "Omschrijving", but not the value from description
$this->moveValutadatumDescription(); // Move "Valutadatum" from description to new column
$this->MoveSavingsAccount(); // Move savings account number and name
break;
case 'BA': // Betaalautomaat
$this->moveValutadatumDescription(); // Move "Valutadatum" from description to new column
$this->addNameIngDescription();
break;
}
}
return $this->row;
}
/**
* Add the Opposing name from cell 1 in the description for Betaalautomaten
* Otherwise the description is only: 'Pasvolgnr:<nr> <date> Transactie:<NR> Term:<nr>'.
*/
protected function addNameIngDescription(): void
{
$this->row[8] = $this->row[1] . ' ' . $this->row[8];
}
/**
* Move "Valutadatum" from the description to new column.
*/
protected function moveValutadatumDescription(): void
{
$matches = [];
if (preg_match('/Valutadatum: ([0-9-]+)/', $this->row[8], $matches)) {
$this->row[9] = date("Ymd", strtotime($matches[1]));
$this->row[8] = preg_replace('/Valutadatum: [0-9-]+/', '', $this->row[8]);
}
}
/**
* Remove IBAN number out of the description
* Default description of Description is: Naam: <OPPOS NAME> Omschrijving: <DESCRIPTION> IBAN: <OPPOS IBAN NR>.
*/
protected function removeIBANIngDescription(): void
{
// Try replace the iban number with nothing. The IBAN nr is found in the third column
$this->row[8] = preg_replace('/\sIBAN:\s' . $this->row[3] . '/', '', $this->row[8]);
}
/**
* Remove "Omschrijving" (and NOT its value) from the description.
*/
protected function removeIngDescription(): void
{
$this->row[8] = preg_replace('/Omschrijving: /', '', $this->row[8]);
}
/**
* Remove "Naam" (and its value) from the description.
*/
protected function removeNameIngDescription(): void
{
$this->row[8] = preg_replace('/Naam:.*?([a-zA-Z\/]+:)/', '$1', $this->row[8]);
}
/**
* Move savings account number to column 1 and name to column 3.
*/
private function MoveSavingsAccount(): void
{
$matches = [];
if (preg_match('/(Naar|Van) (.*rekening) ([A-Za-z0-9]+)/', $this->row[8], $matches)) { // Search for saving acount at 'Mededelingen' column
$this->row[1] = $this->row[1] . ' ' . $matches[2] . ' ' . $matches[3]; // Current name + Saving acount name + Acount number
if ('' === (string) $this->row[3]) { // if Saving account number does not yet exists
$this->row[3] = $matches[3]; // Copy savings account number
}
$this->row[8] = preg_replace('/(Naar|Van) (.*rekening) ([A-Za-z0-9]+)/', '', $this->row[8]); // Remove the savings account content from description
} elseif (preg_match('/(Naar|Van) (.*rekening) ([A-Za-z0-9]+)/', $this->row[1], $matches)) { // Search for saving acount at 'Naam / Omschrijving' column
$this->row[1] = $matches[2] . ' ' . $matches[3]; // Saving acount name + Acount number
if ('' === (string) $this->row[3]) { // if Saving account number does not yet exists
$this->row[3] = $matches[3]; // Copy savings account number
}
}
if ('' !== (string)$this->row[3]) { // if Saving account number exists
if (! preg_match('/[A-Za-z]/', $this->row[3])) { // if Saving account number has no characters
$this->row[3] = sprintf("%010d", $this->row[3]); // Make the number 10 digits
}
}
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* PresidentsChoice.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Class PresidentsChoice.
*
* @deprecated
* @codeCoverageIgnore
*/
class PresidentsChoice implements SpecificInterface
{
/**
* Description of specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getDescription(): string
{
return 'import.specific_pres_descr';
}
/**
* Name of specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getName(): string
{
return 'import.specific_pres_name';
}
/**
* Run this specific.
*
* @param array $row
*
* @return array
*/
public function run(array $row): array
{
$row = array_values($row);
// first, if column 2 is empty and 3 is not, do nothing.
// if column 3 is empty and column 2 is not, move amount to column 3, *-1
if (isset($row[3]) && '' === $row[3]) {
$row[3] = bcmul($row[2], '-1');
}
if (isset($row[1])) {
// copy description into column 2, which is now usable.
$row[2] = $row[1];
}
return $row;
}
}

View File

@ -1,73 +0,0 @@
<?php
/**
* SnsDescription.php
* Copyright (c) 2019 hugovanduijn@gmail.com.
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Class SnsDescription.
*
* @codeCoverageIgnore
* @deprecated
*/
class SnsDescription implements SpecificInterface
{
/**
* Get description of specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getDescription(): string
{
return 'import.specific_sns_descr';
}
/**
* Get name of specific.
*
* @return string
* @codeCoverageIgnore
*/
public static function getName(): string
{
return 'import.specific_sns_name';
}
/**
* Run specific.
*
* @param array $row
*
* @return array
*/
public function run(array $row): array
{
$row = array_values($row);
if (!isset($row[17])) {
return $row;
}
$row[17] = ltrim($row[17], "'");
$row[17] = rtrim($row[17], "'");
return $row;
}
}

View File

@ -1,55 +0,0 @@
<?php
/**
* SpecificInterface.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Specifics;
/**
* Interface SpecificInterface.
*
* @codeCoverageIgnore
* @deprecated
*/
interface SpecificInterface
{
/**
* Get description.
*
* @return string
*/
public static function getDescription(): string;
/**
* Get name.
*
* @return string
*/
public static function getName(): string;
/**
* Run specific.
*
* @param array $row
*
* @return array
*/
public function run(array $row): array;
}

View File

@ -1,630 +0,0 @@
<?php
/**
* ImportArrayStorage.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Import\Storage;
use Carbon\Carbon;
use DB;
use Exception;
use FireflyIII\Events\RequestedReportOnJournals;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\ImportJob;
use FireflyIII\Models\Preference;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\ImportJob\ImportJobRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Repositories\TransactionGroup\TransactionGroupRepositoryInterface;
use FireflyIII\TransactionRules\Engine\RuleEngine;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
use Log;
/**
* Creates new transactions based on arrays.
*
* Class ImportArrayStorage
*
* @codeCoverageIgnore
* @deprecated
*
*/
class ImportArrayStorage
{
/** @var int Number of hits required for a transfer to match. */
private const REQUIRED_HITS = 4;
/** @var bool Check for transfers during import. */
private $checkForTransfers = false;
/** @var TransactionGroupRepositoryInterface */
private $groupRepos;
/** @var ImportJob The import job */
private $importJob;
/** @var JournalRepositoryInterface Journal repository for storage. */
private $journalRepos;
/** @var string */
private $language = 'en_US';
/** @var ImportJobRepositoryInterface Import job repository */
private $repository;
/** @var array The transfers the user already has. */
private $transfers;
/**
* Set job, count transfers in the array and create the repository.
*
* @param ImportJob $importJob
*/
public function setImportJob(ImportJob $importJob): void
{
$this->importJob = $importJob;
$this->repository = app(ImportJobRepositoryInterface::class);
$this->repository->setUser($importJob->user);
$this->countTransfers();
$this->journalRepos = app(JournalRepositoryInterface::class);
$this->journalRepos->setUser($importJob->user);
$this->groupRepos = app(TransactionGroupRepositoryInterface::class);
$this->groupRepos->setUser($importJob->user);
// get language of user.
/** @var Preference $pref */
$pref = app('preferences')->getForUser($importJob->user, 'language', config('firefly.default_language', 'en_US'));
$this->language = $pref->data;
Log::debug('Constructed ImportArrayStorage()');
}
/**
* Actually does the storing. Does three things.
* - Store journals
* - Link to tag
* - Run rules (if set to)
*
* @throws FireflyException
* @return Collection
*/
public function store(): Collection
{
// store transactions
$this->setStatus('storing_data');
$collection = $this->storeGroupArray();
$this->setStatus('stored_data');
// link tag:
$this->setStatus('linking_to_tag');
$this->linkToTag($collection);
$this->setStatus('linked_to_tag');
// run rules, if configured to.
$config = $this->importJob->configuration;
if (isset($config['apply-rules']) && true === $config['apply-rules']) {
$this->setStatus('applying_rules');
$this->applyRules($collection);
$this->setStatus('rules_applied');
}
app('preferences')->mark();
// email about this:
event(new RequestedReportOnJournals((int) $this->importJob->user_id, $collection));
return $collection;
}
/**
* Applies the users rules to the created journals.
*
* @param Collection $collection
*
*/
private function applyRules(Collection $collection): void
{
Log::debug('Now in applyRules()');
/** @var RuleEngine $ruleEngine */
$ruleEngine = app(RuleEngine::class);
$ruleEngine->setUser($this->importJob->user);
$ruleEngine->setAllRules(true);
// for this call, the rule engine only includes "store" rules:
$ruleEngine->setTriggerMode(RuleEngine::TRIGGER_STORE);
Log::debug('Start of engine loop');
foreach ($collection as $group) {
$this->applyRulesGroup($ruleEngine, $group);
}
Log::debug('End of engine loop.');
}
/**
* @param RuleEngine $ruleEngine
* @param TransactionGroup $group
*/
private function applyRulesGroup(RuleEngine $ruleEngine, TransactionGroup $group): void
{
Log::debug(sprintf('Processing group #%d', $group->id));
foreach ($group->transactionJournals as $journal) {
Log::debug(sprintf('Processing journal #%d from group #%d', $journal->id, $group->id));
$ruleEngine->processTransactionJournal($journal);
}
}
/**
* Count the number of transfers in the array. If this is zero, don't bother checking for double transfers.
*/
private function countTransfers(): void
{
Log::debug('Now in countTransfers()');
/** @var array $array */
$array = $this->repository->getTransactions($this->importJob);
$count = 0;
foreach ($array as $index => $group) {
foreach ($group['transactions'] as $transaction) {
if (strtolower(TransactionType::TRANSFER) === strtolower($transaction['type'])) {
$count++;
Log::debug(sprintf('Row #%d is a transfer, increase count to %d', $index + 1, $count));
}
}
}
Log::debug(sprintf('Count of transfers in import array is %d.', $count));
if ($count > 0) {
$this->checkForTransfers = true;
Log::debug('Will check for duplicate transfers.');
// get users transfers. Needed for comparison.
$this->getTransfers();
}
}
/**
* @param int $index
* @param array $group
*
* @return bool
*/
private function duplicateDetected(int $index, array $group): bool
{
Log::debug(sprintf('Now in duplicateDetected(%d)', $index));
$transactions = $group['transactions'] ?? [];
foreach ($transactions as $transaction) {
$hash = $this->getHash($transaction);
$existingId = $this->hashExists($hash);
if (null !== $existingId) {
$message = (string) trans('import.duplicate_row', ['row' => $index, 'description' => $transaction['description']]);
$this->logDuplicateObject($transaction, $existingId);
$this->repository->addErrorMessage($this->importJob, $message);
return true;
}
// do transfer detection:
if ($this->checkForTransfers && $this->transferExists($transaction)) {
$message = (string) trans('import.duplicate_row', ['row' => $index, 'description' => $transaction['description']]);
$this->logDuplicateTransfer($transaction);
$this->repository->addErrorMessage($this->importJob, $message);
return true;
}
}
return false;
}
/**
* Get hash of transaction.
*
* @param array $transaction
*
* @return string
*/
private function getHash(array $transaction): string
{
unset($transaction['import_hash_v2'], $transaction['original_source']);
$json = json_encode($transaction, JSON_THROW_ON_ERROR);
if (false === $json) {
// @codeCoverageIgnoreStart
/** @noinspection ForgottenDebugOutputInspection */
Log::error('Could not encode import array.', $transaction);
try {
$json = random_int(1, 10000);
} catch (Exception $e) {
// seriously?
Log::error(sprintf('random_int() just failed. I want a medal: %s', $e->getMessage()));
}
// @codeCoverageIgnoreEnd
}
$hash = hash('sha256', $json);
Log::debug(sprintf('The hash is: %s', $hash), $transaction);
return $hash;
}
/**
* @param TransactionGroup $transactionGroup
*
* @return array
*/
private function getTransactionFromJournal(TransactionGroup $transactionGroup): array
{
// collect transactions using the journal collector
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->importJob->user);
$collector->setGroup($transactionGroup);
return $collector->getExtractedJournals();
}
/**
* Get the users transfers, so they can be compared to whatever the user is trying to import.
*/
private function getTransfers(): void
{
Log::debug('Now in getTransfers()');
app('preferences')->mark();
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->importJob->user);
$collector
->setTypes([TransactionType::TRANSFER])->setLimit(10000)->setPage(1)
->withAccountInformation();
$this->transfers = $collector->getExtractedJournals();
Log::debug(sprintf('Count of getTransfers() is %d', count($this->transfers)));
}
/**
* Check if the hash exists for the array the user wants to import.
*
* @param string $hash
*
* @return int|null
*/
private function hashExists(string $hash): ?int
{
$entry = $this->journalRepos->findByHash($hash);
if (null === $entry) {
Log::debug(sprintf('Found no transactions with hash %s.', $hash));
return null;
}
Log::info(sprintf('Found a transaction journal with an existing hash: %s', $hash));
return (int) $entry->transaction_journal_id;
}
/**
* Link all imported journals to a tag.
*
* @param Collection $collection
*/
private function linkToTag(Collection $collection): void
{
if (0 === $collection->count()) {
return;
}
/** @var TagRepositoryInterface $repository */
$repository = app(TagRepositoryInterface::class);
$repository->setUser($this->importJob->user);
$data = [
'tag' => (string) trans('import.import_with_key', ['key' => $this->importJob->key]),
'date' => new Carbon,
'description' => null,
'latitude' => null,
'longitude' => null,
'zoom_level' => null,
'tagMode' => 'nothing',
];
$tag = $repository->store($data);
Log::debug(sprintf('Created tag #%d ("%s")', $tag->id, $tag->tag));
Log::debug('Looping groups...');
// TODO double loop.
/** @var TransactionGroup $group */
foreach ($collection as $group) {
Log::debug(sprintf('Looping journals in group #%d', $group->id));
/** @var TransactionJournal $journal */
$journalIds = $group->transactionJournals->pluck('id')->toArray();
$tagId = $tag->id;
foreach ($journalIds as $journalId) {
Log::debug(sprintf('Linking journal #%d to tag #%d...', $journalId, $tagId));
// @codeCoverageIgnoreStart
try {
DB::table('tag_transaction_journal')->insert(['transaction_journal_id' => $journalId, 'tag_id' => $tagId]);
} catch (QueryException $e) {
Log::error(sprintf('Could not link journal #%d to tag #%d because: %s', $journalId, $tagId, $e->getMessage()));
}
// @codeCoverageIgnoreEnd
}
Log::info(sprintf('Linked %d journals to tag #%d ("%s")', $collection->count(), $tag->id, $tag->tag));
}
$this->repository->setTag($this->importJob, $tag);
}
/**
* Log about a duplicate object (double hash).
*
* @param array $transaction
* @param int $existingId
*/
private function logDuplicateObject(array $transaction, int $existingId): void
{
Log::info(
'Transaction is a duplicate, and will not be imported (the hash exists).',
[
'existing' => $existingId,
'description' => $transaction['description'] ?? '',
'amount' => $transaction['transactions'][0]['amount'] ?? 0,
'date' => $transaction['date'] ?? '',
]
);
}
/**
* Log about a duplicate transfer.
*
* @param array $transaction
*/
private function logDuplicateTransfer(array $transaction): void
{
Log::info(
'Transaction is a duplicate transfer, and will not be imported (such a transfer exists already).',
[
'description' => $transaction['description'] ?? '',
'amount' => $transaction['transactions'][0]['amount'] ?? 0,
'date' => $transaction['date'] ?? '',
]
);
}
/**
* Shorthand method to quickly set job status
*
* @param string $status
*/
private function setStatus(string $status): void
{
$this->repository->setStatus($this->importJob, $status);
}
/**
* @param int $index
* @param array $group
*
* @return TransactionGroup|null
*/
private function storeGroup(int $index, array $group): ?TransactionGroup
{
Log::debug(sprintf('Going to store entry #%d', $index + 1));
// do some basic error catching.
foreach ($group['transactions'] as $groupIndex => $transaction) {
$group['transactions'][$groupIndex]['date'] = Carbon::parse($transaction['date'], config('app.timezone'));
$group['transactions'][$groupIndex]['description'] = '' === $transaction['description'] ? '(empty description)' : $transaction['description'];
}
// do duplicate detection!
if ($this->duplicateDetected($index, $group)) {
Log::warning(sprintf('Row #%d seems to be a imported already and will be ignored.', $index));
return null;
}
// store the group
try {
$newGroup = $this->groupRepos->store($group);
// @codeCoverageIgnoreStart
} catch (FireflyException $e) {
Log::error($e->getMessage());
Log::error($e->getTraceAsString());
$this->repository->addErrorMessage($this->importJob, sprintf('Row #%d could not be imported. %s', $index, $e->getMessage()));
return null;
}
// @codeCoverageIgnoreEnd
Log::debug(sprintf('Stored as group #%d', $newGroup->id));
// add to collection of transfers, if necessary:
if ('transfer' === strtolower($group['transactions'][0]['type'])) {
$journals = $this->getTransactionFromJournal($newGroup);
Log::debug('We just stored a transfer, so add the journal to the list of transfers.');
foreach ($journals as $newJournal) {
$this->transfers[] = $newJournal;
}
Log::debug(sprintf('List length is now %d', count($this->transfers)));
}
return $newGroup;
}
/**
* Store array as journals.
*
* @throws FireflyException
*
* @return Collection
*/
private function storeGroupArray(): Collection
{
/** @var array $array */
$array = $this->repository->getTransactions($this->importJob);
$count = count($array);
Log::notice(sprintf('Will now store the groups. Count of groups is %d.', $count));
Log::notice('Going to store...');
$collection = new Collection;
foreach ($array as $index => $group) {
Log::debug(sprintf('Now store #%d', $index + 1));
$result = $this->storeGroup($index, $group);
if (null !== $result) {
$collection->push($result);
}
}
Log::notice(sprintf('Done storing. Firefly III has stored %d transactions.', $collection->count()));
return $collection;
}
/**
* Check if a transfer exists.
*
* @param array $transaction
*
* @return bool
*
*/
private function transferExists(array $transaction): bool
{
Log::debug('transferExists() Check if transaction is a double transfer.');
// how many hits do we need?
Log::debug(sprintf('System has %d existing transfers', count($this->transfers)));
// loop over each split:
// check if is a transfer
if (strtolower(TransactionType::TRANSFER) !== strtolower($transaction['type'])) {
// @codeCoverageIgnoreStart
Log::debug(sprintf('Is a %s, not a transfer so no.', $transaction['type']));
return false;
// @codeCoverageIgnoreEnd
}
Log::debug(sprintf('Required hits for transfer comparison is %d', self::REQUIRED_HITS));
// get the amount:
/** @noinspection UnnecessaryCastingInspection */
$amount = (string) ($transaction['amount'] ?? '0');
if (bccomp($amount, '0') === -1) {
$amount = bcmul($amount, '-1'); // @codeCoverageIgnore
}
// get the description:
//$description = '' === (string)$transaction['description'] ? $transaction['description'] : $transaction['description'];
$description = (string) $transaction['description'];
// get the source and destination ID's:
$transactionSourceIDs = [(int) $transaction['source_id'], (int) $transaction['destination_id']];
sort($transactionSourceIDs);
// get the source and destination names:
$transactionSourceNames = [(string) $transaction['source_name'], (string) $transaction['destination_name']];
sort($transactionSourceNames);
// then loop all transfers:
/** @var array $transfer */
foreach ($this->transfers as $transfer) {
// number of hits for this split-transfer combination:
$hits = 0;
Log::debug(sprintf('Now looking at transaction journal #%d', $transfer['transaction_journal_id']));
// compare amount:
$originalAmount = app('steam')->positive($transfer['amount']);
Log::debug(sprintf('Amount %s compared to %s', $amount, $originalAmount));
if (0 !== bccomp($amount, $originalAmount)) {
Log::debug('Amount is not a match, continue with next transfer.');
continue;
}
++$hits;
Log::debug(sprintf('Comparison is a hit! (%s)', $hits));
// compare description:
// $comparison = '(empty description)' === $transfer['description'] ? '' : $transfer['description'];
$comparison = $transfer['description'];
Log::debug(sprintf('Comparing "%s" to "%s" (original: "%s")', $description, $transfer['description'], $comparison));
if ($description !== $comparison) {
Log::debug('Description is not a match, continue with next transfer.');
continue; // @codeCoverageIgnore
}
++$hits;
Log::debug(sprintf('Comparison is a hit! (%s)', $hits));
// compare date:
$transferDate = $transfer['date']->format('Y-m-d H:i:s');
$transactionDate = $transaction['date']->format('Y-m-d H:i:s');
Log::debug(sprintf('Comparing dates "%s" to "%s"', $transactionDate, $transferDate));
if ($transactionDate !== $transferDate) {
Log::debug('Date is not a match, continue with next transfer.');
continue; // @codeCoverageIgnore
}
++$hits;
Log::debug(sprintf('Comparison is a hit! (%s)', $hits));
// compare source and destination id's
$transferSourceIDs = [(int) $transfer['source_account_id'], (int) $transfer['destination_account_id']];
sort($transferSourceIDs);
/** @noinspection DisconnectedForeachInstructionInspection */
Log::debug('Comparing current transaction source+dest IDs', $transactionSourceIDs);
Log::debug('.. with current transfer source+dest IDs', $transferSourceIDs);
if ($transactionSourceIDs === $transferSourceIDs) {
++$hits;
Log::debug(sprintf('Source IDs are the same! (%d)', $hits));
}
if ($transactionSourceIDs !== $transferSourceIDs) {
Log::debug('Source IDs are not the same.');
}
unset($transferSourceIDs);
// compare source and destination names
$transferSource = [(string) ($transfer['source_account_name'] ?? ''), (string) ($transfer['destination_account_name'] ?? '')];
sort($transferSource);
/** @noinspection DisconnectedForeachInstructionInspection */
Log::debug('Comparing current transaction source+dest names', $transactionSourceNames);
Log::debug('.. with current transfer source+dest names', $transferSource);
if ($transactionSourceNames === $transferSource && $transferSource !== ['', '']) {
// @codeCoverageIgnoreStart
++$hits;
Log::debug(sprintf('Source names are the same! (%d)', $hits));
// @codeCoverageIgnoreEnd
}
if ($transactionSourceNames !== $transferSource) {
Log::debug('Source names are not the same.');
}
Log::debug(sprintf('Number of hits is %d', $hits));
if ($hits >= self::REQUIRED_HITS) {
Log::debug(sprintf('Is more than %d, return true.', self::REQUIRED_HITS));
return true;
}
}
Log::debug('Is not an existing transfer, return false.');
return false;
}
}

View File

@ -1,150 +0,0 @@
<?php
/**
* ImportJob.php
* Copyright (c) 2019 james@firefly-iii.org
*
* This file is part of Firefly III (https://github.com/firefly-iii).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Models;
use Carbon\Carbon;
use Eloquent;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class ImportJob.
*
* @codeCoverageIgnore
* @deprecated
* @property array $transactions
* @property array $configuration
* @property User $user
* @property int $user_id
* @property string $status
* @property string $stage
* @property string $key
* @property string $provider
* @property string $file_type
* @property int $tag_id
* @property Tag $tag
* @property array $errors
* @property array extended_status
* @property int id
* @property Carbon $created_at
* @property Carbon $updated_at
* @property-read Collection|Attachment[] $attachments
* @method static Builder|ImportJob newModelQuery()
* @method static Builder|ImportJob newQuery()
* @method static Builder|ImportJob query()
* @method static Builder|ImportJob whereConfiguration($value)
* @method static Builder|ImportJob whereCreatedAt($value)
* @method static Builder|ImportJob whereErrors($value)
* @method static Builder|ImportJob whereExtendedStatus($value)
* @method static Builder|ImportJob whereFileType($value)
* @method static Builder|ImportJob whereId($value)
* @method static Builder|ImportJob whereKey($value)
* @method static Builder|ImportJob whereProvider($value)
* @method static Builder|ImportJob whereStage($value)
* @method static Builder|ImportJob whereStatus($value)
* @method static Builder|ImportJob whereTagId($value)
* @method static Builder|ImportJob whereTransactions($value)
* @method static Builder|ImportJob whereUpdatedAt($value)
* @method static Builder|ImportJob whereUserId($value)
* @mixin Eloquent
* @property-read int|null $attachments_count
* @property int $id
* @property array|null $extended_status
*/
class ImportJob extends Model
{
/**
* The attributes that should be casted to native types.
*
* @var array
*/
protected $casts
= [
'user_id' => 'int',
'created_at' => 'datetime',
'updated_at' => 'datetime',
'configuration' => 'array',
'extended_status' => 'array',
'transactions' => 'array',
'errors' => 'array',
];
/** @var array Fields that can be filled */
protected $fillable = ['key', 'user_id', 'file_type', 'provider', 'status', 'stage', 'configuration', 'extended_status', 'transactions', 'errors'];
/**
* Route binder. Converts the key in the URL to the specified object (or throw 404).
*
* @param $value
*
* @throws NotFoundHttpException
* @return mixed
*
*/
public static function routeBinder(string $value): ImportJob
{
if (auth()->check()) {
$key = trim($value);
/** @var User $user */
$user = auth()->user();
/** @var ImportJob $importJob */
$importJob = $user->importJobs()->where('key', $key)->first();
if (null !== $importJob) {
return $importJob;
}
}
throw new NotFoundHttpException;
}
/**
* @codeCoverageIgnore
* @return MorphMany
*/
public function attachments(): MorphMany
{
return $this->morphMany(Attachment::class, 'attachable');
}
/**
* @codeCoverageIgnore
* @return BelongsTo
*/
public function tag(): BelongsTo
{
return $this->belongsTo(Tag::class);
}
/**
* @codeCoverageIgnore
* @return BelongsTo
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

View File

@ -4,13 +4,50 @@ declare(strict_types=1);
namespace FireflyIII\Models;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
/**
* Class ObjectGroup
*
* @property-read \Illuminate\Database\Eloquent\Collection|\FireflyIII\Models\PiggyBank[] $piggyBanks
* @property-read int|null $piggy_banks_count
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup query()
* @mixin \Eloquent
* @property int $id
* @property \Illuminate\Support\Carbon|null $created_at
* @property \Illuminate\Support\Carbon|null $updated_at
* @property string|null $deleted_at
* @property string $title
* @property int $order
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup whereDeletedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup whereOrder($value)
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup whereTitle($value)
* @method static \Illuminate\Database\Eloquent\Builder|\FireflyIII\Models\ObjectGroup whereUpdatedAt($value)
*/
class ObjectGroup extends Model
{
protected $fillable = ['title', 'order', 'user_id'];
/**
* The attributes that should be casted to native types.
*
* @var array
*/
protected $casts
= [
'created_at' => 'datetime',
'updated_at' => 'datetime',
'user_id' => 'integer',
'deleted_at' => 'datetime',
];
/**
* @return \Illuminate\Database\Eloquent\Relations\MorphToMany
*/
@ -18,4 +55,34 @@ class ObjectGroup extends Model
{
return $this->morphedByMany(PiggyBank::class, 'object_groupable');
}
/**
* Route binder. Converts the key in the URL to the specified object (or throw 404).
*
* @param string $value
*
* @throws NotFoundHttpException
* @return ObjectGroup
*/
public static function routeBinder(string $value): ObjectGroup
{
if (auth()->check()) {
$objectGroupId = (int) $value;
$objectGroup = self::where('object_groups.id', $objectGroupId)
->where('object_groups.user_id', auth()->user()->id)->first();
if (null !== $objectGroup) {
return $objectGroup;
}
}
throw new NotFoundHttpException;
}
/**
* @return BelongsTo
* @codeCoverageIgnore
*/
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

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