Compare commits

...

20 Commits
4.0.0 ... 4.0.1

Author SHA1 Message Date
James Cole
5a47391a64 Merge branch 'release/4.0.1' 2016-10-04 20:13:50 +02:00
James Cole
a31ac79173 New version. 2016-10-04 20:13:40 +02:00
James Cole
0d0a604254 Changelog for 4.0.1 [skip ci] 2016-10-04 20:13:09 +02:00
James Cole
724d25f2c2 Merge branch 'develop'
* develop:
  Fixed some rare bugs.
  Extra clear button to reapply rules #307
  Fix trim when null [skip ci]
  Fixed a bug where incoming transactions would not be properly filtered in several reports.
  Removed for #334
  Fix #337 [skip ci]
  Fix #335
  Remove account extra text #336 [skip ci]
  Fixes bug #338
  Refer to correct page [skip ci]
  Catch unset row.
2016-10-04 20:08:35 +02:00
James Cole
8ed22d452d Merge pull request #342 from tomwerf/master
ING Import
2016-10-04 20:02:34 +02:00
Tom van der Werf
d7fef45a56 added some comments 2016-10-04 17:50:01 +00:00
Tom van der Werf
dc22802dec removed some debug commands 2016-10-04 17:30:49 +00:00
Tom van der Werf
ce5af7b1d9 Better descriptions for ING accounts 2016-10-03 17:08:24 +00:00
James Cole
0a147e5c9c Fixed some rare bugs. 2016-10-02 15:09:43 +02:00
James Cole
7d21255f7f Extra clear button to reapply rules #307 2016-10-02 08:14:11 +02:00
James Cole
13f952f182 Fix trim when null [skip ci] 2016-10-01 09:41:16 +02:00
James Cole
b494be228b Fixed a bug where incoming transactions would not be properly filtered in several reports. 2016-10-01 09:37:18 +02:00
James Cole
0fdaac53d0 Removed for #334 2016-10-01 08:49:33 +02:00
James Cole
e1b3a08878 Fix #337 [skip ci] 2016-10-01 08:49:02 +02:00
James Cole
dc893588b0 Fix #335 2016-10-01 08:48:13 +02:00
James Cole
b9fcc443ec Remove account extra text #336 [skip ci] 2016-10-01 08:45:14 +02:00
James Cole
d8586c8043 Fixes bug #338 2016-09-29 19:17:24 +02:00
James Cole
4252a3e53b Refer to correct page [skip ci] 2016-09-29 07:04:58 +02:00
James Cole
dbb5cdb9cf Catch unset row. 2016-09-29 07:02:47 +02:00
James Cole
3ec8a8c375 Merge branch 'release/4.0.0' into develop 2016-09-26 18:37:33 +02:00
20 changed files with 232 additions and 131 deletions

View File

