This commit is contained in:
James Cole
2018-04-08 16:27:52 +02:00
parent 7583698ee5
commit 8f0e36a8e4
18 changed files with 377 additions and 165 deletions

View File

@@ -52,7 +52,7 @@ class BillFactory
'match' => 'MIGRATED_TO_RULES', 'match' => 'MIGRATED_TO_RULES',
'amount_min' => $data['amount_min'], 'amount_min' => $data['amount_min'],
'user_id' => $this->user->id, 'user_id' => $this->user->id,
'currency_id' => $data['currency_id'], 'transaction_currency_id' => $data['transaction_currency_id'],
'amount_max' => $data['amount_max'], 'amount_max' => $data['amount_max'],
'date' => $data['date'], 'date' => $data['date'],
'repeat_freq' => $data['repeat_freq'], 'repeat_freq' => $data['repeat_freq'],

View File

@@ -136,7 +136,7 @@ class BillController extends Controller
* *
* @return View * @return View
*/ */
public function edit(Request $request, Bill $bill) public function edit(Request $request, CurrencyRepositoryInterface $repository, Bill $bill)
{ {
$periods = []; $periods = [];
foreach (config('firefly.bill_periods') as $current) { foreach (config('firefly.bill_periods') as $current) {
@@ -152,6 +152,8 @@ class BillController extends Controller
$currency = app('amount')->getDefaultCurrency(); $currency = app('amount')->getDefaultCurrency();
$bill->amount_min = round($bill->amount_min, $currency->decimal_places); $bill->amount_min = round($bill->amount_min, $currency->decimal_places);
$bill->amount_max = round($bill->amount_max, $currency->decimal_places); $bill->amount_max = round($bill->amount_max, $currency->decimal_places);
$defaultCurrency = app('amount')->getDefaultCurrency();
$currencies = ExpandedForm::makeSelectList($repository->get());
$preFilled = [ $preFilled = [
'notes' => '', 'notes' => '',
@@ -167,7 +169,7 @@ class BillController extends Controller
$request->session()->forget('bills.edit.fromUpdate'); $request->session()->forget('bills.edit.fromUpdate');
return view('bills.edit', compact('subTitle', 'periods', 'bill')); return view('bills.edit', compact('subTitle', 'periods', 'bill', 'defaultCurrency', 'currencies'));
} }
/** /**
@@ -296,6 +298,12 @@ class BillController extends Controller
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
} }
// do return to original bill form?
$return = 'false';
if (1 === (int)$request->get('create_another')) {
$return = 'true';
}
// find first rule group, or create one: // find first rule group, or create one:
$count = $ruleGroupRepository->count(); $count = $ruleGroupRepository->count();
if ($count === 0) { if ($count === 0) {
@@ -309,9 +317,10 @@ class BillController extends Controller
$group = $ruleGroupRepository->getActiveGroups(auth()->user())->first(); $group = $ruleGroupRepository->getActiveGroups(auth()->user())->first();
} }
// redirect to page that will create a new rule. // redirect to page that will create a new rule.
return redirect(route('rules.create', [$group->id]) . '?fromBill=' . $bill->id); $params = http_build_query(['fromBill' => $bill->id, 'return' => $return]);
return redirect(route('rules.create', [$group->id]) . '?' . $params);
} }
/** /**

View File

@@ -31,6 +31,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface; use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface; use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface; use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\Journal\JournalRepositoryInterface; use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
use FireflyIII\Repositories\Tag\TagRepositoryInterface; use FireflyIII\Repositories\Tag\TagRepositoryInterface;
use FireflyIII\Support\CacheProperties; use FireflyIII\Support\CacheProperties;
@@ -119,6 +120,19 @@ class AutoCompleteController extends Controller
return response()->json($return); return response()->json($return);
} }
/**
* @param CurrencyRepositoryInterface $repository
*
* @return \Illuminate\Http\JsonResponse
*/
public function currencyNames(CurrencyRepositoryInterface $repository)
{
$return = $repository->get()->pluck('name')->toArray();
sort($return);
return response()->json($return);
}
/** /**
* Returns a JSON list of all beneficiaries. * Returns a JSON list of all beneficiaries.
* *

View File

@@ -29,6 +29,7 @@ use FireflyIII\Http\Requests\SelectTransactionsRequest;
use FireflyIII\Http\Requests\TestRuleFormRequest; use FireflyIII\Http\Requests\TestRuleFormRequest;
use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions; use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
use FireflyIII\Models\AccountType; use FireflyIII\Models\AccountType;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Rule; use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction; use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup; use FireflyIII\Models\RuleGroup;
@@ -39,8 +40,10 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface; use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\TransactionMatcher; use FireflyIII\TransactionRules\TransactionMatcher;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Log;
use Preferences; use Preferences;
use Session; use Session;
use Throwable;
use View; use View;
/** /**
@@ -73,81 +76,47 @@ class RuleController extends Controller
* *
* @return View * @return View
* *
*/ */
public function create(Request $request, RuleGroupRepositoryInterface $ruleGroupRepository, BillRepositoryInterface $billRepository, RuleGroup $ruleGroup) public function create(Request $request, RuleGroupRepositoryInterface $ruleGroupRepository, BillRepositoryInterface $billRepository, RuleGroup $ruleGroup)
{ {
$bill = null; $bill = null;
$billId = (int)$request->get('fromBill'); $billId = (int)$request->get('fromBill');
$preFilled = []; $preFilled = [];
// count for possible present previous entered triggers/actions. $groups = ExpandedForm::makeSelectList($ruleGroupRepository->get());
$triggerCount = 0;
$actionCount = 0;
// collection of those triggers/actions.
$oldTriggers = []; $oldTriggers = [];
$oldActions = []; $oldActions = [];
$returnToBill = false;
if ($request->get('return') === 'true') {
$returnToBill = true;
}
// has bill?
if ($billId > 0) {
$bill = $billRepository->find($billId);
}
// has old input? // has old input?
if ($request->old()) { if ($request->old()) {
// process old triggers.
$oldTriggers = $this->getPreviousTriggers($request); $oldTriggers = $this->getPreviousTriggers($request);
$triggerCount = \count($oldTriggers);
// process old actions
$oldActions = $this->getPreviousActions($request); $oldActions = $this->getPreviousActions($request);
$actionCount = \count($oldActions);
} }
if ($billId > 0) { // has existing bill refered to in URI?
$bill = $billRepository->find($billId); if (null !== $bill && !$request->old()) {
// create some sensible defaults: // create some sensible defaults:
$preFilled['title'] = trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]); $preFilled['title'] = trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]);
$preFilled['description'] = trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]); $preFilled['description'] = trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]);
$request->session()->flash('preFilled', $preFilled); $request->session()->flash('preFilled', $preFilled);
// pretend there are old triggers, so the page will fill them in: // get triggers and actions for bill:
$oldTriggers[] = view( $oldTriggers = $this->getTriggersForBill($bill);
'rules.partials.trigger', $oldActions = $this->getActionsForBill($bill);
[
'oldTrigger' => 'amount_more',
'oldValue' => round($bill->amount_min,12),
'oldChecked' => false,
'count' => 1,
]
)->render();
$oldTriggers[] = view(
'rules.partials.trigger',
[
'oldTrigger' => 'amount_less',
'oldValue' => round($bill->amount_max,12),
'oldChecked' => false,
'count' => 2,
]
)->render();
$oldTriggers[] = view(
'rules.partials.trigger',
[
'oldTrigger' => 'description_contains',
'oldValue' => $bill->name,12,
'oldChecked' => false,
'count' => 3,
]
)->render();
$oldActions[] = view(
'rules.partials.action',
[
'oldAction' => 'link_to_bill',
'oldValue' => $bill->name,
'oldChecked' => false,
'count' => 1,
]
)->render();
} }
$triggerCount = \count($oldTriggers);
$actionCount = \count($oldActions);
$subTitleIcon = 'fa-clone'; $subTitleIcon = 'fa-clone';
$subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]); $subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
@@ -159,7 +128,10 @@ class RuleController extends Controller
return view( return view(
'rules.rule.create', 'rules.rule.create',
compact('subTitleIcon', 'oldTriggers', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle') compact(
'subTitleIcon', 'oldTriggers', 'returnToBill', 'groups', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup',
'subTitle'
)
); );
} }
@@ -380,24 +352,32 @@ class RuleController extends Controller
/** /**
* @param RuleFormRequest $request * @param RuleFormRequest $request
* @param RuleRepositoryInterface $repository * @param RuleRepositoryInterface $repository
* @param RuleGroup $ruleGroup
* *
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
*/ */
public function store(RuleFormRequest $request, RuleRepositoryInterface $repository, RuleGroup $ruleGroup) public function store(RuleFormRequest $request, RuleRepositoryInterface $repository)
{ {
$data = $request->getRuleData(); $data = $request->getRuleData();
$data['rule_group_id'] = $ruleGroup->id;
$rule = $repository->store($data); $rule = $repository->store($data);
Session::flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title])); session()->flash('success', trans('firefly.stored_new_rule', ['title' => $rule->title]));
Preferences::mark(); Preferences::mark();
// redirect to show bill.
if ($request->get('return_to_bill') === 'true' && (int)$request->get('bill_id') > 0) {
return redirect(route('bills.show', [(int)$request->get('bill_id')]));
}
// redirect to new bill creation.
if ((int)$request->get('bill_id') > 0) {
return redirect(route('bills.create'));
}
if (1 === (int)$request->get('create_another')) { if (1 === (int)$request->get('create_another')) {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
Session::put('rules.create.fromStore', true); Session::put('rules.create.fromStore', true);
return redirect(route('rules.create', [$ruleGroup]))->withInput(); return redirect(route('rules.create', [$data['rule_group_id']]))->withInput();
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
} }
@@ -416,7 +396,6 @@ class RuleController extends Controller
* *
* @return \Illuminate\Http\JsonResponse * @return \Illuminate\Http\JsonResponse
* *
*/ */
public function testTriggers(TestRuleFormRequest $request) public function testTriggers(TestRuleFormRequest $request)
{ {
@@ -586,6 +565,31 @@ class RuleController extends Controller
} }
} }
/**
* @param Bill $bill
*
* @return array
*/
private function getActionsForBill(Bill $bill): array
{
$actions = [];
try {
$actions[] = view(
'rules.partials.action',
[
'oldAction' => 'link_to_bill',
'oldValue' => $bill->name,
'oldChecked' => false,
'count' => 1,
]
)->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getActionsForBill(): %s', $e->getMessage()));
}
return $actions;
}
/** /**
* @param Rule $rule * @param Rule $rule
* *
@@ -601,6 +605,7 @@ class RuleController extends Controller
/** @var RuleAction $entry */ /** @var RuleAction $entry */
foreach ($rule->ruleActions as $entry) { foreach ($rule->ruleActions as $entry) {
$count = ($index + 1); $count = ($index + 1);
try {
$actions[] = view( $actions[] = view(
'rules.partials.action', 'rules.partials.action',
[ [
@@ -610,6 +615,9 @@ class RuleController extends Controller
'count' => $count, 'count' => $count,
] ]
)->render(); )->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
}
++$index; ++$index;
} }
@@ -632,6 +640,7 @@ class RuleController extends Controller
foreach ($rule->ruleTriggers as $entry) { foreach ($rule->ruleTriggers as $entry) {
if ('user_action' !== $entry->trigger_type) { if ('user_action' !== $entry->trigger_type) {
$count = ($index + 1); $count = ($index + 1);
try {
$triggers[] = view( $triggers[] = view(
'rules.partials.trigger', 'rules.partials.trigger',
[ [
@@ -641,6 +650,9 @@ class RuleController extends Controller
'count' => $count, 'count' => $count,
] ]
)->render(); )->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
}
++$index; ++$index;
} }
} }
@@ -664,6 +676,7 @@ class RuleController extends Controller
foreach ($oldActions as $index => $entry) { foreach ($oldActions as $index => $entry) {
$count = ($newIndex + 1); $count = ($newIndex + 1);
$checked = isset($request->old('rule-action-stop')[$index]) ? true : false; $checked = isset($request->old('rule-action-stop')[$index]) ? true : false;
try {
$actions[] = view( $actions[] = view(
'rules.partials.action', 'rules.partials.action',
[ [
@@ -673,6 +686,9 @@ class RuleController extends Controller
'count' => $count, 'count' => $count,
] ]
)->render(); )->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
}
++$newIndex; ++$newIndex;
} }
@@ -695,6 +711,7 @@ class RuleController extends Controller
foreach ($oldTriggers as $index => $entry) { foreach ($oldTriggers as $index => $entry) {
$count = ($newIndex + 1); $count = ($newIndex + 1);
$oldChecked = isset($request->old('rule-trigger-stop')[$index]) ? true : false; $oldChecked = isset($request->old('rule-trigger-stop')[$index]) ? true : false;
try {
$triggers[] = view( $triggers[] = view(
'rules.partials.trigger', 'rules.partials.trigger',
[ [
@@ -704,12 +721,72 @@ class RuleController extends Controller
'count' => $count, 'count' => $count,
] ]
)->render(); )->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
}
++$newIndex; ++$newIndex;
} }
return $triggers; return $triggers;
} }
/**
* Create fake triggers to match the bill's properties
*
* @param Bill $bill
*
* @return array
*/
private function getTriggersForBill(Bill $bill): array
{
$triggers = [];
try {
$triggers[] = view(
'rules.partials.trigger',
[
'oldTrigger' => 'currency_is',
'oldValue' => $bill->transactionCurrency()->first()->name,
'oldChecked' => false,
'count' => 1,
]
)->render();
$triggers[] = view(
'rules.partials.trigger',
[
'oldTrigger' => 'amount_more',
'oldValue' => round($bill->amount_min, 12),
'oldChecked' => false,
'count' => 2,
]
)->render();
$triggers[] = view(
'rules.partials.trigger',
[
'oldTrigger' => 'amount_less',
'oldValue' => round($bill->amount_max, 12),
'oldChecked' => false,
'count' => 3,
]
)->render();
$triggers[] = view(
'rules.partials.trigger',
[
'oldTrigger' => 'description_contains',
'oldValue' => $bill->name, 12,
'oldChecked' => false,
'count' => 4,
]
)->render();
} catch (Throwable $e) {
Log::debug(sprintf('Throwable was thrown in getTriggersForBill(): %s', $e->getMessage()));
Log::debug($e->getTraceAsString());
}
return $triggers;
}
/** /**
* @param TestRuleFormRequest $request * @param TestRuleFormRequest $request
* *
@@ -723,7 +800,7 @@ class RuleController extends Controller
'rule-trigger-values' => $request->get('rule-trigger-value'), 'rule-trigger-values' => $request->get('rule-trigger-value'),
'rule-trigger-stop' => $request->get('rule-trigger-stop'), 'rule-trigger-stop' => $request->get('rule-trigger-stop'),
]; ];
if (is_array($data['rule-triggers'])) { if (\is_array($data['rule-triggers'])) {
foreach ($data['rule-triggers'] as $index => $triggerType) { foreach ($data['rule-triggers'] as $index => $triggerType) {
$data['rule-trigger-stop'][$index] = (int)($data['rule-trigger-stop'][$index] ?? 0.0); $data['rule-trigger-stop'][$index] = (int)($data['rule-trigger-stop'][$index] ?? 0.0);
$triggers[] = [ $triggers[] = [

View File

@@ -44,7 +44,7 @@ class BillFormRequest extends Request
return [ return [
'name' => $this->string('name'), 'name' => $this->string('name'),
'amount_min' => $this->string('amount_min'), 'amount_min' => $this->string('amount_min'),
'currency_id' => $this->integer('currency_id'), 'transaction_currency_id' => $this->integer('transaction_currency_id'),
'amount_max' => $this->string('amount_max'), 'amount_max' => $this->string('amount_max'),
'date' => $this->date('date'), 'date' => $this->date('date'),
'repeat_freq' => $this->string('repeat_freq'), 'repeat_freq' => $this->string('repeat_freq'),
@@ -69,7 +69,7 @@ class BillFormRequest extends Request
'name' => $nameRule, 'name' => $nameRule,
'amount_min' => 'required|numeric|more:0', 'amount_min' => 'required|numeric|more:0',
'amount_max' => 'required|numeric|more:0', 'amount_max' => 'required|numeric|more:0',
'currency_id' => 'required|exists:transaction_currencies,id', 'transaction_currency_id' => 'required|exists:transaction_currencies,id',
'date' => 'required|date', 'date' => 'required|date',
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly', 'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
'skip' => 'required|between:0,31', 'skip' => 'required|between:0,31',

View File

@@ -23,6 +23,7 @@ declare(strict_types=1);
namespace FireflyIII\Models; namespace FireflyIII\Models;
use Crypt; use Crypt;
use FireflyIII\User;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
@@ -57,7 +58,7 @@ class Bill extends Model
*/ */
protected $fillable protected $fillable
= ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip', = ['name', 'match', 'amount_min', 'match_encrypted', 'name_encrypted', 'user_id', 'amount_max', 'date', 'repeat_freq', 'skip',
'automatch', 'active','currency_id']; 'automatch', 'active', 'transaction_currency_id'];
/** /**
* @var array * @var array
*/ */
@@ -179,13 +180,22 @@ class Bill extends Model
$this->attributes['name_encrypted'] = $encrypt; $this->attributes['name_encrypted'] = $encrypt;
} }
/**
* @codeCoverageIgnore
* @return BelongsTo
*/
public function transactionCurrency(): BelongsTo
{
return $this->belongsTo(TransactionCurrency::class);
}
/** /**
* @codeCoverageIgnore * @codeCoverageIgnore
* @return HasMany * @return HasMany
*/ */
public function transactionJournals(): HasMany public function transactionJournals(): HasMany
{ {
return $this->hasMany('FireflyIII\Models\TransactionJournal'); return $this->hasMany(TransactionJournal::class);
} }
/** /**
@@ -194,6 +204,6 @@ class Bill extends Model
*/ */
public function user(): BelongsTo public function user(): BelongsTo
{ {
return $this->belongsTo('FireflyIII\User'); return $this->belongsTo(User::class);
} }
} }

