mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-08-28 17:07:21 +00:00
Compare commits
105 Commits
5.2.8
...
5.3.0-beta
Author | SHA1 | Date | |
---|---|---|---|
|
80de6c78dc | ||
|
5009cb5d55 | ||
|
0c90171a49 | ||
|
d282cb4e34 | ||
|
976f79b5a6 | ||
|
6693a5166f | ||
|
7b9906d493 | ||
|
f927e61b37 | ||
|
430b498caf | ||
|
983508e291 | ||
|
104a2379f3 | ||
|
e337bcf8bd | ||
|
029774687c | ||
|
be58545999 | ||
|
d774b4e2e3 | ||
|
cb65999124 | ||
|
77e7af75dc | ||
|
714184867c | ||
|
fad2331d80 | ||
|
bb5de8bf7e | ||
|
6f78c96cee | ||
|
883342b2c8 | ||
|
6232858b85 | ||
|
4e4b44d41d | ||
|
daf74e11ed | ||
|
3e2c2e6395 | ||
|
bc5b2085b9 | ||
|
ebcd751145 | ||
|
cdfde3dca8 | ||
|
4e3378451c | ||
|
415fb7294c | ||
|
1e35f0e7e3 | ||
|
b83d06294d | ||
|
7945220825 | ||
|
3e8a4d55ef | ||
|
e1fbdca5c1 | ||
|
1b31d20877 | ||
|
aaaab03995 | ||
|
affa8a317a | ||
|
5a03f3395c | ||
|
8da6ec3f5b | ||
|
a0402ac742 | ||
|
654e0fc74f | ||
|
d3bd1f4124 | ||
|
2aa6067437 | ||
|
356c87da49 | ||
|
0d76fcd564 | ||
|
963c3b2a68 | ||
|
7617fe3510 | ||
|
88724be3aa | ||
|
f845c97955 | ||
|
2c69a2eda2 | ||
|
dcce747e92 | ||
|
c251ca5daf | ||
|
bcb9794315 | ||
|
1a043e35c2 | ||
|
4fef316ddd | ||
|
7196ac3ec9 | ||
|
1c74db30ed | ||
|
00440f282b | ||
|
dfe099f9c6 | ||
|
0dbee47182 | ||
|
46796a8c10 | ||
|
c381067364 | ||
|
19573de5df | ||
|
77359fbc55 | ||
|
45eb758583 | ||
|
1a154a8d45 | ||
|
c40f6f2864 | ||
|
c036c5a2bc | ||
|
5b29e78c4b | ||
|
b54ef9f5e5 | ||
|
b7f48a19e8 | ||
|
c8f1e4bbd7 | ||
|
5cc1369191 | ||
|
16a511cf79 | ||
|
7c78708865 | ||
|
0449430ec3 | ||
|
dd5a179ba1 | ||
|
7c1139e42b | ||
|
caddf3d1c6 | ||
|
54d5778bf3 | ||
|
b1732d0de8 | ||
|
48b5f749a1 | ||
|
a63b8322db | ||
|
2130eef971 | ||
|
5b829b514f | ||
|
1bac3258da | ||
|
d7181100ee | ||
|
ccc82858ad | ||
|
5dd6b23b09 | ||
|
6a08f52fa5 | ||
|
18172b7fdb | ||
|
3eccc56c7a | ||
|
f7545af17a | ||
|
aa4da1e2e1 | ||
|
b4aafefc2b | ||
|
8304ee21f3 | ||
|
ca6479ede6 | ||
|
471cdefcff | ||
|
16b0307b0a | ||
|
2f63090e7c | ||
|
8643034945 | ||
|
6cc4d14fcb | ||
|
60fa0d7244 |
30
.env.example
30
.env.example
@@ -10,14 +10,14 @@ APP_DEBUG=false
|
||||
SITE_OWNER=mail@example.com
|
||||
|
||||
# The encryption key for your sessions. Keep this very secure.
|
||||
# If you generate a new one existing data must be considered LOST.
|
||||
# If you generate a new one all existing attachments must be considered LOST.
|
||||
# Change it to a string of exactly 32 chars or use something like `php artisan key:generate` to generate it.
|
||||
# If you use Docker or similar, you can set this variable from a file by using APP_KEY_FILE
|
||||
APP_KEY=SomeRandomStringOf32CharsExactly
|
||||
|
||||
#
|
||||
# Firefly III will launch using this language (for new users and unauthenticated visitors)
|
||||
# For a list of available languages: https://github.com/firefly-iii/firefly-iii/tree/master/resources/lang
|
||||
# For a list of available languages: https://github.com/firefly-iii/firefly-iii/tree/main/resources/lang
|
||||
#
|
||||
# If text is still in English, remember that not everything may have been translated.
|
||||
DEFAULT_LANGUAGE=en_US
|
||||
@@ -57,7 +57,7 @@ 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.
|
||||
# Use "pgsql" for PostgreSQL and MariaDB. Use "sqlite" for SQLite.
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=fireflyiiidb
|
||||
DB_PORT=3306
|
||||
@@ -108,8 +108,8 @@ COOKIE_SECURE=false
|
||||
# If you want Firefly III to mail you, update these settings
|
||||
# For instructions, see: https://docs.firefly-iii.org/advanced-installation/email
|
||||
# If you use Docker or similar, you can set these variables from a file by appending them with _FILE
|
||||
MAIL_DRIVER=log
|
||||
MAIL_HOST=smtp.mailtrap.io
|
||||
MAIL_MAILER=log
|
||||
MAIL_HOST=null
|
||||
MAIL_PORT=2525
|
||||
MAIL_FROM=changeme@example.com
|
||||
MAIL_USERNAME=null
|
||||
@@ -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
|
||||
@@ -287,9 +304,8 @@ PUSHER_ID=
|
||||
DEMO_USERNAME=
|
||||
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.
|
||||
|
2
.github/contributing.md
vendored
2
.github/contributing.md
vendored
@@ -8,7 +8,7 @@ I am always interested in expanding Firefly III's many features. Just open a tic
|
||||
|
||||
## Pull requests
|
||||
|
||||
When contributing to Firefly III, please first discuss the change you wish to make via issue, email, or any other method. I can only accept pull requests against the `develop` branch, never the `master` branch.
|
||||
When contributing to Firefly III, please first discuss the change you wish to make via issue, email, or any other method. I can only accept pull requests against the `develop` branch, never the `main` branch.
|
||||
|
||||
## Translations :us: :fr: :de:
|
||||
|
||||
|
5
.github/pull_request_template.md
vendored
5
.github/pull_request_template.md
vendored
@@ -1,8 +1,9 @@
|
||||
<!--
|
||||
Before you create a new PR, please consider the following two considerations.
|
||||
Before you create a new PR, please consider:
|
||||
|
||||
1) Pull request for the MASTER branch will be closed.
|
||||
1) Pull requests for the MAIN branch will be closed.
|
||||
2) We cannot accept pull requests to add new currencies.
|
||||
3) DO NOT include translations in your PR. Only English US sentences.
|
||||
|
||||
Thanks.
|
||||
-->
|
||||
|
2
.github/security.md
vendored
2
.github/security.md
vendored
@@ -8,5 +8,5 @@ Only the latest version of Firefly III is supported. If you're not running the l
|
||||
|
||||
If you find something that compromises the security of Firefly III, you should [send me a message](mailto:james@firefly-iii.org) as soon as possible. These issues will be fixed immediately. You can also open an issue, but if you feel the issue is sensitive, please drop me a message instead.
|
||||
|
||||
You can use my [GPG key](https://keybase.io/jc5) for extra security. My [GitHub commits](https://github.com/firefly-iii/firefly-iii/commits/master) are almost always signed with this key.
|
||||
You can use my [GPG key](https://keybase.io/jc5) for extra security. My [GitHub commits](https://github.com/firefly-iii/firefly-iii/commits/main) are almost always signed with this key.
|
||||
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
/node_modules
|
||||
/frontend/node_modules
|
||||
/frontend/fonts
|
||||
/public/hot
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
|
2
app.json
2
app.json
@@ -3,7 +3,7 @@
|
||||
"description": "A free and open source personal finances manager",
|
||||
"repository": "https://github.com/firefly-iii/firefly-iii",
|
||||
"website": "https://firefly-iii.org/",
|
||||
"logo": "https://raw.githubusercontent.com/firefly-iii/firefly-iii/master/public/mstile-150x150.png",
|
||||
"logo": "https://raw.githubusercontent.com/firefly-iii/firefly-iii/main/public/mstile-150x150.png",
|
||||
"keywords": [
|
||||
"finance",
|
||||
"finances",
|
||||
|
@@ -50,8 +50,9 @@ use League\Fractal\Resource\Item;
|
||||
class AccountController extends Controller
|
||||
{
|
||||
use AccountFilter, TransactionFilter;
|
||||
/** @var AccountRepositoryInterface The account repository */
|
||||
private $repository;
|
||||
|
||||
private AccountRepositoryInterface $repository;
|
||||
public const RESOURCE_KEY = 'accounts';
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
@@ -150,7 +151,7 @@ class AccountController extends Controller
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($accounts, $transformer, 'accounts');
|
||||
$resource = new FractalCollection($accounts, $transformer, self::RESOURCE_KEY);
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
@@ -208,7 +209,7 @@ class AccountController extends Controller
|
||||
/** @var AccountTransformer $transformer */
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
$resource = new Item($account, $transformer, 'accounts');
|
||||
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
@@ -230,7 +231,7 @@ class AccountController extends Controller
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Item($account, $transformer, 'accounts');
|
||||
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
@@ -304,7 +305,7 @@ class AccountController extends Controller
|
||||
/** @var AccountTransformer $transformer */
|
||||
$transformer = app(AccountTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
$resource = new Item($account, $transformer, 'accounts');
|
||||
$resource = new Item($account, $transformer, self::RESOURCE_KEY);
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
|
@@ -42,10 +42,8 @@ use Illuminate\Http\JsonResponse;
|
||||
class AccountController extends Controller
|
||||
{
|
||||
use ApiSupport;
|
||||
/** @var CurrencyRepositoryInterface */
|
||||
private $currencyRepository;
|
||||
/** @var AccountRepositoryInterface */
|
||||
private $repository;
|
||||
private CurrencyRepositoryInterface $currencyRepository;
|
||||
private AccountRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* AccountController constructor.
|
||||
|
@@ -141,49 +141,6 @@ class CategoryController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// foreach ([] as $set) {
|
||||
// foreach ($set as $currency) {
|
||||
// $inKey = sprintf('%d-i', $currency['currency_id']);
|
||||
// $outKey = sprintf('%d-e', $currency['currency_id']);
|
||||
// $categories[] = (string)trans('firefly.no_category');
|
||||
// // make data arrays if not yet present.
|
||||
// $tempData[$inKey] = $tempData[$inKey] ?? [
|
||||
// 'currency_id' => $currency['currency_id'],
|
||||
// 'label' => (string)trans('firefly.box_earned_in_currency', ['currency' => $currency['currency_name']]),
|
||||
// 'currency_code' => $currency['currency_code'],
|
||||
// 'currency_symbol' => $currency['currency_symbol'],
|
||||
// 'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
// 'type' => 'bar', // line, area or bar
|
||||
// 'yAxisID' => 0, // 0, 1, 2
|
||||
// 'entries' => [
|
||||
// // per category:
|
||||
// // "category" => 5,
|
||||
// ],
|
||||
// ];
|
||||
// $tempData[$outKey] = $tempData[$outKey] ?? [
|
||||
// 'currency_id' => $currency['currency_id'],
|
||||
// 'label' => (string)trans('firefly.box_spent_in_currency', ['currency' => $currency['currency_name']]),
|
||||
// 'currency_code' => $currency['currency_code'],
|
||||
// 'currency_symbol' => $currency['currency_symbol'],
|
||||
// 'currency_decimal_places' => $currency['currency_decimal_places'],
|
||||
// 'type' => 'bar', // line, area or bar
|
||||
// 'yAxisID' => 0, // 0, 1, 2
|
||||
// 'entries' => [
|
||||
// // per category:
|
||||
// // "category" => 5,
|
||||
// ],
|
||||
// ];
|
||||
// foreach ($currency['transaction_journals'] as $journal) {
|
||||
// // is it expense or income?
|
||||
// $letter = -1 === bccomp($journal['amount'], '0') ? 'e' : 'i';
|
||||
// $currentKey = sprintf('%d-%s', $currency['currency_id'], $letter);
|
||||
// $name = (string)trans('firefly.no_category');
|
||||
// $tempData[$currentKey]['entries'][$name] = $tempData[$currentKey]['entries'][$name] ?? '0';
|
||||
// $tempData[$currentKey]['entries'][$name] = bcadd($tempData[$currentKey]['entries'][$name], $journal['amount']);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// re-sort every spent array and add 0 for missing entries.
|
||||
foreach ($tempData as $index => $set) {
|
||||
$oldSet = $set['entries'];
|
||||
|
@@ -577,7 +577,8 @@ class CurrencyController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
$currency = app('amount')->getDefaultCurrencyByUser(auth()->user());
|
||||
|
||||
$this->parameters->set('defaultCurrency', $currency);
|
||||
|
||||
/** @var CurrencyTransformer $transformer */
|
||||
$transformer = app(CurrencyTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -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');
|
||||
}
|
||||
|
||||
}
|
196
app/Api/V1/Controllers/ObjectGroupController.php
Normal file
196
app/Api/V1/Controllers/ObjectGroupController.php
Normal 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');
|
||||
}
|
||||
}
|
@@ -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();
|
||||
@@ -240,7 +241,6 @@ class PiggyBankController extends Controller
|
||||
$this->repository->setCurrentAmount($piggyBank, $data['current_amount']);
|
||||
}
|
||||
|
||||
|
||||
$manager = $this->getManager();
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* AccountController.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Search;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TransactionController.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,45 +20,51 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Search;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Support\Search\SearchInterface;
|
||||
use FireflyIII\Transformers\TransactionGroupTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
use League\Fractal\Resource\Collection;
|
||||
|
||||
/**
|
||||
* Class TransactionController
|
||||
*/
|
||||
class TransactionController extends Controller
|
||||
{
|
||||
/** @var string */
|
||||
public const SEARCH_ALL = 'all';
|
||||
/** @var string */
|
||||
public const SEARCH_DESCRIPTION = 'description';
|
||||
/** @var string */
|
||||
public const SEARCH_NOTES = 'notes';
|
||||
/** @var string */
|
||||
public const SEARCH_ACCOUNTS = 'accounts';
|
||||
/** @var array */
|
||||
private $validFields;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->validFields = [
|
||||
self::SEARCH_ALL,
|
||||
self::SEARCH_DESCRIPTION,
|
||||
self::SEARCH_NOTES,
|
||||
self::SEARCH_ACCOUNTS,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param Request $request
|
||||
* @param SearchInterface $searcher
|
||||
*
|
||||
* @return void
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function search(Request $request): void
|
||||
public function search(Request $request, SearchInterface $searcher): JsonResponse
|
||||
{
|
||||
die('the route is present but nobody\'s home.');
|
||||
$manager = $this->getManager();
|
||||
$fullQuery = (string) $request->get('query');
|
||||
$page = 0 === (int) $request->get('page') ? 1 : (int) $request->get('page');
|
||||
|
||||
$searcher->parseQuery($fullQuery);
|
||||
$searcher->setPage($page);
|
||||
$searcher->setLimit((int) config('firefly.search_result_limit'));
|
||||
$groups = $searcher->searchTransactions();
|
||||
$parameters = ['search' => $fullQuery];
|
||||
$url = route('api.v1.search.transactions') . '?' . http_build_query($parameters);
|
||||
$groups->setPath($url);
|
||||
$transactions = $groups->getCollection();
|
||||
|
||||
/** @var TransactionGroupTransformer $transformer */
|
||||
$transformer = app(TransactionGroupTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new Collection($transactions, $transformer, 'transactions');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($groups));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', 'application/vnd.api+json');
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TransferController.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Search;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
|
@@ -70,6 +70,7 @@ class BillRequest extends Request
|
||||
'repeat_freq' => $this->string('repeat_freq'),
|
||||
'skip' => $this->integer('skip'),
|
||||
'active' => $active,
|
||||
'order' => $this->integer('order'),
|
||||
'notes' => $this->nlString('notes'),
|
||||
];
|
||||
}
|
||||
@@ -83,13 +84,13 @@ class BillRequest extends Request
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|between:1,255|uniqueObjectForUser:bills,name',
|
||||
'amount_min' => 'required|numeric|more:0',
|
||||
'amount_max' => 'required|numeric|more:0',
|
||||
'name' => 'between:1,255|uniqueObjectForUser:bills,name',
|
||||
'amount_min' => 'numeric|more:0',
|
||||
'amount_max' => 'numeric|more:0',
|
||||
'currency_id' => 'numeric|exists:transaction_currencies,id',
|
||||
'currency_code' => 'min:3|max:3|exists:transaction_currencies,code',
|
||||
'date' => 'required|date',
|
||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'date' => 'date',
|
||||
'repeat_freq' => 'in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'between:0,31',
|
||||
'active' => [new IsBoolean],
|
||||
'notes' => 'between:1,65536',
|
||||
|
@@ -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',
|
||||
];
|
||||
}
|
||||
}
|
@@ -63,6 +63,7 @@ class PiggyBankRequest extends Request
|
||||
'startdate' => $this->date('start_date'),
|
||||
'targetdate' => $this->date('target_date'),
|
||||
'notes' => $this->nlString('notes'),
|
||||
'order' => $this->integer('order'),
|
||||
];
|
||||
}
|
||||
|
||||
|
86
app/Api/V1/Requests/PiggyBankStoreRequest.php
Normal file
86
app/Api/V1/Requests/PiggyBankStoreRequest.php
Normal 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',
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TransferRequest.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Requests\Search;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\Request;
|
||||
|
@@ -263,17 +263,13 @@ class TransactionUpdateRequest extends Request
|
||||
// TODO if the transaction_journal_id is empty, some fields are mandatory, like the amount!
|
||||
|
||||
// all journals must have a description
|
||||
//$this->validateDescriptions($validator);
|
||||
|
||||
// // validate foreign currency info
|
||||
// $this->validateForeignCurrencyInformation($validator);
|
||||
//
|
||||
|
||||
//
|
||||
// // make sure all splits have valid source + dest info
|
||||
// $this->validateSplitAccounts($validator);
|
||||
// the group must have a description if > 1 journal.
|
||||
// $this->validateGroupDescription($validator);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CorrectOpeningBalanceCurrencies.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Models\Account;
|
||||
|
60
app/Console/Commands/Correction/FixGroupAccounts.php
Normal file
60
app/Console/Commands/Correction/FixGroupAccounts.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use DB;
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Handlers\Events\UpdatedGroupEventHandler;
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Class FixGroupAccounts
|
||||
*/
|
||||
class FixGroupAccounts extends Command
|
||||
{
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Unify the source / destination accounts of split groups.';
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'firefly-iii:unify-group-accounts';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
// select transaction_group_id, count(transaction_group_id) as the_count from transaction_journals group by transaction_group_id having the_count > 1
|
||||
$groups = [];
|
||||
$res = TransactionJournal
|
||||
::groupBy('transaction_group_id')
|
||||
->get(['transaction_group_id', DB::raw('COUNT(transaction_group_id) as the_count')]);
|
||||
foreach ($res as $journal) {
|
||||
if ((int) $journal->the_count > 1) {
|
||||
$groups[] = (int) $journal->transaction_group_id;
|
||||
}
|
||||
}
|
||||
$handler = new UpdatedGroupEventHandler;
|
||||
foreach($groups as $groupId) {
|
||||
$group = TransactionGroup::find($groupId);
|
||||
$event = new UpdatedTransactionGroup($group);
|
||||
$handler->unifyAccounts($event);
|
||||
}
|
||||
|
||||
$this->line('Updated inconsistent transaction groups.');
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* FixLongDescriptions.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Models\TransactionGroup;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* FixRecurringTransactions.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Correction;
|
||||
|
||||
use FireflyIII\Models\Recurrence;
|
||||
@@ -55,9 +57,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();
|
||||
|
@@ -1,6 +1,4 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* CreateDatabase.php
|
||||
@@ -22,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
@@ -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')));
|
||||
|
@@ -159,7 +159,6 @@ 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()));
|
||||
}
|
||||
|
||||
return $value;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* ExportData.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Export;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* RestoreOAuthKeys.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Integrity;
|
||||
|
||||
use FireflyIII\Support\System\OAuthKeys;
|
||||
|
@@ -1,5 +1,4 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SetLatestVersion.php
|
||||
@@ -21,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
|
@@ -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.}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* MigrateRecurrenceMeta.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Upgrade;
|
||||
|
||||
use FireflyIII\Models\RecurrenceMeta;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* MigrateTagLocations.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Console\Commands\Upgrade;
|
||||
|
||||
use FireflyIII\Models\Location;
|
||||
|
@@ -211,7 +211,6 @@ class MigrateToRules extends Command
|
||||
$lang = app('preferences')->getForUser($user, 'language', 'en_US');
|
||||
$groupTitle = (string) trans('firefly.rulegroup_for_bills_title', [], $lang->data);
|
||||
$ruleGroup = $this->ruleGroupRepository->findByTitle($groupTitle);
|
||||
//$currency = $this->getCurrency($user);
|
||||
|
||||
if (null === $ruleGroup) {
|
||||
$ruleGroup = $this->ruleGroupRepository->store(
|
||||
|
@@ -341,19 +341,17 @@ class TransferCurrenciesCorrections extends Command
|
||||
if (isset($this->accountCurrencies[$accountId]) && $this->accountCurrencies[$accountId] instanceof TransactionCurrency) {
|
||||
return $this->accountCurrencies[$accountId]; // @codeCoverageIgnore
|
||||
}
|
||||
// TODO we can use getAccountCurrency() instead
|
||||
$currencyId = (int) $this->accountRepos->getMetaValue($account, 'currency_id');
|
||||
$result = $this->currencyRepos->findNull($currencyId);
|
||||
if (null === $result) {
|
||||
$currency = $this->accountRepos->getAccountCurrency($account);
|
||||
if (null === $currency) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$this->accountCurrencies[$accountId] = 0;
|
||||
|
||||
return null;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
$this->accountCurrencies[$accountId] = $result;
|
||||
$this->accountCurrencies[$accountId] = $currency;
|
||||
|
||||
return $result;
|
||||
return $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -76,7 +76,7 @@ class UpgradeDatabase extends Command
|
||||
'firefly-iii:migrate-recurrence-meta',
|
||||
'firefly-iii:migrate-tag-locations',
|
||||
|
||||
// there are 16 verify commands.
|
||||
// there are 15 verify commands.
|
||||
'firefly-iii:fix-piggies',
|
||||
'firefly-iii:create-link-types',
|
||||
'firefly-iii:create-access-tokens',
|
||||
@@ -93,6 +93,7 @@ class UpgradeDatabase extends Command
|
||||
'firefly-iii:fix-ob-currencies',
|
||||
'firefly-iii:fix-long-descriptions',
|
||||
'firefly-iii:fix-recurring-transactions',
|
||||
'firefly-iii:unify-group-accounts',
|
||||
|
||||
// two report commands
|
||||
'firefly-iii:report-empty-objects',
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* DuplicateTransactionException.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
@@ -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 */
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Factory;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups;
|
||||
use FireflyIII\Services\Internal\Support\BillServiceTrait;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\QueryException;
|
||||
@@ -37,7 +38,7 @@ use Log;
|
||||
*/
|
||||
class BillFactory
|
||||
{
|
||||
use BillServiceTrait;
|
||||
use BillServiceTrait, CreatesObjectGroups;
|
||||
|
||||
/** @var User */
|
||||
private $user;
|
||||
@@ -97,6 +98,24 @@ class BillFactory
|
||||
$this->updateNote($bill, $data['notes']);
|
||||
}
|
||||
|
||||
$objectGroupTitle = $data['object_group'] ?? '';
|
||||
if ('' !== $objectGroupTitle) {
|
||||
$objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle);
|
||||
if (null !== $objectGroup) {
|
||||
$bill->objectGroups()->sync([$objectGroup->id]);
|
||||
$bill->save();
|
||||
}
|
||||
}
|
||||
// try also with ID:
|
||||
$objectGroupId = (int) ($data['object_group_id'] ?? 0);
|
||||
if (0 !== $objectGroupId) {
|
||||
$objectGroup = $this->findObjectGroupById($objectGroupId);
|
||||
if (null !== $objectGroup) {
|
||||
$bill->objectGroups()->sync([$objectGroup->id]);
|
||||
$bill->save();
|
||||
}
|
||||
}
|
||||
|
||||
return $bill;
|
||||
}
|
||||
|
||||
|
@@ -367,19 +367,6 @@ class TransactionJournalFactory
|
||||
|
||||
// verify that journal has two transactions. Otherwise, delete and cancel.
|
||||
// TODO this can't be faked so it can't be tested.
|
||||
// $count = $journal->transactions()->count();
|
||||
// if (2 !== $count) {
|
||||
// // @codeCoverageIgnoreStart
|
||||
// Log::error(sprintf('The journal unexpectedly has %d transaction(s). This is not OK. Cancel operation.', $count));
|
||||
// try {
|
||||
// $journal->delete();
|
||||
// } catch (Exception $e) {
|
||||
// Log::debug(sprintf('Dont care: %s.', $e->getMessage()));
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// // @codeCoverageIgnoreEnd
|
||||
// }
|
||||
$journal->completed = true;
|
||||
$journal->save();
|
||||
|
||||
|
@@ -23,14 +23,58 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Handlers\Events;
|
||||
|
||||
use FireflyIII\Events\UpdatedTransactionGroup;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionJournal;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\TransactionRules\Engine\RuleEngine;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class UpdatedGroupEventHandler
|
||||
*/
|
||||
class UpdatedGroupEventHandler
|
||||
{
|
||||
/**
|
||||
* This method will make sure all source / destination accounts are the same.
|
||||
*
|
||||
* @param UpdatedTransactionGroup $updatedGroupEvent
|
||||
*/
|
||||
public function unifyAccounts(UpdatedTransactionGroup $updatedGroupEvent): void
|
||||
{
|
||||
$group = $updatedGroupEvent->transactionGroup;
|
||||
if (1 === $group->transactionJournals->count()) {
|
||||
return;
|
||||
}
|
||||
Log::debug(sprintf('Correct inconsistent accounts in group #%d', $group->id));
|
||||
// first journal:
|
||||
/** @var TransactionJournal $first */
|
||||
$first = $group->transactionJournals()
|
||||
->orderBy('transaction_journals.date', 'DESC')
|
||||
->orderBy('transaction_journals.order', 'ASC')
|
||||
->orderBy('transaction_journals.id', 'DESC')
|
||||
->orderBy('transaction_journals.description', 'DESC')
|
||||
->first();
|
||||
$all = $group->transactionJournals()->get()->pluck('id')->toArray();
|
||||
/** @var Account $sourceAccount */
|
||||
$sourceAccount = $first->transactions()->where('amount', '<', '0')->first()->account;
|
||||
/** @var Account $destAccount */
|
||||
$destAccount = $first->transactions()->where('amount', '>', '0')->first()->account;
|
||||
|
||||
$type = $first->transactionType->type;
|
||||
if (TransactionType::TRANSFER === $type || TransactionType::WITHDRAWAL === $type) {
|
||||
// set all source transactions to source account:
|
||||
Transaction::whereIn('transaction_journal_id', $all)
|
||||
->where('amount', '<', 0)->update(['account_id' => $sourceAccount->id]);
|
||||
}
|
||||
if (TransactionType::TRANSFER === $type || TransactionType::DEPOSIT === $type) {
|
||||
// set all destination transactions to destination account:
|
||||
Transaction::whereIn('transaction_journal_id', $all)
|
||||
->where('amount', '>', 0)->update(['account_id' => $destAccount->id]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will check all the rules when a journal is updated.
|
||||
*
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* AccountCollection.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector\Extensions;
|
||||
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* AmountCollection.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector\Extensions;
|
||||
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* CollectorProperties.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector\Extensions;
|
||||
|
||||
use FireflyIII\User;
|
||||
@@ -36,6 +38,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. */
|
||||
@@ -56,4 +60,6 @@ trait CollectorProperties
|
||||
private $total;
|
||||
/** @var User The user object. */
|
||||
private $user;
|
||||
|
||||
private bool $hasJoinedMetaTables;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* MetaCollection.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector\Extensions;
|
||||
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
@@ -28,6 +30,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 +39,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.
|
||||
@@ -288,4 +312,36 @@ trait MetaCollection
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setExternalId(string $externalId): GroupCollectorInterface
|
||||
{
|
||||
if (false === $this->hasJoinedMetaTables) {
|
||||
$this->hasJoinedMetaTables = true;
|
||||
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
|
||||
}
|
||||
$this->query->where('journal_meta.name', '=', 'external_id');
|
||||
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $externalId));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setInternalReference(string $internalReference): GroupCollectorInterface
|
||||
{
|
||||
if (false === $this->hasJoinedMetaTables) {
|
||||
$this->hasJoinedMetaTables = true;
|
||||
$this->query->leftJoin('journal_meta', 'transaction_journals.id', '=', 'journal_meta.transaction_journal_id');
|
||||
}
|
||||
|
||||
$this->query->where('journal_meta.name', '=', 'internal_reference');
|
||||
$this->query->where('journal_meta.data', 'LIKE', sprintf('%%%s%%', $internalReference));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TimeCollection.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Helpers\Collector\Extensions;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -62,8 +62,10 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$this->hasCatInformation = false;
|
||||
$this->hasBudgetInformation = false;
|
||||
$this->hasBillInformation = false;
|
||||
$this->hasNotesInformation = false;
|
||||
$this->hasJoinedTagTables = false;
|
||||
$this->hasJoinedAttTables = false;
|
||||
$this->hasJoinedMetaTables = false;
|
||||
$this->integerFields = [
|
||||
'transaction_group_id',
|
||||
'user_id',
|
||||
@@ -166,13 +168,8 @@ class GroupCollector implements GroupCollectorInterface
|
||||
*/
|
||||
public function getGroups(): Collection
|
||||
{
|
||||
//$start = microtime(true);
|
||||
/** @var Collection $result */
|
||||
$result = $this->query->get($this->fields);
|
||||
//$end = round(microtime(true) - $start, 5);
|
||||
// log info about query time.
|
||||
//Log::info(sprintf('Query took Firefly III %s seconds', $end));
|
||||
//Log::info($this->query->toSql(), $this->query->getBindings());
|
||||
|
||||
// now to parse this into an array.
|
||||
$collection = $this->parseArray($result);
|
||||
@@ -311,7 +308,7 @@ class GroupCollector implements GroupCollectorInterface
|
||||
$this->query->where(
|
||||
static function (EloquentBuilder $q) use ($array) {
|
||||
$q->where(
|
||||
function (EloquentBuilder $q1) use ($array) {
|
||||
static function (EloquentBuilder $q1) use ($array) {
|
||||
foreach ($array as $word) {
|
||||
$keyword = sprintf('%%%s%%', $word);
|
||||
$q1->where('transaction_journals.description', 'LIKE', $keyword);
|
||||
@@ -552,9 +549,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());
|
||||
}
|
||||
|
@@ -398,6 +398,13 @@ interface GroupCollectorInterface
|
||||
*/
|
||||
public function withCategoryInformation(): GroupCollectorInterface;
|
||||
|
||||
/**
|
||||
* Will include notes.
|
||||
*
|
||||
* @return GroupCollectorInterface
|
||||
*/
|
||||
public function withNotes(): GroupCollectorInterface;
|
||||
|
||||
/**
|
||||
* Add tag info.
|
||||
*
|
||||
@@ -419,4 +426,22 @@ interface GroupCollectorInterface
|
||||
*/
|
||||
public function withoutCategory(): GroupCollectorInterface;
|
||||
|
||||
/**
|
||||
* Look for specific external ID's.
|
||||
*
|
||||
* @param string $externalId
|
||||
*
|
||||
* @return GroupCollectorInterface
|
||||
*/
|
||||
public function setExternalId(string $externalId): GroupCollectorInterface;
|
||||
|
||||
/**
|
||||
* Look for specific external ID's.
|
||||
*
|
||||
* @param string $externalId
|
||||
*
|
||||
* @return GroupCollectorInterface
|
||||
*/
|
||||
public function setInternalReference(string $externalId): GroupCollectorInterface;
|
||||
|
||||
}
|
||||
|
@@ -77,7 +77,7 @@ class Help implements HelpInterface
|
||||
*/
|
||||
public function getFromGitHub(string $route, string $language): string
|
||||
{
|
||||
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/master/%s/%s.md', $language, $route);
|
||||
$uri = sprintf('https://raw.githubusercontent.com/firefly-iii/help/main/%s/%s.md', $language, $route);
|
||||
Log::debug(sprintf('Trying to get %s...', $uri));
|
||||
$opt = ['headers' => ['User-Agent' => $this->userAgent]];
|
||||
$content = '';
|
||||
|
@@ -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);
|
||||
}
|
||||
|
@@ -101,7 +101,7 @@ class IndexController extends Controller
|
||||
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||
$account->difference = bcsub($account->endBalance, $account->startBalance);
|
||||
$account->interest = round($this->repository->getMetaValue($account, 'interest'), 6);
|
||||
$account->interest = number_format((float) $this->repository->getMetaValue($account, 'interest'), 6, '.', '');
|
||||
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
|
||||
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
|
||||
}
|
||||
@@ -155,7 +155,7 @@ class IndexController extends Controller
|
||||
$account->startBalance = $this->isInArray($startBalances, $account->id);
|
||||
$account->endBalance = $this->isInArray($endBalances, $account->id);
|
||||
$account->difference = bcsub($account->endBalance, $account->startBalance);
|
||||
$account->interest = round($this->repository->getMetaValue($account, 'interest'), 6);
|
||||
$account->interest = number_format((float) $this->repository->getMetaValue($account, 'interest'), 6, '.', '');
|
||||
$account->interestPeriod = (string) trans(sprintf('firefly.interest_calc_%s', $this->repository->getMetaValue($account, 'interest_period')));
|
||||
$account->accountTypeString = (string) trans(sprintf('firefly.account_type_%s', $account->accountType->type));
|
||||
$account->location = $this->repository->getLocation($account);
|
||||
|
@@ -129,9 +129,8 @@ 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);
|
||||
$startBalance = number_format((float) app('steam')->balance($account, $startDate), $currency->decimal_places, '.', '');
|
||||
$endBalance = number_format((float) 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]);
|
||||
|
||||
|
@@ -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.
|
||||
|
@@ -25,7 +25,6 @@ namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Http\Middleware\IsSandStormUser;
|
||||
use FireflyIII\Http\Requests\ConfigurationRequest;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@@ -55,7 +54,6 @@ class ConfigurationController extends Controller
|
||||
}
|
||||
);
|
||||
$this->middleware(IsDemoUser::class)->except(['index']);
|
||||
$this->middleware(IsSandStormUser::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -25,7 +25,6 @@ namespace FireflyIII\Http\Controllers\Admin;
|
||||
use FireflyIII\Events\AdminRequestedTestMessage;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Http\Middleware\IsSandStormUser;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
@@ -48,7 +47,6 @@ class HomeController extends Controller
|
||||
{
|
||||
parent::__construct();
|
||||
$this->middleware(IsDemoUser::class)->except(['index']);
|
||||
$this->middleware(IsSandStormUser::class)->except(['index']);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,9 +59,8 @@ class HomeController extends Controller
|
||||
Log::channel('audit')->info('User visits admin index.');
|
||||
$title = (string) trans('firefly.administration');
|
||||
$mainTitleIcon = 'fa-hand-spock-o';
|
||||
$sandstorm = 1 === (int) getenv('SANDSTORM');
|
||||
|
||||
return view('admin.index', compact('title', 'mainTitleIcon', 'sandstorm'));
|
||||
return view('admin.index', compact('title', 'mainTitleIcon'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TelemetryController.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -26,7 +26,6 @@ namespace FireflyIII\Http\Controllers\Admin;
|
||||
use FireflyIII\Helpers\Update\UpdateTrait;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Http\Middleware\IsSandStormUser;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -57,7 +56,6 @@ class UpdateController extends Controller
|
||||
}
|
||||
);
|
||||
$this->middleware(IsDemoUser::class)->except(['index']);
|
||||
$this->middleware(IsSandStormUser::class)->except(['index']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -24,7 +24,6 @@ namespace FireflyIII\Http\Controllers\Admin;
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Middleware\IsDemoUser;
|
||||
use FireflyIII\Http\Middleware\IsSandStormUser;
|
||||
use FireflyIII\Http\Requests\UserFormRequest;
|
||||
use FireflyIII\Repositories\User\UserRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
@@ -57,7 +56,6 @@ class UserController extends Controller
|
||||
}
|
||||
);
|
||||
$this->middleware(IsDemoUser::class)->except(['index', 'show']);
|
||||
$this->middleware(IsSandStormUser::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,6 +1,4 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
/**
|
||||
* ConfirmPasswordController.php
|
||||
@@ -22,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Auth;
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
|
@@ -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('/');
|
||||
}
|
||||
|
||||
}
|
||||
|
130
app/Http/Controllers/Bill/CreateController.php
Normal file
130
app/Http/Controllers/Bill/CreateController.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CreateController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Bill;
|
||||
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\BillStoreRequest;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class CreateController
|
||||
*/
|
||||
class CreateController extends Controller
|
||||
{
|
||||
private AttachmentHelperInterface $attachments;
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->attachments = app(AttachmentHelperInterface::class);
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new bill.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
$periods = [];
|
||||
/** @var array $billPeriods */
|
||||
$billPeriods = config('firefly.bill_periods');
|
||||
foreach ($billPeriods as $current) {
|
||||
$periods[$current] = strtolower((string) trans('firefly.repeat_freq_' . $current));
|
||||
}
|
||||
$subTitle = (string) trans('firefly.create_new_bill');
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('bills.create.fromStore')) {
|
||||
$this->rememberPreviousUri('bills.create.uri');
|
||||
}
|
||||
$request->session()->forget('bills.create.fromStore');
|
||||
|
||||
return view('bills.create', compact('periods', 'subTitle', 'defaultCurrency'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a new bill.
|
||||
*
|
||||
* @param BillStoreRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*
|
||||
*/
|
||||
public function store(BillStoreRequest $request): RedirectResponse
|
||||
{
|
||||
$billData = $request->getBillData();
|
||||
$billData['active'] = true;
|
||||
try {
|
||||
$bill = $this->repository->store($billData);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$request->session()->flash('error', (string) trans('firefly.bill_store_error'));
|
||||
|
||||
return redirect(route('bills.create'))->withInput();
|
||||
}
|
||||
$request->session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
/** @var array $files */
|
||||
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
|
||||
if (null !== $files && !auth()->user()->hasRole('demo')) {
|
||||
$this->attachments->saveAttachmentsForModel($bill, $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
|
||||
}
|
||||
|
||||
return redirect(route('rules.create-from-bill', [$bill->id]));
|
||||
}
|
||||
}
|
99
app/Http/Controllers/Bill/DeleteController.php
Normal file
99
app/Http/Controllers/Bill/DeleteController.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DeleteController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Bill;
|
||||
|
||||
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\View\View;
|
||||
|
||||
/**
|
||||
* Class DeleteController
|
||||
*/
|
||||
class DeleteController extends Controller
|
||||
{
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('showBudget', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Delete a bill.
|
||||
*
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function delete(Bill $bill)
|
||||
{
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('bills.delete.uri');
|
||||
$subTitle = (string) trans('firefly.delete_bill', ['name' => $bill->name]);
|
||||
|
||||
return view('bills.delete', compact('bill', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function destroy(Request $request, Bill $bill)
|
||||
{
|
||||
$name = $bill->name;
|
||||
$this->repository->destroy($bill);
|
||||
|
||||
$request->session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('bills.delete.uri'));
|
||||
}
|
||||
}
|
155
app/Http/Controllers/Bill/EditController.php
Normal file
155
app/Http/Controllers/Bill/EditController.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* EditController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Bill;
|
||||
|
||||
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\BillUpdateRequest;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
/**
|
||||
* Class EditController
|
||||
*/
|
||||
class EditController extends Controller
|
||||
{
|
||||
private AttachmentHelperInterface $attachments;
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->attachments = app(AttachmentHelperInterface::class);
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Edit a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View
|
||||
*/
|
||||
public function edit(Request $request, Bill $bill)
|
||||
{
|
||||
$periods = [];
|
||||
/** @var array $billPeriods */
|
||||
$billPeriods = config('firefly.bill_periods');
|
||||
|
||||
foreach ($billPeriods as $current) {
|
||||
$periods[$current] = (string) trans('firefly.' . $current);
|
||||
}
|
||||
|
||||
$subTitle = (string) trans('firefly.edit_bill', ['name' => $bill->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('bills.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('bills.edit.uri');
|
||||
}
|
||||
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$bill->amount_min = round((float) $bill->amount_min, $currency->decimal_places);
|
||||
$bill->amount_max = round((float) $bill->amount_max, $currency->decimal_places);
|
||||
$rules = $this->repository->getRulesForBill($bill);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
|
||||
$preFilled = [
|
||||
'notes' => $this->repository->getNoteText($bill),
|
||||
'transaction_currency_id' => $bill->transaction_currency_id,
|
||||
'active' => $hasOldInput ? (bool) $request->old('active') : $bill->active,
|
||||
'object_group' => $bill->objectGroups->first() ? $bill->objectGroups->first()->title : '',
|
||||
];
|
||||
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
$request->session()->forget('bills.edit.fromUpdate');
|
||||
|
||||
return view('bills.edit', compact('subTitle', 'periods', 'rules', 'bill', 'defaultCurrency', 'preFilled'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update a bill.
|
||||
*
|
||||
* @param BillUpdateRequest $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function update(BillUpdateRequest $request, Bill $bill): RedirectResponse
|
||||
{
|
||||
$billData = $request->getBillData();
|
||||
$bill = $this->repository->update($bill, $billData);
|
||||
|
||||
$request->session()->flash('success', (string) trans('firefly.updated_bill', ['name' => $bill->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
/** @var array $files */
|
||||
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
|
||||
if (null !== $files && !auth()->user()->hasRole('demo')) {
|
||||
$this->attachments->saveAttachmentsForModel($bill, $files);
|
||||
}
|
||||
if (null !== $files && auth()->user()->hasRole('demo')) {
|
||||
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
|
||||
}
|
||||
|
||||
// flash messages
|
||||
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
|
||||
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
|
||||
}
|
||||
$redirect = redirect($this->getPreviousUri('bills.edit.uri'));
|
||||
|
||||
if (1 === (int) $request->get('return_to_edit')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('bills.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('bills.edit', [$bill->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
}
|
247
app/Http/Controllers/Bill/IndexController.php
Normal file
247
app/Http/Controllers/Bill/IndexController.php
Normal file
@@ -0,0 +1,247 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* IndexController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Bill;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\ObjectGroup\OrganisesObjectGroups;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
* Class IndexController
|
||||
*/
|
||||
class IndexController extends Controller
|
||||
{
|
||||
use OrganisesObjectGroups;
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all bills.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->cleanupObjectGroups();
|
||||
$this->repository->correctOrder();
|
||||
|
||||
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
$collection = $this->repository->getBills();
|
||||
$total = $collection->count();
|
||||
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$parameters = new ParameterBag;
|
||||
$parameters->set('start', $start);
|
||||
$parameters->set('end', $end);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($parameters);
|
||||
|
||||
// loop all bills, convert to array and add rules and stuff.
|
||||
$rules = $this->repository->getRulesForBills($collection);
|
||||
|
||||
// make bill groups:
|
||||
$bills = [
|
||||
0 => [ // the index is the order, not the ID.
|
||||
'object_group_id' => 0,
|
||||
'object_group_title' => (string) trans('firefly.default_group_title_name'),
|
||||
'bills' => [],
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
/** @var Bill $bill */
|
||||
foreach ($collection as $bill) {
|
||||
$array = $transformer->transform($bill);
|
||||
$groupOrder = (int) $array['object_group_order'];
|
||||
// make group array if necessary:
|
||||
$bills[$groupOrder] = $bills[$groupOrder] ?? [
|
||||
'object_group_id' => $array['object_group_id'],
|
||||
'object_group_title' => $array['object_group_title'],
|
||||
'bills' => [],
|
||||
];
|
||||
|
||||
$nextExpectedMatch = new Carbon($array['next_expected_match']);
|
||||
$array['next_expected_match_diff'] = $nextExpectedMatch->isToday()
|
||||
? trans('firefly.today')
|
||||
: $nextExpectedMatch->diffForHumans(
|
||||
today(), Carbon::DIFF_RELATIVE_TO_NOW
|
||||
);
|
||||
$currency = $bill->transactionCurrency ?? $defaultCurrency;
|
||||
$array['currency_id'] = $currency->id;
|
||||
$array['currency_name'] = $currency->name;
|
||||
$array['currency_symbol'] = $currency->symbol;
|
||||
$array['currency_code'] = $currency->code;
|
||||
$array['currency_decimal_places'] = $currency->decimal_places;
|
||||
$array['attachments'] = $this->repository->getAttachments($bill);
|
||||
$array['rules'] = $rules[$bill['id']] ?? [];
|
||||
$bills[$groupOrder]['bills'][] = $array;
|
||||
}
|
||||
|
||||
// order by key
|
||||
ksort($bills);
|
||||
|
||||
// summarise per currency / per group.
|
||||
$sums = $this->getSums($bills);
|
||||
|
||||
return view('bills.index', compact('bills', 'sums', 'total'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $bills
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getSums(array $bills): array
|
||||
{
|
||||
$sums = [];
|
||||
$range = app('preferences')->get('viewRange', '1M')->data;
|
||||
|
||||
/** @var array $group */
|
||||
foreach ($bills as $groupOrder => $group) {
|
||||
/** @var array $bill */
|
||||
foreach ($group['bills'] as $bill) {
|
||||
if (false === $bill['active']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var TransactionCurrency $currency */
|
||||
$currencyId = $bill['currency_id'];
|
||||
$sums[$groupOrder][$currencyId] = $sums[$groupOrder][$currencyId] ?? [
|
||||
'currency_id' => $currencyId,
|
||||
'currency_code' => $bill['currency_code'],
|
||||
'currency_name' => $bill['currency_name'],
|
||||
'currency_symbol' => $bill['currency_symbol'],
|
||||
'currency_decimal_places' => $bill['currency_decimal_places'],
|
||||
'avg' => '0',
|
||||
'period' => $range,
|
||||
'per_period' => '0',
|
||||
];
|
||||
// only fill in avg when bill is active.
|
||||
if (count($bill['pay_dates']) > 0) {
|
||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
||||
$avg = bcmul($avg, (string) count($bill['pay_dates']));
|
||||
$sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg);
|
||||
}
|
||||
// fill in per period regardless:
|
||||
$sums[$groupOrder][$currencyId]['per_period'] = bcadd($sums[$groupOrder][$currencyId]['per_period'], $this->amountPerPeriod($bill, $range));
|
||||
}
|
||||
}
|
||||
|
||||
return $sums;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $bill
|
||||
* @param string $range
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function amountPerPeriod(array $bill, string $range): string
|
||||
{
|
||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
||||
|
||||
Log::debug(sprintf('Amount per period for bill #%d "%s"', $bill['id'], $bill['name']));
|
||||
Log::debug(sprintf(sprintf('Average is %s', $avg)));
|
||||
// calculate amount per year:
|
||||
$multiplies = [
|
||||
'yearly' => '1',
|
||||
'half-year' => '2',
|
||||
'quarterly' => '4',
|
||||
'monthly' => '12',
|
||||
'weekly' => '52.17',
|
||||
];
|
||||
$yearAmount = bcmul($avg, $multiplies[$bill['repeat_freq']]);
|
||||
Log::debug(sprintf('Amount per year is %s (%s * %s)', $yearAmount, $avg, $multiplies[$bill['repeat_freq']]));
|
||||
|
||||
// per period:
|
||||
$division = [
|
||||
'1Y' => '1',
|
||||
'6M' => '2',
|
||||
'3M' => '4',
|
||||
'1M' => '12',
|
||||
'1W' => '52.16',
|
||||
'1D' => '365.24',
|
||||
];
|
||||
$perPeriod = bcdiv($yearAmount, $division[$range]);
|
||||
|
||||
Log::debug(sprintf('Amount per %s is %s (%s / %s)', $range, $perPeriod, $yearAmount, $division[$range]));
|
||||
|
||||
return $perPeriod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the order of a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function setOrder(Request $request, Bill $bill): JsonResponse
|
||||
{
|
||||
$objectGroupTitle = (string)$request->get('objectGroupTitle');
|
||||
$newOrder = (int) $request->get('order');
|
||||
$this->repository->setOrder($bill, $newOrder);
|
||||
if ('' !== $objectGroupTitle) {
|
||||
$this->repository->setObjectGroup($bill, $objectGroupTitle);
|
||||
}
|
||||
if ('' === $objectGroupTitle) {
|
||||
$this->repository->removeObjectGroup($bill);
|
||||
}
|
||||
|
||||
return response()->json(['data' => 'OK']);
|
||||
}
|
||||
}
|
195
app/Http/Controllers/Bill/ShowController.php
Normal file
195
app/Http/Controllers/Bill/ShowController.php
Normal file
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/**
|
||||
* ShowController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Bill;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\TransactionRules\TransactionMatcher;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\View\View;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\DataArraySerializer;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
* Class ShowController
|
||||
*/
|
||||
class ShowController extends Controller
|
||||
{
|
||||
private BillRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('showBudget', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->repository = app(BillRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Rescan bills for transactions.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function rescan(Request $request, Bill $bill)
|
||||
{
|
||||
$total = 0;
|
||||
if (false === $bill->active) {
|
||||
$request->session()->flash('warning', (string) trans('firefly.cannot_scan_inactive_bill'));
|
||||
|
||||
return redirect(route('bills.show', [$bill->id]));
|
||||
}
|
||||
$set = new Collection;
|
||||
if (true === $bill->active) {
|
||||
$set = $this->repository->getRulesForBill($bill);
|
||||
$total = 0;
|
||||
}
|
||||
if (0 === $set->count()) {
|
||||
$request->session()->flash('error', (string) trans('firefly.no_rules_for_bill'));
|
||||
|
||||
return redirect(route('bills.show', [$bill->id]));
|
||||
}
|
||||
|
||||
// unlink all journals:
|
||||
$this->repository->unlinkAll($bill);
|
||||
|
||||
foreach ($set as $rule) {
|
||||
// simply fire off all rules?
|
||||
/** @var TransactionMatcher $matcher */
|
||||
$matcher = app(TransactionMatcher::class);
|
||||
$matcher->setSearchLimit(100000); // large upper limit
|
||||
$matcher->setTriggeredLimit(100000); // large upper limit
|
||||
$matcher->setRule($rule);
|
||||
$matchingTransactions = $matcher->findTransactionsByRule();
|
||||
$total += count($matchingTransactions);
|
||||
$this->repository->linkCollectionToBill($bill, $matchingTransactions);
|
||||
}
|
||||
|
||||
|
||||
$request->session()->flash('success', (string) trans_choice('firefly.rescanned_bill', $total));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect(route('bills.show', [$bill->id]));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Show a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function show(Request $request, Bill $bill)
|
||||
{
|
||||
// add info about rules:
|
||||
$rules = $this->repository->getRulesForBill($bill);
|
||||
$subTitle = $bill->name;
|
||||
/** @var Carbon $start */
|
||||
$start = session('start');
|
||||
/** @var Carbon $end */
|
||||
$end = session('end');
|
||||
$year = $start->year;
|
||||
$page = (int) $request->get('page');
|
||||
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
||||
$yearAverage = $this->repository->getYearAverage($bill, $start);
|
||||
$overallAverage = $this->repository->getOverallAverage($bill);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new DataArraySerializer());
|
||||
$manager->parseIncludes(['attachments', 'notes']);
|
||||
|
||||
// Make a resource out of the data and
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('start', $start);
|
||||
$parameters->set('end', $end);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($parameters);
|
||||
|
||||
$resource = new Item($bill, $transformer, 'bill');
|
||||
$object = $manager->createData($resource)->toArray();
|
||||
$object['data']['currency'] = $bill->transactionCurrency;
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setBill($bill)->setLimit($pageSize)->setPage($page)->withBudgetInformation()
|
||||
->withCategoryInformation()->withAccountInformation();
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath(route('bills.show', [$bill->id]));
|
||||
|
||||
// transform any attachments as well.
|
||||
$collection = $this->repository->getAttachments($bill);
|
||||
$attachments = new Collection;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($collection->count() > 0) {
|
||||
/** @var AttachmentTransformer $transformer */
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
$attachments = $collection->each(
|
||||
static function (Attachment $attachment) use ($transformer) {
|
||||
return $transformer->transform($attachment);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
|
||||
return view('bills.show', compact('attachments', 'groups', 'rules', 'yearAverage', 'overallAverage', 'year', 'object', 'bill', 'subTitle'));
|
||||
}
|
||||
|
||||
}
|
@@ -1,477 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* BillController.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\Exceptions\FireflyException;
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Http\Requests\BillFormRequest;
|
||||
use FireflyIII\Models\Attachment;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\TransactionRules\TransactionMatcher;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Redirector;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\View\View;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Resource\Item;
|
||||
use League\Fractal\Serializer\DataArraySerializer;
|
||||
use Log;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
* Class BillController.
|
||||
*
|
||||
*/
|
||||
class BillController extends Controller
|
||||
{
|
||||
/** @var AttachmentHelperInterface Helper for attachments. */
|
||||
private $attachments;
|
||||
/** @var BillRepositoryInterface Bill repository */
|
||||
private $billRepository;
|
||||
|
||||
/**
|
||||
* BillController constructor.
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
app('view')->share('showBudget', true);
|
||||
|
||||
$this->middleware(
|
||||
function ($request, $next) {
|
||||
app('view')->share('title', (string) trans('firefly.bills'));
|
||||
app('view')->share('mainTitleIcon', 'fa-calendar-o');
|
||||
$this->attachments = app(AttachmentHelperInterface::class);
|
||||
$this->billRepository = app(BillRepositoryInterface::class);
|
||||
|
||||
return $next($request);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new bill.
|
||||
*
|
||||
* @param Request $request
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function create(Request $request)
|
||||
{
|
||||
$periods = [];
|
||||
/** @var array $billPeriods */
|
||||
$billPeriods = config('firefly.bill_periods');
|
||||
foreach ($billPeriods as $current) {
|
||||
$periods[$current] = strtolower((string) trans('firefly.repeat_freq_' . $current));
|
||||
}
|
||||
$subTitle = (string) trans('firefly.create_new_bill');
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
|
||||
// put previous url in session if not redirect from store (not "create another").
|
||||
if (true !== session('bills.create.fromStore')) {
|
||||
$this->rememberPreviousUri('bills.create.uri');
|
||||
}
|
||||
$request->session()->forget('bills.create.fromStore');
|
||||
|
||||
return view('bills.create', compact('periods', 'subTitle', 'defaultCurrency'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a bill.
|
||||
*
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function delete(Bill $bill)
|
||||
{
|
||||
// put previous url in session
|
||||
$this->rememberPreviousUri('bills.delete.uri');
|
||||
$subTitle = (string) trans('firefly.delete_bill', ['name' => $bill->name]);
|
||||
|
||||
return view('bills.delete', compact('bill', 'subTitle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function destroy(Request $request, Bill $bill)
|
||||
{
|
||||
$name = $bill->name;
|
||||
$this->billRepository->destroy($bill);
|
||||
|
||||
$request->session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect($this->getPreviousUri('bills.delete.uri'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Edit a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function edit(Request $request, Bill $bill)
|
||||
{
|
||||
$periods = [];
|
||||
/** @var array $billPeriods */
|
||||
$billPeriods = config('firefly.bill_periods');
|
||||
|
||||
foreach ($billPeriods as $current) {
|
||||
$periods[$current] = (string) trans('firefly.' . $current);
|
||||
}
|
||||
|
||||
$subTitle = (string) trans('firefly.edit_bill', ['name' => $bill->name]);
|
||||
|
||||
// put previous url in session if not redirect from store (not "return_to_edit").
|
||||
if (true !== session('bills.edit.fromUpdate')) {
|
||||
$this->rememberPreviousUri('bills.edit.uri');
|
||||
}
|
||||
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$bill->amount_min = round((float) $bill->amount_min, $currency->decimal_places);
|
||||
$bill->amount_max = round((float) $bill->amount_max, $currency->decimal_places);
|
||||
$rules = $this->billRepository->getRulesForBill($bill);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
|
||||
// code to handle active-checkboxes
|
||||
$hasOldInput = null !== $request->old('_token');
|
||||
|
||||
$preFilled = [
|
||||
'notes' => $this->billRepository->getNoteText($bill),
|
||||
'transaction_currency_id' => $bill->transaction_currency_id,
|
||||
'active' => $hasOldInput ? (bool) $request->old('active') : $bill->active,
|
||||
];
|
||||
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
$request->session()->forget('bills.edit.fromUpdate');
|
||||
|
||||
return view('bills.edit', compact('subTitle', 'periods', 'rules', 'bill', 'defaultCurrency', 'preFilled'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show all bills.
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$start = session('start');
|
||||
$end = session('end');
|
||||
$unfiltered = $this->billRepository->getBills();
|
||||
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('start', $start);
|
||||
$parameters->set('end', $end);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($parameters);
|
||||
|
||||
/** @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 $return;
|
||||
}
|
||||
);
|
||||
|
||||
// add info about rules:
|
||||
$rules = $this->billRepository->getRulesForBills($unfiltered);
|
||||
$bills = $bills->map(
|
||||
static function (array $bill) use ($rules) {
|
||||
$bill['rules'] = $rules[$bill['id']] ?? [];
|
||||
|
||||
return $bill;
|
||||
}
|
||||
);
|
||||
|
||||
// summarise per currency:
|
||||
$sums = $this->getSums($bills);
|
||||
|
||||
return view('bills.index', compact('bills', 'sums'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Rescan bills for transactions.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function rescan(Request $request, Bill $bill)
|
||||
{
|
||||
$total = 0;
|
||||
if (false === $bill->active) {
|
||||
$request->session()->flash('warning', (string) trans('firefly.cannot_scan_inactive_bill'));
|
||||
|
||||
return redirect(route('bills.show', [$bill->id]));
|
||||
}
|
||||
$set = new Collection;
|
||||
if (true === $bill->active) {
|
||||
$set = $this->billRepository->getRulesForBill($bill);
|
||||
$total = 0;
|
||||
}
|
||||
if (0 === $set->count()) {
|
||||
$request->session()->flash('error', (string) trans('firefly.no_rules_for_bill'));
|
||||
|
||||
return redirect(route('bills.show', [$bill->id]));
|
||||
}
|
||||
|
||||
// unlink all journals:
|
||||
$this->billRepository->unlinkAll($bill);
|
||||
|
||||
foreach ($set as $rule) {
|
||||
// simply fire off all rules?
|
||||
/** @var TransactionMatcher $matcher */
|
||||
$matcher = app(TransactionMatcher::class);
|
||||
$matcher->setSearchLimit(100000); // large upper limit
|
||||
$matcher->setTriggeredLimit(100000); // large upper limit
|
||||
$matcher->setRule($rule);
|
||||
$matchingTransactions = $matcher->findTransactionsByRule();
|
||||
$total += count($matchingTransactions);
|
||||
$this->billRepository->linkCollectionToBill($bill, $matchingTransactions);
|
||||
}
|
||||
|
||||
|
||||
$request->session()->flash('success', (string) trans_choice('firefly.rescanned_bill', $total));
|
||||
app('preferences')->mark();
|
||||
|
||||
return redirect(route('bills.show', [$bill->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a bill.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return Factory|View
|
||||
*/
|
||||
public function show(Request $request, Bill $bill)
|
||||
{
|
||||
// add info about rules:
|
||||
$rules = $this->billRepository->getRulesForBill($bill);
|
||||
$subTitle = $bill->name;
|
||||
/** @var Carbon $start */
|
||||
$start = session('start');
|
||||
/** @var Carbon $end */
|
||||
$end = session('end');
|
||||
$year = $start->year;
|
||||
$page = (int) $request->get('page');
|
||||
$pageSize = (int) app('preferences')->get('listPageSize', 50)->data;
|
||||
$yearAverage = $this->billRepository->getYearAverage($bill, $start);
|
||||
$overallAverage = $this->billRepository->getOverallAverage($bill);
|
||||
$manager = new Manager();
|
||||
$manager->setSerializer(new DataArraySerializer());
|
||||
$manager->parseIncludes(['attachments', 'notes']);
|
||||
|
||||
// Make a resource out of the data and
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('start', $start);
|
||||
$parameters->set('end', $end);
|
||||
|
||||
/** @var BillTransformer $transformer */
|
||||
$transformer = app(BillTransformer::class);
|
||||
$transformer->setParameters($parameters);
|
||||
|
||||
$resource = new Item($bill, $transformer, 'bill');
|
||||
$object = $manager->createData($resource)->toArray();
|
||||
$object['data']['currency'] = $bill->transactionCurrency;
|
||||
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setBill($bill)->setLimit($pageSize)->setPage($page)->withBudgetInformation()
|
||||
->withCategoryInformation()->withAccountInformation();
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath(route('bills.show', [$bill->id]));
|
||||
|
||||
// transform any attachments as well.
|
||||
$collection = $this->billRepository->getAttachments($bill);
|
||||
$attachments = new Collection;
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if ($collection->count() > 0) {
|
||||
/** @var AttachmentTransformer $transformer */
|
||||
$transformer = app(AttachmentTransformer::class);
|
||||
$attachments = $collection->each(
|
||||
static function (Attachment $attachment) use ($transformer) {
|
||||
return $transformer->transform($attachment);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
|
||||
return view('bills.show', compact('attachments', 'groups', 'rules', 'yearAverage', 'overallAverage', 'year', 'object', 'bill', 'subTitle'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store a new bill.
|
||||
*
|
||||
* @param BillFormRequest $request
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*
|
||||
*/
|
||||
public function store(BillFormRequest $request): RedirectResponse
|
||||
{
|
||||
$billData = $request->getBillData();
|
||||
$billData['active'] = true;
|
||||
try {
|
||||
$bill = $this->billRepository->store($billData);
|
||||
} catch (FireflyException $e) {
|
||||
Log::error($e->getMessage());
|
||||
$request->session()->flash('error', (string) trans('firefly.bill_store_error'));
|
||||
|
||||
return redirect(route('bills.create'))->withInput();
|
||||
}
|
||||
$request->session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
/** @var array $files */
|
||||
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
|
||||
if (null !== $files && !auth()->user()->hasRole('demo')) {
|
||||
$this->attachments->saveAttachmentsForModel($bill, $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
|
||||
}
|
||||
|
||||
return redirect(route('rules.create-from-bill', [$bill->id]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a bill.
|
||||
*
|
||||
* @param BillFormRequest $request
|
||||
* @param Bill $bill
|
||||
*
|
||||
* @return RedirectResponse
|
||||
*/
|
||||
public function update(BillFormRequest $request, Bill $bill): RedirectResponse
|
||||
{
|
||||
$billData = $request->getBillData();
|
||||
$bill = $this->billRepository->update($bill, $billData);
|
||||
|
||||
$request->session()->flash('success', (string) trans('firefly.updated_bill', ['name' => $bill->name]));
|
||||
app('preferences')->mark();
|
||||
|
||||
/** @var array $files */
|
||||
$files = $request->hasFile('attachments') ? $request->file('attachments') : null;
|
||||
if (null !== $files && !auth()->user()->hasRole('demo')) {
|
||||
$this->attachments->saveAttachmentsForModel($bill, $files);
|
||||
}
|
||||
if (null !== $files && auth()->user()->hasRole('demo')) {
|
||||
session()->flash('info',(string)trans('firefly.no_att_demo_user'));
|
||||
}
|
||||
|
||||
// flash messages
|
||||
if (count($this->attachments->getMessages()->get('attachments')) > 0) {
|
||||
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
|
||||
}
|
||||
$redirect = redirect($this->getPreviousUri('bills.edit.uri'));
|
||||
|
||||
if (1 === (int) $request->get('return_to_edit')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$request->session()->put('bills.edit.fromUpdate', true);
|
||||
|
||||
$redirect = redirect(route('bills.edit', [$bill->id]))->withInput(['return_to_edit' => 1]);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $redirect;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $bills
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getSums(Collection $bills): array
|
||||
{
|
||||
$sums = [];
|
||||
|
||||
/** @var array $bill */
|
||||
foreach ($bills as $bill) {
|
||||
if (false === $bill['active']) {
|
||||
continue;
|
||||
}
|
||||
if (0 === count($bill['pay_dates'])) {
|
||||
continue;
|
||||
}
|
||||
/** @var TransactionCurrency $currency */
|
||||
$currencyId = $bill['currency_id'];
|
||||
$sums[$currencyId] = $sums[$currencyId] ?? [
|
||||
'currency_id' => $currencyId,
|
||||
'currency_code' => $bill['currency_code'],
|
||||
'currency_name' => $bill['currency_name'],
|
||||
'currency_symbol' => $bill['currency_symbol'],
|
||||
'currency_decimal_places' => $bill['currency_decimal_places'],
|
||||
'avg' => '0',
|
||||
];
|
||||
|
||||
$avg = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2');
|
||||
$avg = bcmul($avg, (string) count($bill['pay_dates']));
|
||||
$sums[$currencyId]['avg'] = bcadd($sums[$currencyId]['avg'], $avg);
|
||||
}
|
||||
|
||||
return $sums;
|
||||
}
|
||||
}
|
@@ -157,7 +157,7 @@ class AvailableBudgetController extends Controller
|
||||
*/
|
||||
public function edit(AvailableBudget $availableBudget, Carbon $start, Carbon $end)
|
||||
{
|
||||
$availableBudget->amount = round($availableBudget->amount, $availableBudget->transactionCurrency->decimal_places);
|
||||
$availableBudget->amount = number_format((float) $availableBudget->amount, $availableBudget->transactionCurrency->decimal_places, '.', '');
|
||||
return view('budgets.available-budgets.edit', compact('availableBudget', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
@@ -213,7 +213,7 @@ class BudgetLimitController extends Controller
|
||||
$array['left_per_day'] = bcdiv(bcadd($array['spent'], $array['amount']), $array['days_left']);
|
||||
|
||||
// left per day formatted.
|
||||
$array['amount'] = round($limit['amount'], $limit->transactionCurrency->decimal_places);
|
||||
$array['amount'] = number_format((float) $limit['amount'], $limit->transactionCurrency->decimal_places, '.', '');
|
||||
$array['left_per_day_formatted'] = app('amount')->formatAnything($limit->transactionCurrency, $array['left_per_day']);
|
||||
|
||||
return response()->json($array);
|
||||
|
@@ -174,7 +174,7 @@ class IndexController extends Controller
|
||||
$currency = $limit->transactionCurrency ?? $defaultCurrency;
|
||||
$array['budgeted'][] = [
|
||||
'id' => $limit->id,
|
||||
'amount' => round($limit->amount, $currency->decimal_places),
|
||||
'amount' => number_format((float) $limit->amount, $currency->decimal_places, '.', ''),
|
||||
'start_date' => $limit->start_date->formatLocalized($this->monthAndDayFormat),
|
||||
'end_date' => $limit->end_date->formatLocalized($this->monthAndDayFormat),
|
||||
'in_range' => $limit->start_date->isSameDay($start) && $limit->end_date->isSameDay($end),
|
||||
|
@@ -84,8 +84,6 @@ class ShowController extends Controller
|
||||
*/
|
||||
public function noBudget(Request $request, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
|
||||
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start');
|
||||
/** @var Carbon $end */
|
||||
@@ -211,7 +209,7 @@ class ShowController extends Controller
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
|
||||
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)
|
||||
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)->withAccountInformation()
|
||||
->setBudget($budget)->setLimit($pageSize)->setPage($page)->withBudgetInformation()->withCategoryInformation();
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath(route('budgets.show', [$budget->id, $budgetLimit->id]));
|
||||
|
@@ -79,7 +79,6 @@ class ShowController extends Controller
|
||||
*/
|
||||
public function show(Request $request, Category $category, Carbon $start = null, Carbon $end = null)
|
||||
{
|
||||
//Log::debug('Now in show()');
|
||||
/** @var Carbon $start */
|
||||
$start = $start ?? session('start', Carbon::now()->startOfMonth());
|
||||
/** @var Carbon $end */
|
||||
@@ -106,8 +105,6 @@ class ShowController extends Controller
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath($path);
|
||||
|
||||
//Log::debug('End of show()');
|
||||
|
||||
return view('categories.show', compact('category','attachments', 'groups', 'periods', 'subTitle', 'subTitleIcon', 'start', 'end'));
|
||||
}
|
||||
|
||||
|
@@ -111,7 +111,6 @@ class BudgetController extends Controller
|
||||
$loopStart = app('navigation')->startOfPeriod($loopStart, $step);
|
||||
$currencies = [];
|
||||
$defaultEntries = [];
|
||||
// echo '<hr>';
|
||||
while ($end >= $loopStart) {
|
||||
/** @var Carbon $currentEnd */
|
||||
$loopEnd = app('navigation')->endOfPeriod($loopStart, $step);
|
||||
@@ -217,7 +216,6 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($budgetLimitId);
|
||||
$cache->addProperty('chart.budget.expense-asset');
|
||||
$collector->setRange(session()->get('start'), session()->get('end'));
|
||||
$start = session()->get('start');
|
||||
$end = session()->get('end');
|
||||
if (null !== $budgetLimit) {
|
||||
@@ -231,6 +229,7 @@ class BudgetController extends Controller
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$collector->setRange($start, $end);
|
||||
$collector->setBudget($budget);
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$result = [];
|
||||
@@ -283,13 +282,12 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($budgetLimitId);
|
||||
$cache->addProperty('chart.budget.expense-category');
|
||||
$collector->setRange(session()->get('start'), session()->get('end'));
|
||||
$start = session()->get('start');
|
||||
$end = session()->get('end');
|
||||
if (null !== $budgetLimit) {
|
||||
$start = $budgetLimit->start_date;
|
||||
$end = $budgetLimit->end_date;
|
||||
$collector->setRange($budgetLimit->start_date, $budgetLimit->end_date)->setCurrency($budgetLimit->transactionCurrency);
|
||||
$collector->setCurrency($budgetLimit->transactionCurrency);
|
||||
}
|
||||
$cache->addProperty($start);
|
||||
$cache->addProperty($end);
|
||||
@@ -297,6 +295,7 @@ class BudgetController extends Controller
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
$collector->setRange($start, $end);
|
||||
$collector->setBudget($budget)->withCategoryInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$result = [];
|
||||
@@ -346,7 +345,6 @@ class BudgetController extends Controller
|
||||
$cache->addProperty($budget->id);
|
||||
$cache->addProperty($budgetLimitId);
|
||||
$cache->addProperty('chart.budget.expense-expense');
|
||||
$collector->setRange(session()->get('start'), session()->get('end'));
|
||||
$start = session()->get('start');
|
||||
$end = session()->get('end');
|
||||
if (null !== $budgetLimit) {
|
||||
@@ -360,7 +358,7 @@ class BudgetController extends Controller
|
||||
if ($cache->has()) {
|
||||
return response()->json($cache->get()); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$collector->setRange($start, $end);
|
||||
$collector->setTypes([TransactionType::WITHDRAWAL])->setBudget($budget)->withAccountInformation();
|
||||
$journals = $collector->getExtractedJournals();
|
||||
$result = [];
|
||||
|
@@ -85,8 +85,6 @@ class CategoryController extends Controller
|
||||
$start = app('navigation')->startOfPeriod($start, $range);
|
||||
$end = $this->getDate();
|
||||
|
||||
//Log::debug(sprintf('Full range is %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
|
||||
|
||||
/** @var WholePeriodChartGenerator $generator */
|
||||
$generator = app(WholePeriodChartGenerator::class);
|
||||
$chartData = $generator->generate($category, $start, $end);
|
||||
|
@@ -64,61 +64,6 @@ class CategoryReportController extends Controller
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// /**
|
||||
// * Chart for expenses grouped by expense account.
|
||||
// *
|
||||
// * TODO this chart is not multi-currency aware.
|
||||
// *
|
||||
// * @param Collection $accounts
|
||||
// * @param Collection $categories
|
||||
// * @param Carbon $start
|
||||
// * @param Carbon $end
|
||||
// * @param string $others
|
||||
// *
|
||||
// * @return JsonResponse
|
||||
// */
|
||||
// public function accountExpense(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others): JsonResponse
|
||||
// {
|
||||
// /** @var MetaPieChartInterface $helper */
|
||||
// $helper = app(MetaPieChartInterface::class);
|
||||
// $helper->setAccounts($accounts)->setCategories($categories)->setStart($start)->setEnd($end)->setCollectOtherObjects(1 === (int)$others);
|
||||
//
|
||||
// $chartData = $helper->generate('expense', 'account');
|
||||
// $data = $this->generator->pieChart($chartData);
|
||||
//
|
||||
// return response()->json($data);
|
||||
// }
|
||||
|
||||
//
|
||||
// /**
|
||||
// * Chart for income grouped by revenue account.
|
||||
// *
|
||||
// * TODO this chart is not multi-currency aware.
|
||||
// *
|
||||
// * @param Collection $accounts
|
||||
// * @param Collection $categories
|
||||
// * @param Carbon $start
|
||||
// * @param Carbon $end
|
||||
// * @param string $others
|
||||
// *
|
||||
// * @return JsonResponse
|
||||
// */
|
||||
// public function accountIncome(Collection $accounts, Collection $categories, Carbon $start, Carbon $end, string $others): JsonResponse
|
||||
// {
|
||||
// /** @var MetaPieChartInterface $helper */
|
||||
// $helper = app(MetaPieChartInterface::class);
|
||||
// $helper->setAccounts($accounts);
|
||||
// $helper->setCategories($categories);
|
||||
// $helper->setStart($start);
|
||||
// $helper->setEnd($end);
|
||||
// $helper->setCollectOtherObjects(1 === (int)$others);
|
||||
// $chartData = $helper->generate('income', 'account');
|
||||
// $data = $this->generator->pieChart($chartData);
|
||||
//
|
||||
// return response()->json($data);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param Collection $accounts
|
||||
* @param Collection $categories
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* TransactionController.php
|
||||
* Copyright (c) 2020 thegrumpydictator@gmail.com
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Chart;
|
||||
|
||||
use Carbon\Carbon;
|
||||
|
@@ -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'));
|
||||
|
@@ -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 = ' ';
|
||||
|
@@ -1,8 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* IndexController.php
|
||||
* Copyright (c) 2019 james@firefly-iii.org
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Export;
|
||||
|
||||
|
||||
|
@@ -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]));
|
||||
}
|
||||
|
||||
}
|
@@ -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'));
|
||||
}
|
||||
}
|
@@ -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]));
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -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']);
|
||||
}
|
||||
}
|
@@ -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]));
|
||||
|
||||
|
||||
}
|
||||
}
|
@@ -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.
|
||||
*
|
||||
|
@@ -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
|
||||
@@ -361,6 +391,7 @@ class AutoCompleteController extends Controller
|
||||
foreach ($piggies as $piggy) {
|
||||
$currency = $accountRepos->getAccountCurrency($piggy->account) ?? $defaultCurrency;
|
||||
$currentAmount = $repository->getRepetition($piggy)->currentamount ?? '0';
|
||||
$piggy->objectGroup = $piggy->objectGroups->first();
|
||||
$piggy->name_with_amount = sprintf(
|
||||
'%s (%s / %s)',
|
||||
$piggy->name,
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* BudgetController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
@@ -20,6 +20,8 @@ declare(strict_types=1);
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Json;
|
||||
|
||||
|
||||
|
91
app/Http/Controllers/ObjectGroup/DeleteController.php
Normal file
91
app/Http/Controllers/ObjectGroup/DeleteController.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DeleteController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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'));
|
||||
}
|
||||
|
||||
}
|
108
app/Http/Controllers/ObjectGroup/EditController.php
Normal file
108
app/Http/Controllers/ObjectGroup/EditController.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* EditController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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;
|
||||
}
|
||||
}
|
87
app/Http/Controllers/ObjectGroup/IndexController.php
Normal file
87
app/Http/Controllers/ObjectGroup/IndexController.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* IndexController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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->deleteEmpty();
|
||||
$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([]);
|
||||
}
|
||||
|
||||
}
|
221
app/Http/Controllers/PiggyBank/AmountController.php
Normal file
221
app/Http/Controllers/PiggyBank/AmountController.php
Normal file
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* AmountController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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 = number_format((float) $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'));
|
||||
}
|
||||
}
|
133
app/Http/Controllers/PiggyBank/CreateController.php
Normal file
133
app/Http/Controllers/PiggyBank/CreateController.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* CreateController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\PiggyBank;
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\PiggyBankStoreRequest;
|
||||
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 PiggyBankStoreRequest $request
|
||||
*
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function store(PiggyBankStoreRequest $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;
|
||||
}
|
||||
}
|
96
app/Http/Controllers/PiggyBank/DeleteController.php
Normal file
96
app/Http/Controllers/PiggyBank/DeleteController.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* DeleteController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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'));
|
||||
}
|
||||
}
|
154
app/Http/Controllers/PiggyBank/EditController.php
Normal file
154
app/Http/Controllers/PiggyBank/EditController.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* EditController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\PiggyBank;
|
||||
|
||||
|
||||
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Http\Requests\PiggyBankUpdateRequest;
|
||||
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 PiggyBankUpdateRequest $request
|
||||
* @param PiggyBank $piggyBank
|
||||
*
|
||||
* @return RedirectResponse|Redirector
|
||||
*/
|
||||
public function update(PiggyBankUpdateRequest $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;
|
||||
}
|
||||
|
||||
}
|
210
app/Http/Controllers/PiggyBank/IndexController.php
Normal file
210
app/Http/Controllers/PiggyBank/IndexController.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* IndexController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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 = (string) $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']);
|
||||
}
|
||||
}
|
90
app/Http/Controllers/PiggyBank/ShowController.php
Normal file
90
app/Http/Controllers/PiggyBank/ShowController.php
Normal file
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* ShowController.php
|
||||
* Copyright (c) 2020 james@firefly-iii.org
|
||||
*
|
||||
* This file is part of Firefly III (https://github.com/firefly-iii).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace 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'));
|
||||
}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -67,7 +67,8 @@ class PreferencesController extends Controller
|
||||
public function index(AccountRepositoryInterface $repository)
|
||||
{
|
||||
$accounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET, AccountType::LOAN, AccountType::DEBT, AccountType::MORTGAGE]);
|
||||
|
||||
$isDocker = env('IS_DOCKER', false);
|
||||
|
||||
// group accounts
|
||||
$groupedAccounts = [];
|
||||
/** @var Account $account */
|
||||
@@ -122,6 +123,7 @@ class PreferencesController extends Controller
|
||||
compact(
|
||||
'language',
|
||||
'groupedAccounts',
|
||||
'isDocker',
|
||||
'frontPageAccounts',
|
||||
'languages',
|
||||
'locales',
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user