@@ -2,7 +2,35 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). This project adheres to [Semantic Versioning](http://semver.org/).
## [4.0.0] - 2015-05-25 ## [4.0.1] - 2016-10-04
### Added
- New ING import specific by @tomwerf
- New Presidents Choice specific to fix #307
- Added some trimming (#335)
### Changed
- Initial release.
### Deprecated
- Initial release.
### Removed
- Initial release.
### Fixed
- Fixed a bug where incoming transactions would not be properly filtered in several reports.
- #334 by @cyberkov
- #337
- #336
- #338 found by @roberthorlings
### Security
- Initial release.
## [4.0.0] - 2015-09-26
### Added ### Added
- Upgraded to Laravel 5.3, most other libraries upgraded as well. - Upgraded to Laravel 5.3, most other libraries upgraded as well.
- Added GBP as currency, thanks to @Mortalife - Added GBP as currency, thanks to @Mortalife

View File

@@ -221,6 +221,33 @@ class AccountCrud implements AccountCrudInterface
return $result; return $result;
} }
/**
* @param array $types
*
* @return Collection
*/
public function getActiveAccountsByType(array $types): Collection
{
/** @var Collection $result */
$query = $this->user->accounts()->with(
['accountmeta' => function (HasMany $query) {
$query->where('name', 'accountRole');
}]
);
if (count($types) > 0) {
$query->accountTypeIn($types);
}
$query->where('active', 1);
$result = $query->get(['accounts.*']);
$result = $result->sortBy(
function (Account $account) {
return strtolower($account->name);
}
);
return $result;
}
/** /**
* @param array $data * @param array $data
* *

View File

@@ -75,6 +75,13 @@ interface AccountCrudInterface
*/ */
public function getAccountsByType(array $types): Collection; public function getAccountsByType(array $types): Collection;
/**
* @param array $types
*
* @return Collection
*/
public function getActiveAccountsByType(array $types): Collection;
/** /**
* @param array $data * @param array $data
* *

View File

@@ -295,14 +295,14 @@ class AccountController extends Controller
public function store(AccountFormRequest $request, AccountCrudInterface $crud) public function store(AccountFormRequest $request, AccountCrudInterface $crud)
{ {
$accountData = [ $accountData = [
'name' => $request->input('name'), 'name' => trim($request->input('name')),
'accountType' => $request->input('what'), 'accountType' => $request->input('what'),
'virtualBalance' => round($request->input('virtualBalance'), 2), 'virtualBalance' => round($request->input('virtualBalance'), 2),
'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')), 'virtualBalanceCurrency' => intval($request->input('amount_currency_id_virtualBalance')),
'active' => true, 'active' => true,
'user' => auth()->user()->id, 'user' => auth()->user()->id,
'iban' => $request->input('iban'), 'iban' => trim($request->input('iban')),
'accountNumber' => $request->input('accountNumber'), 'accountNumber' => trim($request->input('accountNumber')),
'accountRole' => $request->input('accountRole'), 'accountRole' => $request->input('accountRole'),
'openingBalance' => round($request->input('openingBalance'), 2), 'openingBalance' => round($request->input('openingBalance'), 2),
'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')), 'openingBalanceDate' => new Carbon((string)$request->input('openingBalanceDate')),

View File

@@ -1,84 +0,0 @@
<?php
/**
* AuthController.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Http\Controllers\Auth;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\User;
use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers;
use Illuminate\Foundation\Auth\ThrottlesLogins;
use Validator;
/**
* Class AuthController
*
* @package FireflyIII\Http\Controllers\Auth
*/
class AuthController extends Controller
{
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
/**
* Where to redirect users after login / registration.
*
* @var string
*/
protected $redirectTo = '/home';
/**
* Create a new authentication controller instance.
*
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
parent::__construct();
}
/**
* Create a new user instance after a valid registration.
*
* @param array $data
*
* @return User
*/
protected function create(array $data)
{
return User::create(
[
'email' => $data['email'],
'password' => bcrypt($data['password']),
]
);
}
/**
* Get a validator for an incoming registration request.
*
* @param array $data
*
* @return \Illuminate\Contracts\Validation\Validator
*/
protected function validator(array $data)
{
return Validator::make(
$data, [
'email' => 'required|email|max:255|unique:users',
'password' => 'required|confirmed|min:6',
]
);
}
}

View File