View File

@@ -42,19 +42,14 @@ class BillUpdateService
*/ */
public function update(Bill $bill, array $data): Bill public function update(Bill $bill, array $data): Bill
{ {
$matchArray = explode(',', $data['match']);
$matchArray = array_unique($matchArray);
$match = implode(',', $matchArray);
$bill->name = $data['name']; $bill->name = $data['name'];
$bill->match = $match;
$bill->amount_min = $data['amount_min']; $bill->amount_min = $data['amount_min'];
$bill->amount_max = $data['amount_max']; $bill->amount_max = $data['amount_max'];
$bill->date = $data['date']; $bill->date = $data['date'];
$bill->transaction_currency_id = $data['transaction_currency_id'];
$bill->repeat_freq = $data['repeat_freq']; $bill->repeat_freq = $data['repeat_freq'];
$bill->skip = $data['skip']; $bill->skip = $data['skip'];
$bill->automatch = $data['automatch']; $bill->automatch = true;
$bill->active = $data['active']; $bill->active = $data['active'];
$bill->save(); $bill->save();

View File

@@ -0,0 +1,92 @@
<?php
/**
* CurrencyIs.php
* Copyright (c) 2018 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\TransactionRules\Triggers;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use Log;
/**
* Class CurrencyIs.
*/
final class CurrencyIs extends AbstractTrigger implements TriggerInterface
{
/**
* A trigger is said to "match anything", or match any given transaction,
* when the trigger value is very vague or has no restrictions. Easy examples
* are the "AmountMore"-trigger combined with an amount of 0: any given transaction
* has an amount of more than zero! Other examples are all the "Description"-triggers
* which have hard time handling empty trigger values such as "" or "*" (wild cards).
*
* If the user tries to create such a trigger, this method MUST return true so Firefly III
* can stop the storing / updating the trigger. If the trigger is in any way restrictive
* (even if it will still include 99.9% of the users transactions), this method MUST return
* false.
*
* @param null $value
*
* @return bool
*/
public static function willMatchEverything($value = null)
{
if (null !== $value) {
return false;
}
Log::error(sprintf('Cannot use %s with a null value.', self::class));
return true;
}
/**
* Returns true when description is X
*
* @param TransactionJournal $journal
*
* @return bool
*/
public function triggered(TransactionJournal $journal): bool
{
/** @var CurrencyRepositoryInterface $repository */
$repository = app(CurrencyRepositoryInterface::class);
$currency = $repository->findByNameNull($this->triggerValue);
$hit = true;
if (null !== $currency) {
/** @var Transaction $transaction */
foreach ($journal->transactions as $transaction) {
if ((int)$transaction->transaction_currency_id !== (int)$currency->id) {
Log::debug(
sprintf(
'Trigger CurrencyIs: Transaction #%d in journal #%d uses currency %d instead of sought for #%d. No hit!',
$transaction->id, $journal->id, $transaction->transaction_currency_id, $currency->id
)
);
$hit = false;
}
}
}
return $hit;
}
}

View File

@@ -25,6 +25,7 @@ use FireflyIII\TransactionRules\Triggers\AmountLess;
use FireflyIII\TransactionRules\Triggers\AmountMore; use FireflyIII\TransactionRules\Triggers\AmountMore;
use FireflyIII\TransactionRules\Triggers\BudgetIs; use FireflyIII\TransactionRules\Triggers\BudgetIs;
use FireflyIII\TransactionRules\Triggers\CategoryIs; use FireflyIII\TransactionRules\Triggers\CategoryIs;
use FireflyIII\TransactionRules\Triggers\CurrencyIs;
use FireflyIII\TransactionRules\Triggers\DescriptionContains; use FireflyIII\TransactionRules\Triggers\DescriptionContains;
use FireflyIII\TransactionRules\Triggers\DescriptionEnds; use FireflyIII\TransactionRules\Triggers\DescriptionEnds;
use FireflyIII\TransactionRules\Triggers\DescriptionIs; use FireflyIII\TransactionRules\Triggers\DescriptionIs;
@@ -89,7 +90,7 @@ return [
'encryption' => null === env('USE_ENCRYPTION') || env('USE_ENCRYPTION') === true, 'encryption' => null === env('USE_ENCRYPTION') || env('USE_ENCRYPTION') === true,
'version' => '4.7.2.2', 'version' => '4.7.2.2',
'api_version' => '0.1', 'api_version' => '0.1',
'db_version' => 2, 'db_version' => 3,
'maxUploadSize' => 15242880, 'maxUploadSize' => 15242880,
'allowedMimes' => [ 'allowedMimes' => [
/* plain files */ /* plain files */
@@ -324,6 +325,7 @@ return [
'category_is' => CategoryIs::class, 'category_is' => CategoryIs::class,
'budget_is' => BudgetIs::class, 'budget_is' => BudgetIs::class,
'tag_is' => TagIs::class, 'tag_is' => TagIs::class,
'currency_is' => CurrencyIs::class,
'has_attachments' => HasAttachment::class, 'has_attachments' => HasAttachment::class,
'has_no_category' => HasNoCategory::class, 'has_no_category' => HasNoCategory::class,
'has_any_category' => HasAnyCategory::class, 'has_any_category' => HasAnyCategory::class,
@@ -362,6 +364,7 @@ return [
'set_budget', 'set_budget',
'add_tag', 'add_tag',
'remove_tag', 'remove_tag',
'link_to_bill',
'set_description', 'set_description',
'append_description', 'append_description',
'prepend_description', 'prepend_description',

View File

@@ -28,6 +28,7 @@ return [
'4.3' => 'Make sure you run the migrations and clear your cache. If you need more help, please check Github or the Firefly III website.', '4.3' => 'Make sure you run the migrations and clear your cache. If you need more help, please check Github or the Firefly III website.',
'4.6.3' => 'This will be the last version to require PHP7.0. Future versions will require PHP7.1 minimum.', '4.6.3' => 'This will be the last version to require PHP7.0. Future versions will require PHP7.1 minimum.',
'4.6.4' => 'This version of Firefly III requires PHP7.1.', '4.6.4' => 'This version of Firefly III requires PHP7.1.',
'4.7.3' => 'This version of Firefly III handles bills differently. See https://goo.gl/zkVdrF for more information.',
], ],
'install' => 'install' =>
[ [

View File

@@ -28,8 +28,8 @@ class ChangesForV473 extends Migration
Schema::table( Schema::table(
'bills', 'bills',
function (Blueprint $table) { function (Blueprint $table) {
$table->integer('currency_id', false, true)->nullable()->after('user_id'); $table->integer('transaction_currency_id', false, true)->nullable()->after('user_id');
$table->foreign('currency_id')->references('id')->on('transaction_currencies')->onDelete('set null'); $table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('set null');
} }
); );
} }

View File

@@ -285,6 +285,9 @@ function updateTriggerInput(selectList) {
input.prop('disabled', true); input.prop('disabled', true);
input.typeahead('destroy'); input.typeahead('destroy');
break; break;
case 'currency_is':
createAutoComplete(input, 'json/currency-names');
break;
default: default:
input.typeahead('destroy'); input.typeahead('destroy');
break; break;

View File

@@ -345,6 +345,8 @@ return [
'rule_trigger_budget_is' => 'Budget is ":trigger_value"', 'rule_trigger_budget_is' => 'Budget is ":trigger_value"',
'rule_trigger_tag_is_choice' => '(A) tag is..', 'rule_trigger_tag_is_choice' => '(A) tag is..',
'rule_trigger_tag_is' => 'A tag is ":trigger_value"', 'rule_trigger_tag_is' => 'A tag is ":trigger_value"',
'rule_trigger_currency_is_choice' => 'Transaction currency is..',
'rule_trigger_currency_is' => 'Transaction currency is ":trigger_value"',
'rule_trigger_has_attachments_choice' => 'Has at least this many attachments', 'rule_trigger_has_attachments_choice' => 'Has at least this many attachments',
'rule_trigger_has_attachments' => 'Has at least :trigger_value attachment(s)', 'rule_trigger_has_attachments' => 'Has at least :trigger_value attachment(s)',
'rule_trigger_store_journal' => 'When a transaction is created', 'rule_trigger_store_journal' => 'When a transaction is created',

View File

@@ -1,5 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/** /**
* form.php * form.php
* Copyright (c) 2017 thegrumpydictator@gmail.com * Copyright (c) 2017 thegrumpydictator@gmail.com
@@ -36,6 +37,7 @@ return [
'repeat_freq' => 'Repeats', 'repeat_freq' => 'Repeats',
'journal_currency_id' => 'Currency', 'journal_currency_id' => 'Currency',
'currency_id' => 'Currency', 'currency_id' => 'Currency',
'transaction_currency_id' => 'Currency',
'attachments' => 'Attachments', 'attachments' => 'Attachments',
'journal_amount' => 'Amount', 'journal_amount' => 'Amount',
'journal_source_account_name' => 'Revenue account (source)', 'journal_source_account_name' => 'Revenue account (source)',

View File

@@ -17,7 +17,7 @@
</div> </div>
<div class="box-body"> <div class="box-body">
{{ ExpandedForm.text('name') }} {{ ExpandedForm.text('name') }}
{{ ExpandedForm.select('currency_id',currencies, defaultCurrency.id) }} {{ ExpandedForm.select('transaction_currency_id',currencies, defaultCurrency.id) }}
{{ ExpandedForm.amountNoCurrency('amount_min') }} {{ ExpandedForm.amountNoCurrency('amount_min') }}
{{ ExpandedForm.amountNoCurrency('amount_max') }} {{ ExpandedForm.amountNoCurrency('amount_max') }}
{{ ExpandedForm.date('date',phpdate('Y-m-d')) }} {{ ExpandedForm.date('date',phpdate('Y-m-d')) }}

View File

@@ -18,9 +18,9 @@
</div> </div>
<div class="box-body"> <div class="box-body">
{{ ExpandedForm.text('name') }} {{ ExpandedForm.text('name') }}
{{ ExpandedForm.tags('match') }} {{ ExpandedForm.select('transaction_currency_id',currencies) }}
{{ ExpandedForm.amount('amount_min') }} {{ ExpandedForm.amountNoCurrency('amount_min') }}
{{ ExpandedForm.amount('amount_max') }} {{ ExpandedForm.amountNoCurrency('amount_max') }}
{{ ExpandedForm.date('date',bill.date.format('Y-m-d')) }} {{ ExpandedForm.date('date',bill.date.format('Y-m-d')) }}
{{ ExpandedForm.select('repeat_freq',periods) }} {{ ExpandedForm.select('repeat_freq',periods) }}
</div> </div>
@@ -37,7 +37,6 @@
{{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }} {{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }}
{{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }}
{{ ExpandedForm.integer('skip') }} {{ ExpandedForm.integer('skip') }}
{{ ExpandedForm.checkbox('automatch',1) }}
{{ ExpandedForm.checkbox('active',1) }} {{ ExpandedForm.checkbox('active',1) }}
</div> </div>

View File

@@ -6,9 +6,12 @@
{% block content %} {% block content %}
<form method="POST" action="{{ route('rules.store', ruleGroup.id) }}" accept-charset="UTF-8" class="form-horizontal" id="store"> <form method="POST" action="{{ route('rules.store') }}" accept-charset="UTF-8" class="form-horizontal" id="store">
<input name="_token" type="hidden" value="{{ csrf_token() }}"> <input name="_token" type="hidden" value="{{ csrf_token() }}">
<input type="hidden" name="rule_group_id" value="{{ ruleGroup.id }}"/> <input type="hidden" name="rule_group_id" value="{{ ruleGroup.id }}"/>
<input type="hidden" name="return_to_bill" value="{% if returnToBill %}true{% else %}false{% endif %}"/>
<input type="hidden" name="bill_id" value="{% if bill %}{{ bill.id }}{% else %}0{% endif %}"/>
<input type="hidden" name="active" value="1"/> <input type="hidden" name="active" value="1"/>
{% if bill %} {% if bill %}
<div class="row"> <div class="row">
@@ -35,6 +38,7 @@
<div class="box-body"> <div class="box-body">
{{ ExpandedForm.text('title') }} {{ ExpandedForm.text('title') }}
{{ ExpandedForm.select('trigger',allJournalTriggers()) }} {{ ExpandedForm.select('trigger',allJournalTriggers()) }}
{{ ExpandedForm.select('rule_group_id',groups, ruleGroup.id) }}
{{ ExpandedForm.checkbox('stop_processing',1,null, {helpText: trans('firefly.rule_help_stop_processing')}) }} {{ ExpandedForm.checkbox('stop_processing',1,null, {helpText: trans('firefly.rule_help_stop_processing')}) }}
</div> </div>
</div> </div>

View File

@@ -501,6 +501,7 @@ Route::group(
Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'budgets']); Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'budgets']);
Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'tags']); Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'tags']);
Route::get('bills', ['uses' => 'Json\AutoCompleteController@bills', 'as' => 'bills']); Route::get('bills', ['uses' => 'Json\AutoCompleteController@bills', 'as' => 'bills']);
Route::get('currency-names', ['uses' => 'Json\AutoCompleteController@currencyNames', 'as' => 'currency-names']);
Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']); Route::get('transaction-journals/all', ['uses' => 'Json\AutoCompleteController@allTransactionJournals', 'as' => 'all-transaction-journals']);
Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']); Route::get('transaction-journals/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']);
Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']); Route::get('transaction-journals/{what}', ['uses' => 'Json\AutoCompleteController@transactionJournals', 'as' => 'transaction-journals']);
@@ -723,7 +724,7 @@ Route::group(
Route::post('trigger/order/{rule}', ['uses' => 'RuleController@reorderRuleTriggers', 'as' => 'reorder-triggers']); Route::post('trigger/order/{rule}', ['uses' => 'RuleController@reorderRuleTriggers', 'as' => 'reorder-triggers']);
Route::post('action/order/{rule}', ['uses' => 'RuleController@reorderRuleActions', 'as' => 'reorder-actions']); Route::post('action/order/{rule}', ['uses' => 'RuleController@reorderRuleActions', 'as' => 'reorder-actions']);
Route::post('store/{ruleGroup}', ['uses' => 'RuleController@store', 'as' => 'store']); Route::post('store', ['uses' => 'RuleController@store', 'as' => 'store']);
Route::post('update/{rule}', ['uses' => 'RuleController@update', 'as' => 'update']); Route::post('update/{rule}', ['uses' => 'RuleController@update', 'as' => 'update']);
Route::post('destroy/{rule}', ['uses' => 'RuleController@destroy', 'as' => 'destroy']); Route::post('destroy/{rule}', ['uses' => 'RuleController@destroy', 'as' => 'destroy']);
Route::post('execute/{rule}', ['uses' => 'RuleController@execute', 'as' => 'execute']); Route::post('execute/{rule}', ['uses' => 'RuleController@execute', 'as' => 'execute']);