mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2024-12-23 23:50:09 -06:00
Code for #1324
This commit is contained in:
parent
7583698ee5
commit
8f0e36a8e4
@ -48,17 +48,17 @@ class BillFactory
|
||||
/** @var Bill $bill */
|
||||
$bill = Bill::create(
|
||||
[
|
||||
'name' => $data['name'],
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'currency_id' => $data['currency_id'],
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => true,
|
||||
'active' => $data['active'],
|
||||
'name' => $data['name'],
|
||||
'match' => 'MIGRATED_TO_RULES',
|
||||
'amount_min' => $data['amount_min'],
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_currency_id' => $data['transaction_currency_id'],
|
||||
'amount_max' => $data['amount_max'],
|
||||
'date' => $data['date'],
|
||||
'repeat_freq' => $data['repeat_freq'],
|
||||
'skip' => $data['skip'],
|
||||
'automatch' => true,
|
||||
'active' => $data['active'],
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -136,7 +136,7 @@ class BillController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*/
|
||||
public function edit(Request $request, Bill $bill)
|
||||
public function edit(Request $request, CurrencyRepositoryInterface $repository, Bill $bill)
|
||||
{
|
||||
$periods = [];
|
||||
foreach (config('firefly.bill_periods') as $current) {
|
||||
@ -152,6 +152,8 @@ class BillController extends Controller
|
||||
$currency = app('amount')->getDefaultCurrency();
|
||||
$bill->amount_min = round($bill->amount_min, $currency->decimal_places);
|
||||
$bill->amount_max = round($bill->amount_max, $currency->decimal_places);
|
||||
$defaultCurrency = app('amount')->getDefaultCurrency();
|
||||
$currencies = ExpandedForm::makeSelectList($repository->get());
|
||||
|
||||
$preFilled = [
|
||||
'notes' => '',
|
||||
@ -167,7 +169,7 @@ class BillController extends Controller
|
||||
|
||||
$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
|
||||
}
|
||||
|
||||
// do return to original bill form?
|
||||
$return = 'false';
|
||||
if (1 === (int)$request->get('create_another')) {
|
||||
$return = 'true';
|
||||
}
|
||||
|
||||
// find first rule group, or create one:
|
||||
$count = $ruleGroupRepository->count();
|
||||
if ($count === 0) {
|
||||
@ -309,9 +317,10 @@ class BillController extends Controller
|
||||
$group = $ruleGroupRepository->getActiveGroups(auth()->user())->first();
|
||||
}
|
||||
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,7 @@ use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
|
||||
use FireflyIII\Repositories\Journal\JournalRepositoryInterface;
|
||||
use FireflyIII\Repositories\Tag\TagRepositoryInterface;
|
||||
use FireflyIII\Support\CacheProperties;
|
||||
@ -119,6 +120,19 @@ class AutoCompleteController extends Controller
|
||||
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.
|
||||
*
|
||||
|
@ -29,6 +29,7 @@ use FireflyIII\Http\Requests\SelectTransactionsRequest;
|
||||
use FireflyIII\Http\Requests\TestRuleFormRequest;
|
||||
use FireflyIII\Jobs\ExecuteRuleOnExistingTransactions;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
@ -39,8 +40,10 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\TransactionRules\TransactionMatcher;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Preferences;
|
||||
use Session;
|
||||
use Throwable;
|
||||
use View;
|
||||
|
||||
/**
|
||||
@ -73,81 +76,47 @@ class RuleController extends Controller
|
||||
*
|
||||
* @return View
|
||||
*
|
||||
|
||||
|
||||
*/
|
||||
public function create(Request $request, RuleGroupRepositoryInterface $ruleGroupRepository, BillRepositoryInterface $billRepository, RuleGroup $ruleGroup)
|
||||
{
|
||||
$bill = null;
|
||||
$billId = (int)$request->get('fromBill');
|
||||
$preFilled = [];
|
||||
// count for possible present previous entered triggers/actions.
|
||||
$triggerCount = 0;
|
||||
$actionCount = 0;
|
||||
$bill = null;
|
||||
$billId = (int)$request->get('fromBill');
|
||||
$preFilled = [];
|
||||
$groups = ExpandedForm::makeSelectList($ruleGroupRepository->get());
|
||||
$oldTriggers = [];
|
||||
$oldActions = [];
|
||||
$returnToBill = false;
|
||||
|
||||
// collection of those triggers/actions.
|
||||
$oldTriggers = [];
|
||||
$oldActions = [];
|
||||
if ($request->get('return') === 'true') {
|
||||
$returnToBill = true;
|
||||
}
|
||||
|
||||
// has bill?
|
||||
if ($billId > 0) {
|
||||
$bill = $billRepository->find($billId);
|
||||
}
|
||||
|
||||
// has old input?
|
||||
if ($request->old()) {
|
||||
// process old triggers.
|
||||
$oldTriggers = $this->getPreviousTriggers($request);
|
||||
$triggerCount = \count($oldTriggers);
|
||||
|
||||
// process old actions
|
||||
$oldTriggers = $this->getPreviousTriggers($request);
|
||||
$oldActions = $this->getPreviousActions($request);
|
||||
$actionCount = \count($oldActions);
|
||||
|
||||
}
|
||||
if ($billId > 0) {
|
||||
$bill = $billRepository->find($billId);
|
||||
// has existing bill refered to in URI?
|
||||
if (null !== $bill && !$request->old()) {
|
||||
|
||||
// create some sensible defaults:
|
||||
$preFilled['title'] = trans('firefly.new_rule_for_bill_title', ['name' => $bill->name]);
|
||||
$preFilled['description'] = trans('firefly.new_rule_for_bill_description', ['name' => $bill->name]);
|
||||
$request->session()->flash('preFilled', $preFilled);
|
||||
|
||||
// pretend there are old triggers, so the page will fill them in:
|
||||
$oldTriggers[] = view(
|
||||
'rules.partials.trigger',
|
||||
[
|
||||
'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();
|
||||
|
||||
// get triggers and actions for bill:
|
||||
$oldTriggers = $this->getTriggersForBill($bill);
|
||||
$oldActions = $this->getActionsForBill($bill);
|
||||
}
|
||||
|
||||
|
||||
$triggerCount = \count($oldTriggers);
|
||||
$actionCount = \count($oldActions);
|
||||
$subTitleIcon = 'fa-clone';
|
||||
$subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
|
||||
|
||||
@ -159,7 +128,10 @@ class RuleController extends Controller
|
||||
|
||||
return view(
|
||||
'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 RuleRepositoryInterface $repository
|
||||
* @param RuleGroup $ruleGroup
|
||||
*
|
||||
* @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['rule_group_id'] = $ruleGroup->id;
|
||||
|
||||
$data = $request->getRuleData();
|
||||
$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();
|
||||
|
||||
// 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')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
Session::put('rules.create.fromStore', true);
|
||||
|
||||
return redirect(route('rules.create', [$ruleGroup]))->withInput();
|
||||
return redirect(route('rules.create', [$data['rule_group_id']]))->withInput();
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
@ -416,7 +396,6 @@ class RuleController extends Controller
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*
|
||||
|
||||
*/
|
||||
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
|
||||
*
|
||||
@ -600,16 +604,20 @@ class RuleController extends Controller
|
||||
|
||||
/** @var RuleAction $entry */
|
||||
foreach ($rule->ruleActions as $entry) {
|
||||
$count = ($index + 1);
|
||||
$actions[] = view(
|
||||
'rules.partials.action',
|
||||
[
|
||||
'oldAction' => $entry->action_type,
|
||||
'oldValue' => $entry->action_value,
|
||||
'oldChecked' => $entry->stop_processing,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
$count = ($index + 1);
|
||||
try {
|
||||
$actions[] = view(
|
||||
'rules.partials.action',
|
||||
[
|
||||
'oldAction' => $entry->action_type,
|
||||
'oldValue' => $entry->action_value,
|
||||
'oldChecked' => $entry->stop_processing,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getCurrentActions(): %s', $e->getMessage()));
|
||||
}
|
||||
++$index;
|
||||
}
|
||||
|
||||
@ -631,16 +639,20 @@ class RuleController extends Controller
|
||||
/** @var RuleTrigger $entry */
|
||||
foreach ($rule->ruleTriggers as $entry) {
|
||||
if ('user_action' !== $entry->trigger_type) {
|
||||
$count = ($index + 1);
|
||||
$triggers[] = view(
|
||||
'rules.partials.trigger',
|
||||
[
|
||||
'oldTrigger' => $entry->trigger_type,
|
||||
'oldValue' => $entry->trigger_value,
|
||||
'oldChecked' => $entry->stop_processing,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
$count = ($index + 1);
|
||||
try {
|
||||
$triggers[] = view(
|
||||
'rules.partials.trigger',
|
||||
[
|
||||
'oldTrigger' => $entry->trigger_type,
|
||||
'oldValue' => $entry->trigger_value,
|
||||
'oldChecked' => $entry->stop_processing,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getCurrentTriggers(): %s', $e->getMessage()));
|
||||
}
|
||||
++$index;
|
||||
}
|
||||
}
|
||||
@ -662,17 +674,21 @@ class RuleController extends Controller
|
||||
/** @var array $oldActions */
|
||||
$oldActions = is_array($request->old('rule-action')) ? $request->old('rule-action') : [];
|
||||
foreach ($oldActions as $index => $entry) {
|
||||
$count = ($newIndex + 1);
|
||||
$checked = isset($request->old('rule-action-stop')[$index]) ? true : false;
|
||||
$actions[] = view(
|
||||
'rules.partials.action',
|
||||
[
|
||||
'oldAction' => $entry,
|
||||
'oldValue' => $request->old('rule-action-value')[$index],
|
||||
'oldChecked' => $checked,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
$count = ($newIndex + 1);
|
||||
$checked = isset($request->old('rule-action-stop')[$index]) ? true : false;
|
||||
try {
|
||||
$actions[] = view(
|
||||
'rules.partials.action',
|
||||
[
|
||||
'oldAction' => $entry,
|
||||
'oldValue' => $request->old('rule-action-value')[$index],
|
||||
'oldChecked' => $checked,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getPreviousActions(): %s', $e->getMessage()));
|
||||
}
|
||||
++$newIndex;
|
||||
}
|
||||
|
||||
@ -695,16 +711,77 @@ class RuleController extends Controller
|
||||
foreach ($oldTriggers as $index => $entry) {
|
||||
$count = ($newIndex + 1);
|
||||
$oldChecked = isset($request->old('rule-trigger-stop')[$index]) ? true : false;
|
||||
try {
|
||||
$triggers[] = view(
|
||||
'rules.partials.trigger',
|
||||
[
|
||||
'oldTrigger' => $entry,
|
||||
'oldValue' => $request->old('rule-trigger-value')[$index],
|
||||
'oldChecked' => $oldChecked,
|
||||
'count' => $count,
|
||||
]
|
||||
)->render();
|
||||
} catch (Throwable $e) {
|
||||
Log::debug(sprintf('Throwable was thrown in getPreviousTriggers(): %s', $e->getMessage()));
|
||||
}
|
||||
++$newIndex;
|
||||
}
|
||||
|
||||
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' => $entry,
|
||||
'oldValue' => $request->old('rule-trigger-value')[$index],
|
||||
'oldChecked' => $oldChecked,
|
||||
'count' => $count,
|
||||
'oldTrigger' => 'currency_is',
|
||||
'oldValue' => $bill->transactionCurrency()->first()->name,
|
||||
'oldChecked' => false,
|
||||
'count' => 1,
|
||||
]
|
||||
)->render();
|
||||
++$newIndex;
|
||||
|
||||
$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;
|
||||
@ -723,7 +800,7 @@ class RuleController extends Controller
|
||||
'rule-trigger-values' => $request->get('rule-trigger-value'),
|
||||
'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) {
|
||||
$data['rule-trigger-stop'][$index] = (int)($data['rule-trigger-stop'][$index] ?? 0.0);
|
||||
$triggers[] = [
|
||||
|
@ -42,15 +42,15 @@ class BillFormRequest extends Request
|
||||
public function getBillData()
|
||||
{
|
||||
return [
|
||||
'name' => $this->string('name'),
|
||||
'amount_min' => $this->string('amount_min'),
|
||||
'currency_id' => $this->integer('currency_id'),
|
||||
'amount_max' => $this->string('amount_max'),
|
||||
'date' => $this->date('date'),
|
||||
'repeat_freq' => $this->string('repeat_freq'),
|
||||
'skip' => $this->integer('skip'),
|
||||
'active' => $this->boolean('active'),
|
||||
'notes' => $this->string('notes'),
|
||||
'name' => $this->string('name'),
|
||||
'amount_min' => $this->string('amount_min'),
|
||||
'transaction_currency_id' => $this->integer('transaction_currency_id'),
|
||||
'amount_max' => $this->string('amount_max'),
|
||||
'date' => $this->date('date'),
|
||||
'repeat_freq' => $this->string('repeat_freq'),
|
||||
'skip' => $this->integer('skip'),
|
||||
'active' => $this->boolean('active'),
|
||||
'notes' => $this->string('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
@ -66,15 +66,15 @@ class BillFormRequest extends Request
|
||||
}
|
||||
// is OK
|
||||
$rules = [
|
||||
'name' => $nameRule,
|
||||
'amount_min' => 'required|numeric|more:0',
|
||||
'amount_max' => 'required|numeric|more:0',
|
||||
'currency_id' => 'required|exists:transaction_currencies,id',
|
||||
'date' => 'required|date',
|
||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'required|between:0,31',
|
||||
'automatch' => 'in:1',
|
||||
'active' => 'in:1',
|
||||
'name' => $nameRule,
|
||||
'amount_min' => 'required|numeric|more:0',
|
||||
'amount_max' => 'required|numeric|more:0',
|
||||
'transaction_currency_id' => 'required|exists:transaction_currencies,id',
|
||||
'date' => 'required|date',
|
||||
'repeat_freq' => 'required|in:weekly,monthly,quarterly,half-year,yearly',
|
||||
'skip' => 'required|between:0,31',
|
||||
'automatch' => 'in:1',
|
||||
'active' => 'in:1',
|
||||
];
|
||||
|
||||
return $rules;
|
||||
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Models;
|
||||
|
||||
use Crypt;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
@ -57,7 +58,7 @@ class Bill extends Model
|
||||
*/
|
||||
protected $fillable
|
||||
= ['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
|
||||
*/
|
||||
@ -179,13 +180,22 @@ class Bill extends Model
|
||||
$this->attributes['name_encrypted'] = $encrypt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function transactionCurrency(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(TransactionCurrency::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
* @return 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
|
||||
{
|
||||
return $this->belongsTo('FireflyIII\User');
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
|
@ -42,20 +42,15 @@ class BillUpdateService
|
||||
*/
|
||||
public function update(Bill $bill, array $data): Bill
|
||||
{
|
||||
|
||||
$matchArray = explode(',', $data['match']);
|
||||
$matchArray = array_unique($matchArray);
|
||||
$match = implode(',', $matchArray);
|
||||
|
||||
$bill->name = $data['name'];
|
||||
$bill->match = $match;
|
||||
$bill->amount_min = $data['amount_min'];
|
||||
$bill->amount_max = $data['amount_max'];
|
||||
$bill->date = $data['date'];
|
||||
$bill->repeat_freq = $data['repeat_freq'];
|
||||
$bill->skip = $data['skip'];
|
||||
$bill->automatch = $data['automatch'];
|
||||
$bill->active = $data['active'];
|
||||
$bill->name = $data['name'];
|
||||
$bill->amount_min = $data['amount_min'];
|
||||
$bill->amount_max = $data['amount_max'];
|
||||
$bill->date = $data['date'];
|
||||
$bill->transaction_currency_id = $data['transaction_currency_id'];
|
||||
$bill->repeat_freq = $data['repeat_freq'];
|
||||
$bill->skip = $data['skip'];
|
||||
$bill->automatch = true;
|
||||
$bill->active = $data['active'];
|
||||
$bill->save();
|
||||
|
||||
// update note:
|
||||
|
92
app/TransactionRules/Triggers/CurrencyIs.php
Normal file
92
app/TransactionRules/Triggers/CurrencyIs.php
Normal 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;
|
||||
}
|
||||
}
|
@ -25,6 +25,7 @@ use FireflyIII\TransactionRules\Triggers\AmountLess;
|
||||
use FireflyIII\TransactionRules\Triggers\AmountMore;
|
||||
use FireflyIII\TransactionRules\Triggers\BudgetIs;
|
||||
use FireflyIII\TransactionRules\Triggers\CategoryIs;
|
||||
use FireflyIII\TransactionRules\Triggers\CurrencyIs;
|
||||
use FireflyIII\TransactionRules\Triggers\DescriptionContains;
|
||||
use FireflyIII\TransactionRules\Triggers\DescriptionEnds;
|
||||
use FireflyIII\TransactionRules\Triggers\DescriptionIs;
|
||||
@ -89,7 +90,7 @@ return [
|
||||
'encryption' => null === env('USE_ENCRYPTION') || env('USE_ENCRYPTION') === true,
|
||||
'version' => '4.7.2.2',
|
||||
'api_version' => '0.1',
|
||||
'db_version' => 2,
|
||||
'db_version' => 3,
|
||||
'maxUploadSize' => 15242880,
|
||||
'allowedMimes' => [
|
||||
/* plain files */
|
||||
@ -324,6 +325,7 @@ return [
|
||||
'category_is' => CategoryIs::class,
|
||||
'budget_is' => BudgetIs::class,
|
||||
'tag_is' => TagIs::class,
|
||||
'currency_is' => CurrencyIs::class,
|
||||
'has_attachments' => HasAttachment::class,
|
||||
'has_no_category' => HasNoCategory::class,
|
||||
'has_any_category' => HasAnyCategory::class,
|
||||
@ -362,6 +364,7 @@ return [
|
||||
'set_budget',
|
||||
'add_tag',
|
||||
'remove_tag',
|
||||
'link_to_bill',
|
||||
'set_description',
|
||||
'append_description',
|
||||
'prepend_description',
|
||||
|
@ -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.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.7.3' => 'This version of Firefly III handles bills differently. See https://goo.gl/zkVdrF for more information.',
|
||||
],
|
||||
'install' =>
|
||||
[
|
||||
|
@ -28,8 +28,8 @@ class ChangesForV473 extends Migration
|
||||
Schema::table(
|
||||
'bills',
|
||||
function (Blueprint $table) {
|
||||
$table->integer('currency_id', false, true)->nullable()->after('user_id');
|
||||
$table->foreign('currency_id')->references('id')->on('transaction_currencies')->onDelete('set null');
|
||||
$table->integer('transaction_currency_id', false, true)->nullable()->after('user_id');
|
||||
$table->foreign('transaction_currency_id')->references('id')->on('transaction_currencies')->onDelete('set null');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -285,6 +285,9 @@ function updateTriggerInput(selectList) {
|
||||
input.prop('disabled', true);
|
||||
input.typeahead('destroy');
|
||||
break;
|
||||
case 'currency_is':
|
||||
createAutoComplete(input, 'json/currency-names');
|
||||
break;
|
||||
default:
|
||||
input.typeahead('destroy');
|
||||
break;
|
||||
|
@ -345,6 +345,8 @@ return [
|
||||
'rule_trigger_budget_is' => 'Budget is ":trigger_value"',
|
||||
'rule_trigger_tag_is_choice' => '(A) tag is..',
|
||||
'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' => 'Has at least :trigger_value attachment(s)',
|
||||
'rule_trigger_store_journal' => 'When a transaction is created',
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* form.php
|
||||
* Copyright (c) 2017 thegrumpydictator@gmail.com
|
||||
@ -36,6 +37,7 @@ return [
|
||||
'repeat_freq' => 'Repeats',
|
||||
'journal_currency_id' => 'Currency',
|
||||
'currency_id' => 'Currency',
|
||||
'transaction_currency_id' => 'Currency',
|
||||
'attachments' => 'Attachments',
|
||||
'journal_amount' => 'Amount',
|
||||
'journal_source_account_name' => 'Revenue account (source)',
|
||||
|
@ -17,7 +17,7 @@
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{ 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_max') }}
|
||||
{{ ExpandedForm.date('date',phpdate('Y-m-d')) }}
|
||||
|
@ -18,9 +18,9 @@
|
||||
</div>
|
||||
<div class="box-body">
|
||||
{{ ExpandedForm.text('name') }}
|
||||
{{ ExpandedForm.tags('match') }}
|
||||
{{ ExpandedForm.amount('amount_min') }}
|
||||
{{ ExpandedForm.amount('amount_max') }}
|
||||
{{ ExpandedForm.select('transaction_currency_id',currencies) }}
|
||||
{{ ExpandedForm.amountNoCurrency('amount_min') }}
|
||||
{{ ExpandedForm.amountNoCurrency('amount_max') }}
|
||||
{{ ExpandedForm.date('date',bill.date.format('Y-m-d')) }}
|
||||
{{ ExpandedForm.select('repeat_freq',periods) }}
|
||||
</div>
|
||||
@ -37,7 +37,6 @@
|
||||
{{ 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.integer('skip') }}
|
||||
{{ ExpandedForm.checkbox('automatch',1) }}
|
||||
{{ ExpandedForm.checkbox('active',1) }}
|
||||
|
||||
</div>
|
||||
|
@ -6,9 +6,12 @@
|
||||
|
||||
{% 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 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"/>
|
||||
{% if bill %}
|
||||
<div class="row">
|
||||
@ -35,6 +38,7 @@
|
||||
<div class="box-body">
|
||||
{{ ExpandedForm.text('title') }}
|
||||
{{ 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')}) }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -501,6 +501,7 @@ Route::group(
|
||||
Route::get('budgets', ['uses' => 'Json\AutoCompleteController@budgets', 'as' => 'budgets']);
|
||||
Route::get('tags', ['uses' => 'Json\AutoCompleteController@tags', 'as' => 'tags']);
|
||||
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/with-id/{tj}', ['uses' => 'Json\AutoCompleteController@journalsWithId', 'as' => 'journals-with-id']);
|
||||
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('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('destroy/{rule}', ['uses' => 'RuleController@destroy', 'as' => 'destroy']);
|
||||
Route::post('execute/{rule}', ['uses' => 'RuleController@execute', 'as' => 'execute']);
|
||||
|
Loading…
Reference in New Issue
Block a user