@@ -263,7 +263,7 @@ class CategoryController extends Controller
public function store(CategoryFormRequest $request, CRI $repository) public function store(CategoryFormRequest $request, CRI $repository)
{ {
$categoryData = [ $categoryData = [
'name' => $request->input('name'), 'name' => trim($request->input('name')),
'user' => auth()->user()->id, 'user' => auth()->user()->id,
]; ];
$category = $repository->store($categoryData); $category = $repository->store($categoryData);

View File

@@ -13,6 +13,7 @@ namespace FireflyIII\Http\Controllers;
use Carbon\Carbon; use Carbon\Carbon;
use ExpandedForm; use ExpandedForm;
use FireflyIII\Crud\Account\AccountCrudInterface;
use FireflyIII\Events\TransactionJournalStored; use FireflyIII\Events\TransactionJournalStored;
use FireflyIII\Events\TransactionJournalUpdated; use FireflyIII\Events\TransactionJournalUpdated;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
@@ -59,12 +60,12 @@ class TransactionController extends Controller
*/ */
public function create(string $what = TransactionType::DEPOSIT) public function create(string $what = TransactionType::DEPOSIT)
{ {
$crud = app('FireflyIII\Crud\Account\AccountCrudInterface'); $crud = app(AccountCrudInterface::class);
$budgetRepository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface'); $budgetRepository = app('FireflyIII\Repositories\Budget\BudgetRepositoryInterface');
$piggyRepository = app('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface'); $piggyRepository = app('FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface');
$what = strtolower($what); $what = strtolower($what);
$uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size'))); $uploadSize = min(Steam::phpBytes(ini_get('upload_max_filesize')), Steam::phpBytes(ini_get('post_max_size')));
$assetAccounts = ExpandedForm::makeSelectList($crud->getAccountsByType(['Default account', 'Asset account'])); $assetAccounts = ExpandedForm::makeSelectList($crud->getActiveAccountsByType(['Default account', 'Asset account']));
$budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets()); $budgets = ExpandedForm::makeSelectListWithEmpty($budgetRepository->getActiveBudgets());
$piggyBanks = $piggyRepository->getPiggyBanksWithAmount(); $piggyBanks = $piggyRepository->getPiggyBanksWithAmount();
$piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks); $piggies = ExpandedForm::makeSelectListWithEmpty($piggyBanks);

View File

@@ -43,11 +43,11 @@ class JournalFormRequest extends Request
return [ return [
'what' => $this->get('what'), 'what' => $this->get('what'),
'description' => $this->get('description'), 'description' => trim($this->get('description')),
'source_account_id' => intval($this->get('source_account_id')), 'source_account_id' => intval($this->get('source_account_id')),
'source_account_name' => $this->getFieldOrEmptyString('source_account_name'), 'source_account_name' => trim($this->getFieldOrEmptyString('source_account_name')),
'destination_account_id' => intval($this->get('destination_account_id')), 'destination_account_id' => intval($this->get('destination_account_id')),
'destination_account_name' => $this->getFieldOrEmptyString('destination_account_name'), 'destination_account_name' => trim($this->getFieldOrEmptyString('destination_account_name')),
'amount' => round($this->get('amount'), 2), 'amount' => round($this->get('amount'), 2),
'user' => auth()->user()->id, 'user' => auth()->user()->id,
'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')), 'amount_currency_id_amount' => intval($this->get('amount_currency_id_amount')),
@@ -56,7 +56,7 @@ class JournalFormRequest extends Request
'book_date' => $this->getDateOrNull('book_date'), 'book_date' => $this->getDateOrNull('book_date'),
'process_date' => $this->getDateOrNull('process_date'), 'process_date' => $this->getDateOrNull('process_date'),
'budget_id' => intval($this->get('budget_id')), 'budget_id' => intval($this->get('budget_id')),
'category' => $this->getFieldOrEmptyString('category'), 'category' => trim($this->getFieldOrEmptyString('category')),
'tags' => explode(',', $tags), 'tags' => explode(',', $tags),
'piggy_bank_id' => intval($this->get('piggy_bank_id')), 'piggy_bank_id' => intval($this->get('piggy_bank_id')),
@@ -64,8 +64,8 @@ class JournalFormRequest extends Request
'due_date' => $this->getDateOrNull('due_date'), 'due_date' => $this->getDateOrNull('due_date'),
'payment_date' => $this->getDateOrNull('payment_date'), 'payment_date' => $this->getDateOrNull('payment_date'),
'invoice_date' => $this->getDateOrNull('invoice_date'), 'invoice_date' => $this->getDateOrNull('invoice_date'),
'internal_reference' => $this->get('internal_reference'), 'internal_reference' => trim(strval($this->get('internal_reference'))),
'notes' => $this->get('notes'), 'notes' => trim(strval($this->get('notes'))),
]; ];
} }

View File

@@ -181,13 +181,13 @@ class ImportValidator
Log::debug(sprintf('No account named %s of type %s, create new account.', $account->name, $type)); Log::debug(sprintf('No account named %s of type %s, create new account.', $account->name, $type));
$result = $repository->store( $result = $repository->store(
[ [
'user' => $this->user->id, 'user' => $this->user->id,
'accountType' => config('firefly.shortNamesByFullName.' . $type), 'accountType' => config('firefly.shortNamesByFullName.' . $type),
'name' => $account->name, 'name' => $account->name,
'virtualBalance' => 0, 'virtualBalance' => 0,
'active' => true, 'active' => true,
'iban' => null, 'iban' => null,
'openingBalance' => 0, 'openingBalance' => 0,
] ]
); );
} }
@@ -262,6 +262,7 @@ class ImportValidator
$entry->valid = false; $entry->valid = false;
Log::warning('Cannot import entry. Asset account is NULL and import account is also NULL.'); Log::warning('Cannot import entry. Asset account is NULL and import account is also NULL.');
return $entry;
} }
Log::debug('Asset account is OK.', ['id' => $entry->fields['asset-account']->id, 'name' => $entry->fields['asset-account']->name]); Log::debug('Asset account is OK.', ['id' => $entry->fields['asset-account']->id, 'name' => $entry->fields['asset-account']->name]);

View File

