Merge branch 'release/4.8.0.2'

This commit is contained in:
James Cole 2019-08-17 12:38:04 +02:00
commit ad44f99dbf
674 changed files with 4289 additions and 4290 deletions

View File

@ -40,6 +40,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: http://firefly-iii.readthedocs.io/en/latest/support/faq.html
DB_CONNECTION=mysql
# If you use DOCKER COMPOSE, change this variable to "firefly_iii_db"
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=homestead

View File

@ -1,3 +1,27 @@
# 4.8.0.2 (API 0.10.0)
- [Issue 2203](https://github.com/firefly-iii/firefly-iii/issues/2203) Reconciliation inconsistencies.
- [Issue 2392](https://github.com/firefly-iii/firefly-iii/issues/2392) Bad namespace leads to installation errors.
- [Issue 2393](https://github.com/firefly-iii/firefly-iii/issues/2393) Missing budget selector.
- [Issue 2402](https://github.com/firefly-iii/firefly-iii/issues/2402) bad amounts in default report
- [Issue 2405](https://github.com/firefly-iii/firefly-iii/issues/2405) Due date can't be edited.
- [Issue 2404](https://github.com/firefly-iii/firefly-iii/issues/2404) bad page indicator in the "no category" transaction overview.
- [Issue 2407](https://github.com/firefly-iii/firefly-iii/issues/2407) Fix recurring transaction dates
- [Issue 2410](https://github.com/firefly-iii/firefly-iii/issues/2410) Transaction links inconsistent
- [Issue 2414](https://github.com/firefly-iii/firefly-iii/issues/2414) Can't edit recurring transactions
- [Issue 2415](https://github.com/firefly-iii/firefly-iii/issues/2415) Return here + reset form results in empty transaction form
- [Issue 2416](https://github.com/firefly-iii/firefly-iii/issues/2416) Some form inconsistencies.
- [Issue 2418](https://github.com/firefly-iii/firefly-iii/issues/2418) Reports are inaccurate or broken.
- [Issue 2422](https://github.com/firefly-iii/firefly-iii/issues/2422) PHP error when matching transactions.
- [Issue 2423](https://github.com/firefly-iii/firefly-iii/issues/2423) Reports are inaccurate or broken.
- [Issue 2426](https://github.com/firefly-iii/firefly-iii/issues/2426) Inconsistent documentation and instructions.
- [Issue 2427](https://github.com/firefly-iii/firefly-iii/issues/2427) Deleted account and "initial balance" accounts may appear in dropdowns.
- [Issue 2428](https://github.com/firefly-iii/firefly-iii/issues/2428) Reports are inaccurate or broken.
- [Issue 2429](https://github.com/firefly-iii/firefly-iii/issues/2429) Typo leads to SQL errors in available budgets API
- [Issue 2431](https://github.com/firefly-iii/firefly-iii/issues/2431) Issues creating new recurring transactions.
- [Issue 2434](https://github.com/firefly-iii/firefly-iii/issues/2434) You can edit the initial balance transaction but it fails to save.
- ARM build should work now.
# 4.8.0.1 (API 0.10.0)
- The balance box on the dashboard shows only negative numbers, skewing the results.

View File

@ -15,8 +15,8 @@ const pkgdef :Spk.PackageDefinition = (
manifest = (
appTitle = (defaultText = "Firefly III"),
appVersion = 33,
appMarketingVersion = (defaultText = "4.8.0.1"),
appVersion = 34,
appMarketingVersion = (defaultText = "4.8.0.2"),
actions = [
# Define your "new document" handlers here.

View File

@ -1,7 +1,7 @@
sudo: required
language: bash
env:
- VERSION=4.8.0.1
- VERSION=4.8.0.2
dist: xenial
@ -26,4 +26,4 @@ script:
# build everything
- .deploy/docker/build-amd64.sh
- .deploy/docker/build-arm.sh
- .deploy/docker/manifest.sh
- .deploy/docker/manifest.sh

View File

@ -47,7 +47,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AccountController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class AccountController extends Controller
{
@ -234,8 +234,6 @@ class AccountController extends Controller
*
* @return JsonResponse
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
public function transactions(Request $request, Account $account): JsonResponse
{

View File

@ -45,7 +45,7 @@ use function strlen;
/**
* Class AttachmentController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class AttachmentController extends Controller
{

View File

@ -42,7 +42,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class AvailableBudgetController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class AvailableBudgetController extends Controller
{

View File

@ -48,7 +48,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class BillController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class BillController extends Controller
{

View File

@ -47,7 +47,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class BudgetController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class BudgetController extends Controller
{
@ -79,8 +79,6 @@ class BudgetController extends Controller
/**
* Display a listing of the resource.
*
*
* @param Request $request
* @param Budget $budget
*

View File

@ -46,7 +46,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class BudgetLimitController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class BudgetLimitController extends Controller
{

View File

@ -44,7 +44,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class CategoryController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class CategoryController extends Controller
{

View File

@ -37,7 +37,7 @@ use Symfony\Component\HttpFoundation\ParameterBag;
* Class Controller.
*
* @codeCoverageIgnore
* @SuppressWarnings(PHPMD.NumberOfChildren)
*
*/
class Controller extends BaseController
{

View File

@ -66,7 +66,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class CurrencyController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class CurrencyController extends Controller
{

View File

@ -45,7 +45,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class LinkTypeController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class LinkTypeController extends Controller
{

View File

@ -42,7 +42,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class PiggyBankController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class PiggyBankController extends Controller
{

View File

@ -48,7 +48,7 @@ use Log;
/**
* Class RuleController
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class RuleController extends Controller
{

View File

@ -231,7 +231,7 @@ class RuleGroupController extends Controller
*
* @return JsonResponse
* @throws FireflyException
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
*/
public function testGroup(RuleGroupTestRequest $request, RuleGroup $group): JsonResponse
{

View File

@ -42,7 +42,7 @@ use League\Fractal\Serializer\JsonApiSerializer;
/**
* Class UserController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class UserController extends Controller
{

View File

@ -1,4 +1,5 @@
<?php
/**
* DateRequest.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -19,6 +20,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
@ -65,4 +68,4 @@ class DateRequest extends Request
'end' => 'required|date|after:start',
];
}
}
}

View File

@ -1,4 +1,5 @@
<?php
/**
* RuleGroupTestRequest.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -19,6 +20,9 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
@ -141,4 +145,4 @@ class RuleGroupTestRequest extends Request
return null !== $account && AccountType::ASSET === $account->accountType->type;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
/**
* RuleGroupTriggerRequest.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -19,6 +20,9 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
@ -116,4 +120,4 @@ class RuleGroupTriggerRequest extends Request
return null !== $account && AccountType::ASSET === $account->accountType->type;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
/**
* RuleTestRequest.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -19,6 +20,9 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
@ -141,4 +145,4 @@ class RuleTestRequest extends Request
return null !== $account && AccountType::ASSET === $account->accountType->type;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
/**
* RuleTriggerRequest.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -19,6 +20,8 @@
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Api\V1\Requests;
@ -116,4 +119,4 @@ class RuleTriggerRequest extends Request
return null !== $account && AccountType::ASSET === $account->accountType->type;
}
}
}

View File

@ -80,4 +80,4 @@ class CorrectDatabase extends Command
return 0;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* CreateAccessTokens.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* CreateLinkTypes.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* DeleteEmptyGroups.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* DeleteEmptyJournals.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* DeleteOrphanedTransactions.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* DeleteZeroAmount.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* EnableCurrencies.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* FixAccountTypes.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* FixPiggies.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* FixUnevenAmount.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* RemoveBills.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* RenameMetaFields.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* TransferBudgets.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* ReportEmptyObjects.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -70,4 +70,4 @@ class ReportIntegrity extends Command
return 0;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* ReportSum.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* AccountCurrencies.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* BackToJournals.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -116,4 +116,4 @@ class BudgetLimitCurrency extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}
}

View File

@ -115,4 +115,4 @@ class CCLiabilities extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}
}

View File

@ -125,4 +125,4 @@ class MigrateAttachments extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}
}

View File

@ -124,4 +124,4 @@ class MigrateJournalNotes extends Command
{
app('fireflyconfig')->set(self::CONFIG_NAME, true);
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* MigrateToGroups.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -236,7 +237,7 @@ class MigrateToGroups extends Command
* @param TransactionJournal $journal
*
* @throws Exception
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
*/
private function makeMultiGroup(TransactionJournal $journal): void
{

View File

@ -246,4 +246,4 @@ class MigrateToRules extends Command
$this->billRepository->update($bill, $newBillData);
$this->count++;
}
}
}

View File

@ -125,6 +125,7 @@ class OtherCurrenciesCorrections 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) {
@ -247,8 +248,8 @@ class OtherCurrenciesCorrections extends Command
* Gets the transaction that determines the transaction that "leads" and will determine
* the currency to be used by all transactions, and the journal itself.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @param TransactionJournal $journal
*
* @return Transaction|null
*/
private function getLeadTransaction(TransactionJournal $journal): ?Transaction
@ -282,4 +283,4 @@ class OtherCurrenciesCorrections extends Command
return $lead;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* RenameAccountMeta.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* TransactionIdentifier.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* TransferCurrenciesCorrections.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -147,6 +148,7 @@ 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) {
@ -290,8 +292,6 @@ class TransferCurrenciesCorrections extends Command
}
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @param TransactionJournal $transfer
*/
private function updateTransferCurrency(TransactionJournal $transfer): void
@ -575,4 +575,4 @@ class TransferCurrenciesCorrections extends Command
return false;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* UpgradeDatabase.php
* Copyright (c) 2019 thegrumpydictator@gmail.com

View File

@ -36,16 +36,15 @@ class StoredTransactionGroup extends Event
{
use SerializesModels;
public $applyRules;
/** @var TransactionGroup The group that was stored. */
public $transactionGroup;
public $applyRules;
/**
* Create a new event instance.
*
* @param TransactionGroup $transactionGroup
* @param bool $applyRules
* @param bool $applyRules
*/
public function __construct(TransactionGroup $transactionGroup, bool $applyRules = true)
{

View File

@ -29,6 +29,7 @@ use Illuminate\Queue\SerializesModels;
/**
* Class UpdatedTransactionGroup.
*
* @codeCoverageIgnore
*
*/

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* GracefulNotFoundHandler.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -43,9 +44,7 @@ class GracefulNotFoundHandler extends ExceptionHandler
*
* @param Request $request
* @param Exception $exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
*
* @return mixed
*/
@ -225,4 +224,4 @@ class GracefulNotFoundHandler extends ExceptionHandler
}
}
}

View File

@ -48,9 +48,7 @@ class Handler extends ExceptionHandler
*
* @param Request $request
* @param Exception $exception
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
*
* @return mixed
*/
@ -112,7 +110,7 @@ class Handler extends ExceptionHandler
*
* This is a great spot to send exceptions to Sentry etc.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five its fine.
* // it's five its fine.
*
* @param Exception $exception
*

View File

@ -189,7 +189,7 @@ class AccountFactory
* @param null|string $accountType
*
* @return AccountType|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
protected function getAccountType(?int $accountTypeId, ?string $accountType): ?AccountType
{

View File

@ -26,7 +26,6 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Budget;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
@ -53,7 +52,7 @@ class BudgetFactory
* @param null|string $budgetName
*
* @return Budget|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function find(?int $budgetId, ?string $budgetName): ?Budget
{

View File

@ -26,7 +26,6 @@ namespace FireflyIII\Factory;
use FireflyIII\Models\Category;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
@ -63,7 +62,7 @@ class CategoryFactory
* @param null|string $categoryName
*
* @return Category|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function findOrCreate(?int $categoryId, ?string $categoryName): ?Category
{

View File

@ -53,7 +53,7 @@ class PiggyBankEventFactory
* @param PiggyBank|null $piggyBank
*
* @return PiggyBankEvent|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function create(TransactionJournal $journal, ?PiggyBank $piggyBank): ?PiggyBankEvent
{

View File

@ -52,7 +52,7 @@ class PiggyBankFactory
* @param null|string $piggyBankName
*
* @return PiggyBank|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function find(?int $piggyBankId, ?string $piggyBankName): ?PiggyBank
{

View File

@ -79,7 +79,7 @@ class TransactionCurrencyFactory
* @param null|string $currencyCode
*
* @return TransactionCurrency|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function find(?int $currencyId, ?string $currencyCode): ?TransactionCurrency
{

View File

@ -23,9 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Factory;
use FireflyIII\Exceptions\FireflyException;
use FireflyIII\Models\TransactionGroup;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\User;
/**
@ -60,10 +58,8 @@ class TransactionGroupFactory
$collection = $this->journalFactory->create($data);
$title = $data['group_title'] ?? null;
$title = '' === $title ? null : $title;
/** @var TransactionJournal $first */
$first = $collection->first();
$group = new TransactionGroup;
$group->user()->associate($first->user);
$group = new TransactionGroup;
$group->user()->associate($this->user);
$group->title = $title;
$group->save();
@ -81,4 +77,4 @@ class TransactionGroupFactory
{
$this->user = $user;
}
}
}

View File

@ -143,6 +143,9 @@ class TransactionJournalFactory
if (null !== $journal) {
$collection->push($journal);
}
if(null === $journal) {
Log::error('The createJournal() method returned NULL. This may indicate an error.');
}
}
return $collection;
@ -247,6 +250,7 @@ class TransactionJournalFactory
$destinationAccount = $this->getAccount($type->type, 'destination', (int)$row['destination_id'], $row['destination_name']);
// @codeCoverageIgnoreStart
} catch (FireflyException $e) {
Log::error('Could not validate source or destination.');
Log::error($e->getMessage());
return null;

View File

@ -49,8 +49,6 @@ class TransactionJournalMetaFactory
* @param array $data
*
* @return TransactionJournalMeta|null
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function updateOrCreate(array $data): ?TransactionJournalMeta
{

View File

@ -109,7 +109,7 @@ class ChartJsGenerator implements GeneratorInterface
* ]
* ]
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five.
* // it's five.
*
* @param array $data
*

View File

@ -60,7 +60,7 @@ interface GeneratorInterface
* ]
* ]
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's five.
* // it's five.
*
* @param array $data
*

View File

@ -24,7 +24,6 @@ namespace FireflyIII\Generator\Report\Standard;
use Carbon\Carbon;
use FireflyIII\Generator\Report\ReportGeneratorInterface;
use FireflyIII\Helpers\Report\ReportHelperInterface;
use Illuminate\Support\Collection;
use Log;
use Throwable;
@ -50,17 +49,11 @@ class MonthReportGenerator implements ReportGeneratorInterface
*/
public function generate(): string
{
/** @var ReportHelperInterface $helper */
$helper = app(ReportHelperInterface::class);
$bills = $helper->getBillReport($this->start, $this->end, $this->accounts);
$accountIds = implode(',', $this->accounts->pluck('id')->toArray());
$reportType = 'default';
try {
return view(
'reports.default.month',
compact('bills', 'accountIds', 'reportType')
)->with('start', $this->start)->with('end', $this->end)->render();
return view('reports.default.month', compact('accountIds', 'reportType'))->with('start', $this->start)->with('end', $this->end)->render();
} catch (Throwable $e) {
Log::error(sprintf('Cannot render reports.default.month: %s', $e->getMessage()));
$result = 'Could not render report view.';

View File

@ -112,7 +112,7 @@ class Support
/**
* Summarize collection by earned and spent data.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity) // it's exactly five.
* // it's exactly five.
*
* @param array $spent
* @param array $earned

View File

@ -43,9 +43,7 @@ class VersionCheckEventHandler
/**
* Checks with GitHub to see if there is a new version.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.NPathComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @param RequestedVersionCheckStatus $event
*/
public function checkForUpdates(RequestedVersionCheckStatus $event): void

View File

@ -98,7 +98,7 @@ class MetaPieChart implements MetaPieChartInterface
* @param string $group
*
* @return array
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
public function generate(string $direction, string $group): array
{
@ -181,8 +181,6 @@ class MetaPieChart implements MetaPieChartInterface
*
* @return array
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*
*/
protected function groupByFields(array $array, array $fields): array
{

View File

@ -1,97 +0,0 @@
<?php
/**
* Balance.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use Illuminate\Support\Collection;
/**
* Class Balance.
*
* @codeCoverageIgnore
*/
class Balance
{
/** @var BalanceHeader Header row. */
protected $balanceHeader;
/** @var Collection Collection of lines. */
protected $balanceLines;
/**
* Balance constructor.
*/
public function __construct()
{
$this->balanceLines = new Collection;
}
/**
* Add a line.
*
* @param BalanceLine $line
*/
public function addBalanceLine(BalanceLine $line): void
{
$this->balanceLines->push($line);
}
/**
* Get the header.
*
* @return BalanceHeader
*/
public function getBalanceHeader(): BalanceHeader
{
return $this->balanceHeader ?? new BalanceHeader;
}
/**
* Set the header.
*
* @param BalanceHeader $balanceHeader
*/
public function setBalanceHeader(BalanceHeader $balanceHeader): void
{
$this->balanceHeader = $balanceHeader;
}
/**
* Get all lines.
*
* @return Collection
*/
public function getBalanceLines(): Collection
{
return $this->balanceLines;
}
/**
* Set all lines.
*
* @param Collection $balanceLines
*/
public function setBalanceLines(Collection $balanceLines): void
{
$this->balanceLines = $balanceLines;
}
}

View File

@ -1,100 +0,0 @@
<?php
/**
* BalanceEntry.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Account as AccountModel;
/**
* Class BalanceEntry.
*
* @codeCoverageIgnore
*/
class BalanceEntry
{
/** @var AccountModel The account. */
protected $account;
/** @var string The amount left. */
protected $left = '0';
/** @var string The amount spent. */
protected $spent = '0';
/**
* Account getter.
*
* @return AccountModel
*/
public function getAccount(): AccountModel
{
return $this->account;
}
/**
* Account setter.
*
* @param AccountModel $account
*/
public function setAccount(AccountModel $account): void
{
$this->account = $account;
}
/**
* Get amount left.
*
* @return string
*/
public function getLeft(): string
{
return $this->left;
}
/**
* Set amount left.
*
* @param string $left
*/
public function setLeft(string $left): void
{
$this->left = $left;
}
/**
* Get amount spent.
*
* @return string
*/
public function getSpent(): string
{
return $this->spent;
}
/**
* Set amount spent.
*
* @param string $spent
*/
public function setSpent(string $spent): void
{
$this->spent = $spent;
}
}

View File

@ -1,65 +0,0 @@
<?php
/**
* BalanceHeader.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Account as AccountModel;
use Illuminate\Support\Collection;
/**
* Class BalanceHeader.
*
* @codeCoverageIgnore
*/
class BalanceHeader
{
/** @var Collection The accounts. */
protected $accounts;
/**
* BalanceHeader constructor.
*/
public function __construct()
{
$this->accounts = new Collection;
}
/**
* Add an account.
*
* @param AccountModel $account
*/
public function addAccount(AccountModel $account): void
{
$this->accounts->push($account);
}
/**
* Get them all.
*
* @return Collection
*/
public function getAccounts(): Collection
{
return $this->accounts;
}
}

View File

@ -1,189 +0,0 @@
<?php
/**
* BalanceLine.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use Carbon\Carbon;
use FireflyIII\Models\Budget as BudgetModel;
use FireflyIII\Models\BudgetLimit;
use Illuminate\Support\Collection;
/**
* Class BalanceLine.
*
* @codeCoverageIgnore
*/
class BalanceLine
{
/**
*
*/
public const ROLE_DEFAULTROLE = 1;
/**
*
*/
public const ROLE_TAGROLE = 2;
/** @var Collection */
protected $balanceEntries;
/** @var BudgetModel */
protected $budget;
/** @var BudgetLimit */
protected $budgetLimit;
/** @var int */
protected $role = self::ROLE_DEFAULTROLE;
/**
*
*/
public function __construct()
{
$this->balanceEntries = new Collection;
}
/**
* @param BalanceEntry $balanceEntry
*/
public function addBalanceEntry(BalanceEntry $balanceEntry): void
{
$this->balanceEntries->push($balanceEntry);
}
/**
* @return Collection
*/
public function getBalanceEntries(): Collection
{
return $this->balanceEntries;
}
/**
* @param Collection $balanceEntries
*/
public function setBalanceEntries(Collection $balanceEntries): void
{
$this->balanceEntries = $balanceEntries;
}
/**
* @return BudgetModel
*/
public function getBudget(): BudgetModel
{
return $this->budget ?? new BudgetModel;
}
/**
* @param BudgetModel $budget
*/
public function setBudget(BudgetModel $budget): void
{
$this->budget = $budget;
}
/**
* @return BudgetLimit
*/
public function getBudgetLimit(): BudgetLimit
{
return $this->budgetLimit;
}
/**
* @param BudgetLimit $budgetLimit
*/
public function setBudgetLimit(BudgetLimit $budgetLimit): void
{
$this->budgetLimit = $budgetLimit;
}
/**
* @return Carbon
*/
public function getEndDate(): Carbon
{
return $this->budgetLimit->end_date ?? new Carbon;
}
/**
* @return int
*/
public function getRole(): int
{
return $this->role;
}
/**
* @param int $role
*/
public function setRole(int $role): void
{
$this->role = $role;
}
/**
* @return Carbon
*/
public function getStartDate(): Carbon
{
return $this->budgetLimit->start_date ?? new Carbon;
}
/**
* @return string
*/
public function getTitle(): string
{
$title = '';
if ($this->getBudget() instanceof BudgetModel && null !== $this->getBudget()->id) {
$title = $this->getBudget()->name;
}
if ('' === $title && self::ROLE_DEFAULTROLE === $this->getRole()) {
$title = (string)trans('firefly.no_budget');
}
if ('' === $title && self::ROLE_TAGROLE === $this->getRole()) {
$title = (string)trans('firefly.coveredWithTags');
}
return $title;
}
/**
* If a BalanceLine has a budget/repetition, each BalanceEntry in this BalanceLine
* should have a "spent" value, which is the amount of money that has been spent
* on the given budget/repetition. If you subtract all those amounts from the budget/repetition's
* total amount, this is returned:.
*
* @return string
*/
public function leftOfRepetition(): string
{
$start = $this->budgetLimit->amount ?? '0';
/** @var BalanceEntry $balanceEntry */
foreach ($this->getBalanceEntries() as $balanceEntry) {
$start = bcadd($balanceEntry->getSpent(), $start);
}
return $start;
}
}

View File

@ -1,128 +0,0 @@
<?php
/**
* Bill.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use Carbon\Carbon;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
/**
* Class Bill.
*
* @codeCoverageIgnore
*/
class Bill
{
/** @var Collection The bills. */
private $bills;
/** @var Carbon End date of the collection. */
private $endDate;
/** @var Carbon Start date of the collection. */
private $startDate;
/**
* Bill constructor.
*/
public function __construct()
{
$this->bills = new Collection;
}
/**
* Add a bill line.
*
* @param BillLine $bill
*/
public function addBill(BillLine $bill): void
{
$this->bills->push($bill);
}
/**
* Filter the bills (yes how very descriptive).
*/
public function filterBills(): void
{
Log::debug('Now in filterBills()');
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$start = $this->startDate;
$end = $this->endDate;
$lines = $this->bills->filter(
function (BillLine $line) use ($repository, $start, $end) {
// next expected match?
$date = $start;
Log::debug(sprintf('Now at bill line for bill "%s"', $line->getBill()->name));
Log::debug(sprintf('Default date to use is start date: %s', $date->format('Y-m-d')));
if ($line->isHit()) {
$date = $line->getLastHitDate();
Log::debug(sprintf('Line was hit, see date: %s. Always include it.', $date->format('Y-m-d')));
return $line;
}
$expected = $repository->nextExpectedMatch($line->getBill(), $date);
Log::debug(sprintf('Next expected match is %s', $expected->format('Y-m-d')));
if ($expected <= $end && $expected >= $start) {
Log::debug('This date is inside report limits');
return $line;
}
Log::debug('This date is OUTSIDE report limits');
return false;
}
);
$this->bills = $lines;
}
/**
* Bills getter.
*
* @return Collection
*/
public function getBills(): Collection
{
return $this->bills;
}
/**
* End date setter.
*
* @param Carbon $endDate
*/
public function setEndDate(Carbon $endDate): void
{
$this->endDate = $endDate;
}
/**
* Start date setter.
*
* @param Carbon $startDate
*/
public function setStartDate(Carbon $startDate): void
{
$this->startDate = $startDate;
}
}

View File

@ -1,270 +0,0 @@
<?php
/**
* BillLine.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use Carbon\Carbon;
use FireflyIII\Models\Bill as BillModel;
use FireflyIII\Models\TransactionCurrency;
/**
* Class BillLine.
*
* @codeCoverageIgnore
*/
class BillLine
{
/** @var string The amount */
protected $amount;
/** @var BillModel The bill. */
protected $bill;
/** @var bool Is it hit this period */
protected $hit;
/** @var string What was the max amount. */
protected $max;
/** @var string What was the min amount. */
protected $min;
/** @var TransactionCurrency The transaction currency */
private $currency;
/** @var Carbon Latest date that payment is expected. */
private $endOfPayDate;
/** @var Carbon Date of last hit */
private $lastHitDate;
/** @var Carbon Date of last payment */
private $payDate;
/** @var int Journal */
private $transactionJournalId;
/**
* BillLine constructor.
*/
public function __construct()
{
$this->lastHitDate = new Carbon;
}
/**
* Amount getter.
*
* @return string
*/
public function getAmount(): string
{
return $this->amount ?? '0';
}
/**
* Amount setter.
*
* @param string $amount
*/
public function setAmount(string $amount): void
{
$this->amount = $amount;
}
/**
* Bill getter.
*
* @return BillModel
*/
public function getBill(): BillModel
{
return $this->bill;
}
/**
* Bill setter.
*
* @param BillModel $bill
*/
public function setBill(BillModel $bill): void
{
$this->bill = $bill;
}
/**
* @return TransactionCurrency
*/
public function getCurrency(): TransactionCurrency
{
return $this->currency;
}
/**
* @param TransactionCurrency $currency
*/
public function setCurrency(TransactionCurrency $currency): void
{
$this->currency = $currency;
}
/**
* End of pay date getter.
*
* @return Carbon
*/
public function getEndOfPayDate(): Carbon
{
return $this->endOfPayDate;
}
/**
* End of pay date setter.
*
* @param Carbon $endOfPayDate
*/
public function setEndOfPayDate(Carbon $endOfPayDate): void
{
$this->endOfPayDate = $endOfPayDate;
}
/**
* Last hit date getter.
*
* @return Carbon
*/
public function getLastHitDate(): Carbon
{
return $this->lastHitDate;
}
/**
* Last hit date setter.
*
* @param Carbon $lastHitDate
*/
public function setLastHitDate(Carbon $lastHitDate): void
{
$this->lastHitDate = $lastHitDate;
}
/**
* Max getter.
*
* @return string
*/
public function getMax(): string
{
return $this->max;
}
/**
* Max setter.
*
* @param string $max
*/
public function setMax(string $max): void
{
$this->max = $max;
}
/**
* Min getter.
*
* @return string
*/
public function getMin(): string
{
return $this->min;
}
/**
* Min setter.
*
* @param string $min
*/
public function setMin(string $min): void
{
$this->min = $min;
}
/**
* Pay date getter.
*
* @return Carbon
*/
public function getPayDate(): Carbon
{
return $this->payDate;
}
/**
* Pay date setter.
*
* @param Carbon $payDate
*/
public function setPayDate(Carbon $payDate): void
{
$this->payDate = $payDate;
}
/**
* Journal ID getter.
*
* @return int
*/
public function getTransactionJournalId(): int
{
return $this->transactionJournalId ?? 0;
}
/**
* Journal ID setter.
*
* @param int $transactionJournalId
*/
public function setTransactionJournalId(int $transactionJournalId): void
{
$this->transactionJournalId = $transactionJournalId;
}
/**
* Is active.
*
* @return bool
*/
public function isActive(): bool
{
return 1 === (int)$this->bill->active;
}
/**
* Is hit.
*
* @return bool
*/
public function isHit(): bool
{
return $this->hit;
}
/**
* Set is hit.
*
* @param bool $hit
*/
public function setHit(bool $hit): void
{
$this->hit = $hit;
}
}

View File

@ -1,97 +0,0 @@
<?php
/**
* Category.php
* Copyright (c) 2017 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Helpers\Collection;
use FireflyIII\Models\Category as CategoryModel;
use Illuminate\Support\Collection;
/**
* Class Category.
*
* @codeCoverageIgnore
*/
class Category
{
/** @var Collection The categories */
protected $categories;
/** @var string Total amount */
protected $total = '0';
/**
* Category constructor.
*/
public function __construct()
{
$this->categories = new Collection;
}
/**
* Add a category.
*
* @param CategoryModel $category
*/
public function addCategory(CategoryModel $category): void
{
// spent is minus zero for an expense report:
if ($category->spent < 0) {
$this->categories->push($category);
$this->addTotal((string)$category->spent);
}
}
/**
* Add to the total amount.
*
* @param string $add
*/
public function addTotal(string $add): void
{
$this->total = bcadd($this->total, $add);
}
/**
* Get all categories.
*
* @return Collection
*/
public function getCategories(): Collection
{
$set = $this->categories->sortBy(
static function (CategoryModel $category) {
return $category->spent;
}
);
return $set;
}
/**
* Get the total.
*
* @return string
*/
public function getTotal(): string
{
return $this->total;
}
}

View File

@ -46,8 +46,6 @@ use Log;
*/
class GroupCollector implements GroupCollectorInterface
{
/** @var array The accounts to filter on. Asset accounts or liabilities. */
private $accountIds;
/** @var array The standard fields to select. */
private $fields;
/** @var bool Will be set to true if query result contains account information. (see function withAccountInformation). */
@ -86,8 +84,6 @@ class GroupCollector implements GroupCollectorInterface
$this->hasJoinedTagTables = false;
$this->total = 0;
$this->limit = 50;
$this->page = 0;
$this->fields = [
# group
'transaction_groups.id as transaction_group_id',
@ -157,10 +153,14 @@ class GroupCollector implements GroupCollectorInterface
$collection = $this->parseArray($result);
$this->total = $collection->count();
// now filter the array according to the page and the
$offset = $this->page * $this->limit;
// now filter the array according to the page and the limit (if necessary)
if (null !== $this->limit && null !== $this->page) {
$offset = ($this->page-1) * $this->limit;
return $collection->slice($offset, $this->limit);
}
return $collection;
}
@ -182,7 +182,44 @@ class GroupCollector implements GroupCollectorInterface
}
);
app('log')->debug(sprintf('GroupCollector: setAccounts: %s', implode(', ', $accountIds)));
$this->accountIds = $accountIds;
}
return $this;
}
/**
* Define which accounts can be part of the source and destination transactions.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function setSourceAccounts(Collection $accounts): GroupCollectorInterface
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('source.account_id', $accountIds);
app('log')->debug(sprintf('GroupCollector: setSourceAccounts: %s', implode(', ', $accountIds)));
}
return $this;
}
/**
* Define which accounts can be part of the source and destination transactions.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function setDestinationAccounts(Collection $accounts): GroupCollectorInterface
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereIn('destination.account_id', $accountIds);
app('log')->debug(sprintf('GroupCollector: setSourceAccounts: %s', implode(', ', $accountIds)));
}
return $this;
@ -370,9 +407,9 @@ class GroupCollector implements GroupCollectorInterface
*/
public function setPage(int $page): GroupCollectorInterface
{
$page = 0 === $page ? 0 : $page - 1;
$page = 0 === $page ? 1 : $page;
$this->page = $page;
app('log')->debug(sprintf('GroupCollector: page is now %d (is minus 1)', $page));
app('log')->debug(sprintf('GroupCollector: page is now %d', $page));
return $this;
}
@ -807,6 +844,7 @@ class GroupCollector implements GroupCollectorInterface
/** @var TransactionGroup $augmentedGroup */
foreach ($collection as $augmentedGroup) {
$groupId = $augmentedGroup->transaction_group_id;
if (!isset($groups[$groupId])) {
// make new array
$parsedGroup = $this->parseAugmentedGroup($augmentedGroup);
@ -837,7 +875,9 @@ class GroupCollector implements GroupCollectorInterface
$groups[$groupId]['transactions'][$journalId] = $this->parseAugmentedGroup($augmentedGroup);
}
}
$groups = $this->parseSums($groups);
return new Collection($groups);
@ -1010,4 +1050,42 @@ class GroupCollector implements GroupCollectorInterface
->orderBy('transaction_journals.description', 'DESC')
->orderBy('source.amount', 'DESC');
}
}
/**
* These accounts must not be source accounts.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function excludeSourceAccounts(Collection $accounts): GroupCollectorInterface
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereNotIn('source.account_id', $accountIds);
app('log')->debug(sprintf('GroupCollector: excludeSourceAccounts: %s', implode(', ', $accountIds)));
}
return $this;
}
/**
* These accounts must not be destination accounts.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function excludeDestinationAccounts(Collection $accounts): GroupCollectorInterface
{
if ($accounts->count() > 0) {
$accountIds = $accounts->pluck('id')->toArray();
$this->query->whereNotIn('destination.account_id', $accountIds);
app('log')->debug(sprintf('GroupCollector: excludeDestinationAccounts: %s', implode(', ', $accountIds)));
}
return $this;
}
}

View File

@ -46,6 +46,41 @@ interface GroupCollectorInterface
*/
public function getExtractedJournals(): array;
/**
* Set source accounts.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function setSourceAccounts(Collection $accounts): GroupCollectorInterface;
/**
* These accounts must not be source accounts.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function excludeSourceAccounts(Collection $accounts): GroupCollectorInterface;
/**
* Exclude destination accounts.
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function excludeDestinationAccounts(Collection $accounts): GroupCollectorInterface;
/**
* Set destination accounts.
*
* @param Collection $accounts
*
* @return GroupCollectorInterface
*/
public function setDestinationAccounts(Collection $accounts): GroupCollectorInterface;
/**
* Return the sum of all journals.
*
@ -341,4 +376,4 @@ interface GroupCollectorInterface
*/
public function withCategoryInformation(): GroupCollectorInterface;
}
}

View File

@ -23,11 +23,10 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Balance;
use FireflyIII\Helpers\Collection\BalanceEntry;
use FireflyIII\Helpers\Collection\BalanceHeader;
use FireflyIII\Helpers\Collection\BalanceLine;
use FireflyIII\Models\BudgetLimit;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
@ -44,8 +43,6 @@ class BalanceReportHelper implements BalanceReportHelperInterface
/**
* ReportHelper constructor.
*
*
* @param BudgetRepositoryInterface $budgetRepository
*/
public function __construct(BudgetRepositoryInterface $budgetRepository)
@ -65,126 +62,78 @@ class BalanceReportHelper implements BalanceReportHelperInterface
* @param Carbon $start
* @param Carbon $end
*
* @return Balance
* @return array
*/
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): array
{
Log::debug('Start of balance report');
$balance = new Balance;
$header = new BalanceHeader;
$budgetLimits = $this->budgetRepository->getAllBudgetLimits($start, $end);
$report = [
'budgets' => [],
'accounts' => [],
];
/** @var Account $account */
foreach ($accounts as $account) {
Log::debug(sprintf('Add account %s to headers.', $account->name));
$header->addAccount($account);
$report['accounts'][$account->id] = [
'id' => $account->id,
'name' => $account->name,
'iban' => $account->iban,
'sum' => '0',
];
}
/** @var BudgetLimit $budgetLimit */
foreach ($budgetLimits as $budgetLimit) {
if (null !== $budgetLimit->budget) {
$line = $this->createBalanceLine($budgetLimit, $accounts);
$balance->addBalanceLine($line);
$budgets = $this->budgetRepository->getBudgets();
/** @var Budget $budget */
foreach ($budgets as $budget) {
$budgetId = $budget->id;
$report['budgets'][$budgetId] = [
'budget_id' => $budgetId,
'budget_name' => $budget->name,
'spent' => [], // per account
'sums' => [], // per currency
];
$spent = [];
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$journals = $collector->setRange($start, $end)->setSourceAccounts($accounts)->setTypes([TransactionType::WITHDRAWAL])->setBudget($budget)
->getExtractedJournals();
/** @var array $journal */
foreach ($journals as $journal) {
$sourceAccount = $journal['source_account_id'];
$currencyId = $journal['currency_id'];
$spent[$sourceAccount] = $spent[$sourceAccount] ?? [
'source_account_id' => $sourceAccount,
'currency_id' => $journal['currency_id'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'spent' => '0',
];
$spent[$sourceAccount]['spent'] = bcadd($spent[$sourceAccount]['spent'], $journal['amount']);
// also fix sum:
$report['sums'][$budgetId][$currencyId] = $report['sums'][$budgetId][$currencyId] ?? [
'sum' => '0',
'currency_id' => $journal['currency_id'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
$report['sums'][$budgetId][$currencyId]['sum'] = bcadd($report['sums'][$budgetId][$currencyId]['sum'], $journal['amount']);
$report['accounts'][$sourceAccount]['sum'] = bcadd($report['accounts'][$sourceAccount]['sum'], $journal['amount']);
// add currency info for account sum
$report['accounts'][$sourceAccount]['currency_id'] = $journal['currency_id'];
$report['accounts'][$sourceAccount]['currency_code'] = $journal['currency_code'];
$report['accounts'][$sourceAccount]['currency_name'] = $journal['currency_name'];
$report['accounts'][$sourceAccount]['currency_symbol'] = $journal['currency_symbol'];
$report['accounts'][$sourceAccount]['currency_decimal_places'] = $journal['currency_decimal_places'];
}
$report['budgets'][$budgetId]['spent'] = $spent;
// get transactions in budget
}
$noBudgetLine = $this->createNoBudgetLine($accounts, $start, $end);
$balance->addBalanceLine($noBudgetLine);
$balance->setBalanceHeader($header);
Log::debug('Clear unused budgets.');
// remove budgets without expenses from balance lines:
$balance = $this->removeUnusedBudgets($balance);
Log::debug('Return report.');
return $balance;
}
/**
* Create one balance line.
*
* @param BudgetLimit $budgetLimit
* @param Collection $accounts
*
* @return BalanceLine
*/
private function createBalanceLine(BudgetLimit $budgetLimit, Collection $accounts): BalanceLine
{
$line = new BalanceLine;
$line->setBudget($budgetLimit->budget);
$line->setBudgetLimit($budgetLimit);
// loop accounts:
foreach ($accounts as $account) {
$balanceEntry = new BalanceEntry;
$balanceEntry->setAccount($account);
$spent = $this->budgetRepository->spentInPeriod(
new Collection([$budgetLimit->budget]),
new Collection([$account]),
$budgetLimit->start_date,
$budgetLimit->end_date
);
$balanceEntry->setSpent($spent);
$line->addBalanceEntry($balanceEntry);
}
return $line;
}
/**
* Create a line for transactions without a budget.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return BalanceLine
*/
private function createNoBudgetLine(Collection $accounts, Carbon $start, Carbon $end): BalanceLine
{
$empty = new BalanceLine;
foreach ($accounts as $account) {
$spent = $this->budgetRepository->spentInPeriodWoBudget(new Collection([$account]), $start, $end);
// budget
$budgetEntry = new BalanceEntry;
$budgetEntry->setAccount($account);
$budgetEntry->setSpent($spent);
$empty->addBalanceEntry($budgetEntry);
}
return $empty;
}
/**
* Remove unused budgets from the report.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @param Balance $balance
*
* @return Balance
*/
private function removeUnusedBudgets(Balance $balance): Balance
{
$set = $balance->getBalanceLines();
$newSet = new Collection;
/** @var BalanceLine $entry */
foreach ($set as $entry) {
if (null !== $entry->getBudget()->id) {
$sum = '0';
/** @var BalanceEntry $balanceEntry */
foreach ($entry->getBalanceEntries() as $balanceEntry) {
$sum = bcadd($sum, $balanceEntry->getSpent());
}
if (bccomp($sum, '0') === -1) {
$newSet->push($entry);
}
continue;
}
$newSet->push($entry);
}
$balance->setBalanceLines($newSet);
return $balance;
return $report;
}
}

View File

@ -38,7 +38,7 @@ interface BalanceReportHelperInterface
* @param Carbon $start
* @param Carbon $end
*
* @return Balance
* @return array
*/
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): Balance;
public function getBalanceReport(Collection $accounts, Carbon $start, Carbon $end): array;
}

View File

@ -57,8 +57,8 @@ class BudgetReportHelper implements BudgetReportHelperInterface
/**
* Get the full budget report.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
* TODO one big method is very complex.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
@ -68,104 +68,142 @@ class BudgetReportHelper implements BudgetReportHelperInterface
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): array
{
$set = $this->repository->getBudgets();
$array = [];
$array = [
'budgets' => [],
'sums' => [],
];
/** @var Budget $budget */
foreach ($set as $budget) {
$entry = [
'budget_id' => $budget->id,
'budget_name' => $budget->name,
'no_budget' => false,
'rows' => [],
];
// get multi currency expenses first:
$budgetLimits = $this->repository->getBudgetLimits($budget, $start, $end);
if (0 === $budgetLimits->count()) { // no budget limit(s) for this budget
$spent = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end); // spent for budget in time range
if (bccomp($spent, '0') === -1) {
$line = [
'type' => 'budget',
'id' => $budget->id,
'name' => $budget->name,
'budgeted' => '0',
'spent' => $spent,
'left' => '0',
'overspent' => '0',
$expenses = $this->repository->spentInPeriodMc(new Collection([$budget]), $accounts, $start, $end);
if (0 === count($expenses)) {
// list the budget limits, basic amounts.
/** @var BudgetLimit $limit */
foreach ($budgetLimits as $limit) {
$row = [
'limit_id' => $limit->id,
'start_date' => $limit->start_date,
'end_date' => $limit->end_date,
'budgeted' => $limit->amount,
'spent' => '0',
'left' => $limit->amount,
'overspent' => null,
'currency_id' => $limit->transactionCurrency->id,
'currency_code' => $limit->transactionCurrency->code,
'currency_name' => $limit->transactionCurrency->name,
'currency_symbol' => $limit->transactionCurrency->symbol,
'currency_decimal_places' => $limit->transactionCurrency->decimal_places,
];
$array[] = $line;
$entry['rows'][] = $row;
}
continue;
}
/** @var BudgetLimit $budgetLimit */
foreach ($budgetLimits as $budgetLimit) { // one or more repetitions for budget
$data = $this->calculateExpenses($budget, $budgetLimit, $accounts);
$line = [
'type' => 'budget-line',
'start' => $budgetLimit->start_date,
'end' => $budgetLimit->end_date,
'limit' => $budgetLimit->id,
'id' => $budget->id,
'name' => $budget->name,
'budgeted' => (string)$budgetLimit->amount,
'spent' => $data['expenses'],
'left' => $data['left'],
'overspent' => $data['overspent'],
foreach ($expenses as $expense) {
$limit = $this->budgetLimitInCurrency($expense['currency_id'], $budgetLimits);
$row = [
'limit_id' => null,
'start_date' => null,
'end_date' => null,
'budgeted' => null,
'spent' => $expense['amount'],
'left' => null,
'overspent' => null,
'currency_id' => $expense['currency_id'],
'currency_code' => $expense['currency_name'],
'currency_name' => $expense['currency_name'],
'currency_symbol' => $expense['currency_symbol'],
'currency_decimal_places' => $expense['currency_decimal_places'],
];
$array[] = $line;
if (null !== $limit) {
// yes
$row['start_date'] = $limit->start_date;
$row['end_date'] = $limit->end_date;
$row['budgeted'] = $limit->amount;
$row['limit_id'] = $limit->id;
// less than zero? Set to 0.0
$row['left'] = -1 === bccomp(bcadd($limit->amount, $row['spent']), '0') ? '0' : bcadd($limit->amount, $row['spent']);
// spent > budgeted? then sum, otherwise other sum
$row['overspent'] = 1 === bccomp($row['spent'], $row['budgeted']) ? bcadd($row['spent'], $row['budgeted']) : '0';
}
$entry['rows'][] = $row;
}
$array['budgets'][] = $entry;
}
$noBudget = $this->repository->spentInPeriodWoBudget($accounts, $start, $end); // stuff outside of budgets
$line = [
'type' => 'no-budget',
'budgeted' => '0',
'spent' => $noBudget,
'left' => '0',
'overspent' => '0',
$noBudget = $this->repository->spentInPeriodWoBudgetMc($accounts, $start, $end);
$noBudgetEntry = [
'budget_id' => null,
'budget_name' => null,
'no_budget' => true,
'rows' => [],
];
$array[] = $line;
foreach ($noBudget as $row) {
$noBudgetEntry['rows'][] = [
'limit_id' => null,
'start_date' => null,
'end_date' => null,
'budgeted' => null,
'spent' => $row['amount'],
'left' => null,
'overspent' => null,
'currency_id' => $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'],
'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'],
];
}
$array['budgets'][] = $noBudgetEntry;
return $array;
}
/**
* Get all budgets and the expenses in these budgets.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Collection
*/
public function getBudgetsWithExpenses(Carbon $start, Carbon $end, Collection $accounts): Collection
{
/** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class);
$budgets = $repository->getActiveBudgets();
$set = new Collection;
/** @var Budget $budget */
foreach ($budgets as $budget) {
$total = $repository->spentInPeriod(new Collection([$budget]), $accounts, $start, $end);
if (bccomp($total, '0') === -1) {
$set->push($budget);
// fill sums:
/** @var array $budget */
foreach ($array['budgets'] as $budget) {
/** @var array $row */
foreach ($budget['rows'] as $row) {
$currencyId = $row['currency_id'];
$array['sums'][$currencyId] = $array['sums'][$currencyId] ?? [
'currency_id' => $row['currency_id'],
'currency_code' => $row['currency_code'],
'currency_name' => $row['currency_name'],
'currency_symbol' => $row['currency_symbol'],
'currency_decimal_places' => $row['currency_decimal_places'],
'budgeted' => '0',
'spent' => '0',
'left' => '0',
'overspent' => '0',
];
$array['sums'][$currencyId]['budgeted'] = bcadd($array['sums'][$currencyId]['budgeted'], $row['budgeted'] ?? '0');
$array['sums'][$currencyId]['spent'] = bcadd($array['sums'][$currencyId]['spent'], $row['spent'] ?? '0');
$array['sums'][$currencyId]['left'] = bcadd($array['sums'][$currencyId]['left'], $row['left'] ?? '0');
$array['sums'][$currencyId]['overspent'] = bcadd($array['sums'][$currencyId]['overspent'], $row['overspent'] ?? '0');
}
}
return $set;
return $array;
}
/**
* Calculate the expenses for a budget.
* Returns from the collection the budget limit with the indicated currency ID
*
* @param Budget $budget
* @param BudgetLimit $budgetLimit
* @param Collection $accounts
* @param int $currencyId
* @param Collection $budgetLimits
*
* @return array
* @return BudgetLimit|null
*/
private function calculateExpenses(Budget $budget, BudgetLimit $budgetLimit, Collection $accounts): array
private function budgetLimitInCurrency(int $currencyId, Collection $budgetLimits): ?BudgetLimit
{
$array = [];
$expenses = $this->repository->spentInPeriod(new Collection([$budget]), $accounts, $budgetLimit->start_date, $budgetLimit->end_date);
$array['left'] = 1 === bccomp(bcadd($budgetLimit->amount, $expenses), '0') ? bcadd($budgetLimit->amount, $expenses) : '0';
$array['spent'] = 1 === bccomp(bcadd($budgetLimit->amount, $expenses), '0') ? $expenses : '0';
$array['overspent'] = 1 === bccomp(bcadd($budgetLimit->amount, $expenses), '0') ? '0' : bcadd($expenses, $budgetLimit->amount);
$array['expenses'] = $expenses;
return $array;
return $budgetLimits->first(
static function (BudgetLimit $limit) use ($currencyId) {
return $limit->transaction_currency_id === $currencyId;
}
);
}
}

View File

@ -40,15 +40,4 @@ interface BudgetReportHelperInterface
* @return array
*/
public function getBudgetReport(Carbon $start, Carbon $end, Collection $accounts): array;
/**
* Get budgets and the expenses in each budget.
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return Collection
*/
public function getBudgetsWithExpenses(Carbon $start, Carbon $end, Collection $accounts): Collection;
}

View File

@ -26,8 +26,8 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Account;
use FireflyIII\Models\Budget;
use FireflyIII\Models\Category;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
@ -98,11 +98,24 @@ class PopupReport implements PopupReportInterface
*/
public function byBudget(Budget $budget, array $attributes): array
{
// filter by currency, if set.
$currencyId = $attributes['currencyId'] ?? null;
$currency = null;
if (null !== $currencyId) {
/** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class);
$currency = $repos->find((int)$currencyId);
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($attributes['accounts'])->setRange($attributes['startDate'], $attributes['endDate']);
if (null !== $currency) {
$collector->setCurrency($currency);
}
if (null === $budget->id) {
$collector->setTypes([TransactionType::WITHDRAWAL])->withoutBudget();
}
@ -123,12 +136,25 @@ class PopupReport implements PopupReportInterface
*/
public function byCategory(Category $category, array $attributes): array
{
// filter by currency, if set.
$currencyId = $attributes['currencyId'] ?? null;
$currency = null;
if (null !== $currencyId) {
/** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class);
$currency = $repos->find((int)$currencyId);
}
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($attributes['accounts'])->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
$collector->setAccounts($attributes['accounts'])
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER, TransactionType::DEPOSIT])
->setRange($attributes['startDate'], $attributes['endDate'])->withAccountInformation()
->setCategory($category);
if (null !== $currency) {
$collector->setCurrency($currency);
}
return $collector->getExtractedJournals();
}
@ -143,6 +169,15 @@ class PopupReport implements PopupReportInterface
*/
public function byExpenses(Account $account, array $attributes): array
{
// filter by currency, if set.
$currencyId = $attributes['currencyId'] ?? null;
$currency = null;
if (null !== $currencyId) {
/** @var CurrencyRepositoryInterface $repos */
$repos = app(CurrencyRepositoryInterface::class);
$currency = $repos->find((int)$currencyId);
}
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($account->user);
@ -150,20 +185,15 @@ class PopupReport implements PopupReportInterface
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
$collector->setAccounts(new Collection([$account]))
->setRange($attributes['startDate'], $attributes['endDate'])
->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]);
$journals = $collector->getExtractedJournals();
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
$filtered = [];
// TODO not sure if filter is necessary.
/** @var array $journal */
foreach ($journals as $journal) {
if (in_array($journal['source_account_id'], $report, true)) {
$filtered[] = $journal;
}
if (null !== $currency) {
$collector->setCurrency($currency);
}
return $filtered;
return $collector->getExtractedJournals();
}
/**
@ -179,24 +209,14 @@ class PopupReport implements PopupReportInterface
/** @var JournalRepositoryInterface $repository */
$repository = app(JournalRepositoryInterface::class);
$repository->setUser($account->user);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts(new Collection([$account]))->setRange($attributes['startDate'], $attributes['endDate'])
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
$collector
->setSourceAccounts(new Collection([$account]))
->setDestinationAccounts($attributes['accounts'])
->setRange($attributes['startDate'], $attributes['endDate'])
->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->withAccountInformation();
$journals = $collector->getExtractedJournals();
$report = $attributes['accounts']->pluck('id')->toArray(); // accounts used in this report
// filter the set so the destinations outside of $attributes['accounts'] are not included.
// TODO not sure if filter is necessary.
$filtered = [];
/** @var array $journal */
foreach ($journals as $journal) {
if (in_array($journal['destination_account_id'], $report, true)) {
$filtered[] = $journal;
}
}
return $filtered;
return $collector->getExtractedJournals();
}
}

View File

@ -23,8 +23,6 @@ declare(strict_types=1);
namespace FireflyIII\Helpers\Report;
use Carbon\Carbon;
use FireflyIII\Helpers\Collection\Bill as BillCollection;
use FireflyIII\Helpers\Collection\BillLine;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Helpers\Fiscal\FiscalHelperInterface;
use FireflyIII\Models\Bill;
@ -45,8 +43,6 @@ class ReportHelper implements ReportHelperInterface
/**
* ReportHelper constructor.
*
*
* @param BudgetRepositoryInterface $budgetRepository
*/
public function __construct(BudgetRepositoryInterface $budgetRepository)
@ -66,64 +62,57 @@ class ReportHelper implements ReportHelperInterface
*
* Excludes bills which have not had a payment on the mentioned accounts.
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*
* @param Carbon $start
* @param Carbon $end
* @param Collection $accounts
*
* @return BillCollection
* @return array
*/
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts): BillCollection
public function getBillReport(Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var BillRepositoryInterface $repository */
$repository = app(BillRepositoryInterface::class);
$bills = $repository->getBillsForAccounts($accounts);
$collection = new BillCollection;
$collection->setStartDate($start);
$collection->setEndDate($end);
$report = [
'bills' => [],
];
/** @var Bill $bill */
foreach ($bills as $bill) {
$expectedDates = $repository->getPayDatesInRange($bill, $start, $end);
foreach ($expectedDates as $payDate) {
$endOfPayPeriod = app('navigation')->endOfX($payDate, $bill->repeat_freq, null);
$billId = $bill->id;
$currency = $bill->transactionCurrency;
$current = [
'id' => $bill->id,
'name' => $bill->name,
'active' => $bill->active,
'amount_min' => $bill->amount_min,
'amount_max' => $bill->amount_max,
'currency_id' => $bill->transaction_currency_id,
'currency_code' => $currency->code,
'currency_name' => $currency->name,
'currency_symbol' => $currency->symbol,
'currency_decimal_places' => $currency->decimal_places,
'expected_dates' => $expectedDates->toArray(),
'paid_moments' => [],
];
/** @var Carbon $start */
foreach ($expectedDates as $expectedStart) {
$expectedEnd = app('navigation')->endOfX($expectedStart, $bill->repeat_freq, null);
// is paid in this period maybe?
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($payDate, $endOfPayPeriod)->setBill($bill);
$journals = $collector->getExtractedJournals();
$billLine = new BillLine;
$billLine->setBill($bill);
$billLine->setCurrency($bill->transactionCurrency);
$billLine->setPayDate($payDate);
$billLine->setEndOfPayDate($endOfPayPeriod);
$billLine->setMin((string)$bill->amount_min);
$billLine->setMax((string)$bill->amount_max);
$billLine->setHit(false);
/** @var array $first */
$first = null;
if (count($journals) > 0) {
$first = reset($journals);
}
if (null !== $first) {
$billLine->setTransactionJournalId($first['transaction_journal_id']);
$billLine->setAmount($first['amount']);
$billLine->setLastHitDate($first['date']);
$billLine->setHit(true);
}
if ($billLine->isActive() || $billLine->isHit()) {
$collection->addBill($billLine);
}
$collector->setAccounts($accounts)->setRange($expectedStart, $expectedEnd)->setBill($bill);
$current['paid_moments'][] = $collector->getExtractedJournals();
}
}
$collection->filterBills();
return $collection;
// append to report:
$report['bills'][$billId] = $current;
}
return $report;
}
/**

View File

@ -41,9 +41,9 @@ interface ReportHelperInterface
* @param Carbon $end
* @param Collection $accounts
*
* @return BillCollection
* @return array
*/
public function getBillReport(Carbon $start, Carbon $end, Collection $accounts): BillCollection;
public function getBillReport(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* Generate a list of months.

View File

@ -27,6 +27,7 @@ namespace FireflyIII\Http\Controllers\Account;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Support\Http\Controllers\UserNavigation;
use Illuminate\Http\Request;
/**
@ -34,6 +35,8 @@ use Illuminate\Http\Request;
*/
class DeleteController extends Controller
{
use UserNavigation;
/** @var AccountRepositoryInterface The account repository */
private $repository;
@ -67,6 +70,10 @@ class DeleteController extends Controller
*/
public function delete(Account $account)
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
$typeName = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
$subTitle = (string)trans(sprintf('firefly.delete_%s_account', $typeName), ['name' => $account->name]);
$accountList = app('expandedform')->makeSelectListWithEmpty($this->repository->getAccountsByType([$account->accountType->type]));
@ -89,6 +96,10 @@ class DeleteController extends Controller
*/
public function destroy(Request $request, Account $account)
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
$type = $account->accountType->type;
$typeName = config(sprintf('firefly.shortNamesByFullName.%s', $type));
$name = $account->name;

View File

@ -30,6 +30,7 @@ use FireflyIII\Models\Account;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\ModelInformation;
use FireflyIII\Support\Http\Controllers\UserNavigation;
use Illuminate\Http\Request;
/**
@ -38,7 +39,7 @@ use Illuminate\Http\Request;
*/
class EditController extends Controller
{
use ModelInformation;
use ModelInformation, UserNavigation;
/** @var CurrencyRepositoryInterface The currency repository */
private $currencyRepos;
/** @var AccountRepositoryInterface The account repository */
@ -74,11 +75,13 @@ class EditController extends Controller
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function edit(Request $request, Account $account, AccountRepositoryInterface $repository)
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
$objectType = config('firefly.shortNamesByFullName')[$account->accountType->type];
$subTitle = (string)trans(sprintf('firefly.edit_%s_account', $objectType), ['name' => $account->name]);
$subTitleIcon = config(sprintf('firefly.subIconsByIdentifier.%s', $objectType));
@ -144,6 +147,10 @@ class EditController extends Controller
*/
public function update(AccountFormRequest $request, Account $account)
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
$data = $request->getAccountData();
$this->repository->update($account, $data);

View File

@ -86,6 +86,10 @@ class ReconcileController extends Controller
*/
public function reconcile(Account $account, Carbon $start = null, Carbon $end = null)
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
if (AccountType::ASSET !== $account->accountType->type) {
// @codeCoverageIgnoreStart
session()->flash('error', (string)trans('firefly.must_be_asset_account'));
@ -146,6 +150,10 @@ class ReconcileController extends Controller
*/
public function submit(ReconciliationStoreRequest $request, Account $account, Carbon $start, Carbon $end)
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
Log::debug('In ReconcileController::submit()');
$data = $request->getAll();
@ -178,6 +186,10 @@ class ReconcileController extends Controller
*/
private function createReconciliation(Account $account, Carbon $start, Carbon $end, string $difference): string
{
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
$reconciliation = $this->accountRepos->getReconciliation($account);
$currency = $this->accountRepos->getAccountCurrency($account) ?? app('amount')->getDefaultCurrency();
$source = $reconciliation;

View File

@ -28,7 +28,6 @@ use Exception;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Account;
use FireflyIII\Models\AccountType;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\Http\Controllers\PeriodOverview;
@ -40,7 +39,7 @@ use View;
/**
* Class ShowController
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class ShowController extends Controller
{
@ -73,7 +72,7 @@ class ShowController extends Controller
);
}
/** @noinspection MoreThanThreeArgumentsInspection */
/**
* Show an account.
*
@ -87,8 +86,8 @@ class ShowController extends Controller
*/
public function show(Request $request, Account $account, Carbon $start = null, Carbon $end = null)
{
if (in_array($account->accountType->type, [AccountType::INITIAL_BALANCE, AccountType::RECONCILIATION], true)) {
return $this->redirectToOriginalAccount($account); // @codeCoverageIgnore
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
/** @var Carbon $start */
@ -139,15 +138,14 @@ class ShowController extends Controller
* @param Request $request
* @param Account $account
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector|View
*
*
* @throws Exception
*/
public function showAll(Request $request, Account $account)
{
if (AccountType::INITIAL_BALANCE === $account->accountType->type) {
return $this->redirectToOriginalAccount($account); // @codeCoverageIgnore
if (!$this->isEditableAccount($account)) {
return $this->redirectAccountToAccount($account); // @codeCoverageIgnore
}
$isLiability = $this->repository->isLiability($account);
$objectType = config(sprintf('firefly.shortNamesByFullName.%s', $account->accountType->type));
$end = new Carbon;

View File

@ -18,7 +18,6 @@
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
/** @noinspection PhpDynamicAsStaticMethodCallInspection */
declare(strict_types=1);
namespace FireflyIII\Http\Controllers\Auth;
@ -26,8 +25,6 @@ namespace FireflyIII\Http\Controllers\Auth;
use Adldap;
use DB;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\User;
use Illuminate\Cookie\CookieJar;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use Log;
@ -85,61 +82,35 @@ class LoginController extends Controller
}
$this->validateLogin($request);
/** Copied directly from AuthenticatesUsers, but with logging added: */
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
if (method_exists($this, 'hasTooManyLoginAttempts') && $this->hasTooManyLoginAttempts($request)) {
Log::channel('audit')->info(sprintf('Login for user "%s" was locked out.', $request->get('email')));
$this->fireLockoutEvent($request);
/** @noinspection PhpInconsistentReturnPointsInspection */
/** @noinspection PhpVoidFunctionResultUsedInspection */
return $this->sendLockoutResponse($request);
}
/** Copied directly from AuthenticatesUsers, but with logging added: */
if ($this->attemptLogin($request)) {
Log::channel('audit')->info(sprintf('User "%s" has been logged in.', $request->get('email')));
// user is logged in. Save in session if the user requested session to be remembered:
$request->session()->put('remember_login', $request->filled('remember'));
Log::debug(sprintf('Redirect after login is %s.', $this->redirectPath()));
/** @noinspection PhpInconsistentReturnPointsInspection */
/** @noinspection PhpVoidFunctionResultUsedInspection */
$response = $this->sendLoginResponse($request);
Log::debug(sprintf('Response Location header: %s', $response->headers->get('location')));
return $response;
return $this->sendLoginResponse($request);
}
/** Copied directly from AuthenticatesUsers, but with logging added: */
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
Log::channel('audit')->info(sprintf('Login attempt for user "%s" failed.', $request->get('email')));
/** @noinspection PhpInconsistentReturnPointsInspection */
/** @noinspection PhpVoidFunctionResultUsedInspection */
return $this->sendFailedLoginResponse($request);
}
/**
* Log the user out of the application.
*
* @param Request $request
* @param CookieJar $cookieJar
*
* @return $this|\Illuminate\Http\RedirectResponse
*/
public function logout(Request $request, CookieJar $cookieJar)
{
$this->guard()->logout();
$request->session()->invalidate();
$cookie = $cookieJar->forget('twoFactorAuthenticated');
return redirect('/')->withCookie($cookie);
}
/**
* Show the application's login form.
*
@ -151,20 +122,16 @@ class LoginController extends Controller
{
$count = DB::table('users')->count();
$loginProvider = config('firefly.login_provider');
$pageTitle = (string)trans('firefly.login_page_title');
$title = (string)trans('firefly.login_page_title');
if (0 === $count && 'eloquent' === $loginProvider) {
return redirect(route('register')); // @codeCoverageIgnore
}
// forget 2fa session thing.
$request->session()->forget('twoFactorAuthenticated');
// is allowed to?
$singleUserMode = app('fireflyconfig')->get('single_user_mode', config('firefly.configuration.single_user_mode'))->data;
$userCount = User::count();
$allowRegistration = true;
$allowReset = true;
if (true === $singleUserMode && $userCount > 0) {
if (true === $singleUserMode && $count > 0) {
$allowRegistration = false;
}
@ -177,6 +144,6 @@ class LoginController extends Controller
$email = $request->old('email');
$remember = $request->old('remember');
return view('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'pageTitle'));
return view('auth.login', compact('allowRegistration', 'email', 'remember', 'allowReset', 'title'));
}
}

View File

@ -43,7 +43,7 @@ use Symfony\Component\HttpFoundation\ParameterBag;
/**
* Class BillController.
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
*
*/
class BillController extends Controller
{
@ -339,8 +339,6 @@ class BillController extends Controller
*
* @return RedirectResponse
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function store(BillFormRequest $request): RedirectResponse
{

View File

@ -25,18 +25,15 @@ namespace FireflyIII\Http\Controllers\Budget;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Http\Requests\BudgetIncomeRequest;
use FireflyIII\Models\Budget;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Support\Http\Controllers\DateCalculation;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Log;
/**
* Class AmountController
@ -75,8 +72,6 @@ class AmountController extends Controller
* @param Budget $budget
*
* @return JsonResponse
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function amount(Request $request, Budget $budget): JsonResponse
{

View File

@ -74,8 +74,6 @@ class IndexController extends Controller
* @param Carbon|null $end
*
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
public function index(Request $request, Carbon $start = null, Carbon $end = null)
{

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* CreateController.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -100,4 +101,4 @@ class CreateController extends Controller
return $redirect;
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* DeleteController.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -89,4 +90,4 @@ class DeleteController extends Controller
return redirect($this->getPreviousUri('categories.delete.uri'));
}
}
}

View File

@ -1,4 +1,5 @@
<?php
declare(strict_types=1);
/**
* EditController.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
@ -106,4 +107,4 @@ class EditController extends Controller
return $redirect;
}
}
}

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