@@ -50,9 +50,15 @@ class AbnAmroDescription implements SpecificInterface
public function run(array $row): array public function run(array $row): array
{ {
$this->row = $row; $this->row = $row;
if (!isset($row[7])) {
return $row;
}
// Try to parse the description in known formats. // Try to parse the description in known formats.
$parsed = $this->parseSepaDescription() || $this->parseTRTPDescription() || $this->parseGEABEADescription() || $this->parseABNAMRODescription(); $parsed = $this->parseSepaDescription() || $this->parseTRTPDescription() || $this->parseGEABEADescription() || $this->parseABNAMRODescription();
// If the description could not be parsed, specify an unknown opposing // If the description could not be parsed, specify an unknown opposing
// account, as an opposing account is required // account, as an opposing account is required
if (!$parsed) { if (!$parsed) {

View File

@@ -0,0 +1,112 @@
<?php
/**
* IngDescription.php
* Copyright (C) 2016 thegrumpydictator@gmail.com
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
declare(strict_types = 1);
namespace FireflyIII\Import\Specifics;
/**
* Class IngDescription
*
* Parses the description from CSV files for Ing bank accounts.
*
* With Mutation 'InternetBankieren', 'Overschrijving', 'Verzamelbetaling' and 'Incasso' the
* Name of Opposing account the Opposing IBAN number are in the Description
* This class will remove them
* Add Name in description by 'Betaalautomaat' so those are easily recognizable
*
* @package FireflyIII\Import\Specifics
*/
class IngDescription implements SpecificInterface
{
/** @var array */
public $row;
/**
* @return string
*/
public static function getDescription(): string
{
return 'Create better descriptions in ING import files.';
}
/**
* @return string
*/
public static function getName(): string
{
return 'ING description';
}
/**
* @param array $row
*
* @return array
*/
public function run(array $row): array
{
$this->row = $row;
if (count($this->row) >= 8) { // check if the array is correct
switch ($this->row[4]) { // Get value for the mutation type
case 'GT': // InternetBanieren
case 'OV': // Overschrijving
case 'VZ': // Verzamelbetaling
case 'IC': // Incasso
$this->removeIBANIngDescription();
$this->removeNameIngDescription();
break;
case 'BA' : // Betaalautomaat
$this->addNameIngDescription();
break;
}
}
return $this->row;
}
/**
* Remove IBAN number out of the description
* Default description of Description is: Naam: <OPPOS NAME> Omschrijving: <DESCRIPTION> IBAN: <OPPOS IBAN NR>
*
* @return bool true
*/
protected function removeIBANIngDescription()
{
// Try replace the iban number with nothing. The IBAN nr is found in the third row
$this->row[8] = preg_replace('/\sIBAN:\s'.$this->row[3].'/', '', $this->row[8]);
return true;
}
/**
* Remove name from the description (Remove everything before the description incl the word 'Omschrijving' )
*
* @return bool true
*/
protected function removeNameIngDescription()
{
// Try remove everything bevore the 'Omschrijving'
$this->row[8] = preg_replace('/.+Omschrijving: /', '', $this->row[8]);
return true;
}
/**
* Add the Opposing name from cell 1 in the description for Betaalautomaten
* Otherwise the description is only: 'Pasvolgnr:<nr> <date> Transactie:<NR> Term:<nr>'
*
* @return bool true
*/
protected function addNameIngDescription()
{
$this->row[8] = $this->row[1]. " " . $this->row[8];
return true;
}
}

View File

@@ -377,7 +377,10 @@ class AccountRepository implements AccountRepositoryInterface
* The destination of a transfer must be one of the $accounts in order to * The destination of a transfer must be one of the $accounts in order to
* be included. Otherwise, it would not be income. * be included. Otherwise, it would not be income.
*/ */
if (in_array($journal->destination_account_id, $accountIds)) { $destinations = TransactionJournal::destinationAccountList($journal)->pluck('id')->toArray();
if (count(array_intersect($destinations, $accountIds)) > 0) {
// at least one of $target is in $haystack
return true; return true;
} }

View File

@@ -189,22 +189,22 @@ class BillRepository implements BillRepositoryInterface
'bills.active', 'bills.active',
'bills.name_encrypted', 'bills.name_encrypted',
'bills.match_encrypted']; 'bills.match_encrypted'];
$ids = $accounts->pluck('id')->toArray(); $ids = $accounts->pluck('id')->toArray();
$set = $this->user->bills() $set = $this->user->bills()
->leftJoin( ->leftJoin(
'transaction_journals', function (JoinClause $join) { 'transaction_journals', function (JoinClause $join) {
$join->on('transaction_journals.bill_id', '=', 'bills.id')->whereNull('transaction_journals.deleted_at'); $join->on('transaction_journals.bill_id', '=', 'bills.id')->whereNull('transaction_journals.deleted_at');
} }
) )
->leftJoin( ->leftJoin(
'transactions', function (JoinClause $join) { 'transactions', function (JoinClause $join) {
$join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0); $join->on('transaction_journals.id', '=', 'transactions.transaction_journal_id')->where('transactions.amount', '<', 0);
} }
) )
->whereIn('transactions.account_id', $ids) ->whereIn('transactions.account_id', $ids)
->whereNull('transaction_journals.deleted_at') ->whereNull('transaction_journals.deleted_at')
->groupBy($fields) ->groupBy($fields)
->get($fields); ->get($fields);
$set = $set->sortBy( $set = $set->sortBy(
function (Bill $bill) { function (Bill $bill) {

View File

@@ -143,7 +143,7 @@ class TagRepository implements TagRepositoryInterface
->transactionJournals() ->transactionJournals()
->sortCorrectly() ->sortCorrectly()
->expanded() ->expanded()
->groupBy(['tag_transaction_journal.tag_id']) ->groupBy(['tag_transaction_journal.tag_id','tag_transaction_journal.transaction_journal_id'])
->get(TransactionJournal::queryFields()); ->get(TransactionJournal::queryFields());
return $journals; return $journals;

View File

@@ -48,7 +48,7 @@ class SetBudget implements ActionInterface
public function act(TransactionJournal $journal): bool public function act(TransactionJournal $journal): bool
{ {
/** @var BudgetRepositoryInterface $repository */ /** @var BudgetRepositoryInterface $repository */
$repository = app(BudgetRepositoryInterface::class); $repository = app(BudgetRepositoryInterface::class, [$journal->user]);
$search = $this->action->action_value; $search = $this->action->action_value;
$budgets = $repository->getActiveBudgets(); $budgets = $repository->getActiveBudgets();
$budget = $budgets->filter( $budget = $budgets->filter(

View File

@@ -8,6 +8,7 @@ return [
* Configuration for the CSV specifics. * Configuration for the CSV specifics.
*/ */
'import_specifics' => [ 'import_specifics' => [
'IngDescription' => 'FireflyIII\Import\Specifics\IngDescription',
'RabobankDescription' => 'FireflyIII\Import\Specifics\RabobankDescription', 'RabobankDescription' => 'FireflyIII\Import\Specifics\RabobankDescription',
'AbnAmroDescription' => 'FireflyIII\Import\Specifics\AbnAmroDescription', 'AbnAmroDescription' => 'FireflyIII\Import\Specifics\AbnAmroDescription',
'PresidentsChoice' => 'FireflyIII\Import\Specifics\PresidentsChoice', 'PresidentsChoice' => 'FireflyIII\Import\Specifics\PresidentsChoice',

View File

@@ -12,7 +12,7 @@ return [
'single_user_mode' => true, 'single_user_mode' => true,
], ],
'chart' => 'chartjs', 'chart' => 'chartjs',
'version' => '4.0.0', 'version' => '4.0.1',
'csv_import_enabled' => true, 'csv_import_enabled' => true,
'maxUploadSize' => 5242880, 'maxUploadSize' => 5242880,
'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'], 'allowedMimes' => ['image/png', 'image/jpeg', 'application/pdf'],

View File

@@ -17,6 +17,6 @@ return [
'Please follow the instructions on the following page: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-3.7.0', 'Please follow the instructions on the following page: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-3.7.0',
'3.8' => 'This version of Firefly III requires PHP 7.0.', '3.8' => 'This version of Firefly III requires PHP 7.0.',
'3.10' => 'Please find the full upgrade instructions here: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-3.10', '3.10' => 'Please find the full upgrade instructions here: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-3.10',
'4.0' => 'Please find the full upgrade instructions here: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-3.10', '4.0' => 'Please find the full upgrade instructions here: https://github.com/JC5/firefly-iii/wiki/Upgrade-to-4.0',
], ],
]; ];

View File

@@ -6,13 +6,6 @@
{% block content %} {% block content %}
<div class="row">
<div class="col-lg-6 col-md-8 col-sm-12 col-xs-12">
<p>
{{ ('accountExtraHelp_'~what)|_ }}
</p>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-lg-12 col-md-12 col-sm-12"> <div class="col-lg-12 col-md-12 col-sm-12">
<div class="box" id="account-index-{{ what }}"> <div class="box" id="account-index-{{ what }}">

View File

@@ -104,6 +104,12 @@
class="btn btn-danger"><span class="btn btn-danger"><span
class="fa fa-fw fa-trash"></span></a> class="fa fa-fw fa-trash"></span></a>
</div> </div>
<br />
<div class="btn-group btn-group-xs">
<a href="{{ route('rules.rule-group.select_transactions',ruleGroup.id) }}" class="btn btn-default"
title=" {{ 'execute_on_existing_transactions_short'|_ }}">
<i class="fa fa-fw fa-check-circle"></i></a>
</div>
</td> </td>
<td> <td>