This commit is contained in:
James Cole
2018-04-07 22:23:16 +02:00
parent d3701837e3
commit 7b715925cf
22 changed files with 343 additions and 72 deletions

View File

@@ -28,13 +28,20 @@ use FireflyIII\Models\Account;
use FireflyIII\Models\AccountMeta;
use FireflyIII\Models\AccountType;
use FireflyIII\Models\Attachment;
use FireflyIII\Models\Bill;
use FireflyIII\Models\Note;
use FireflyIII\Models\Preference;
use FireflyIII\Models\Rule;
use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Models\Transaction;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Models\TransactionJournalMeta;
use FireflyIII\Models\TransactionType;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\User;
use Illuminate\Console\Command;
use Illuminate\Database\QueryException;
use Illuminate\Support\Collection;
@@ -70,6 +77,7 @@ class UpgradeDatabase extends Command
*/
public function handle()
{
$this->migrateBillsToRules();
$this->setTransactionIdentifier();
$this->updateAccountCurrencies();
$this->createNewTypes();
@@ -79,9 +87,118 @@ class UpgradeDatabase extends Command
$this->line('Done updating currency information..');
$this->migrateNotes();
$this->migrateAttachmentData();
$this->info('Firefly III database is up to date.');
return;
$this->info('Firefly III database is up to date.');
}
public function migrateBillsToRules()
{
foreach (User::get() as $user) {
/** @var Preference $lang */
$lang = Preferences::getForUser($user, 'language', 'en_US');
$groupName = (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data);
$ruleGroup = $user->ruleGroups()->where('title', $groupName)->first();
$currencyPreference = Preferences::getForUser($user, 'currencyPreference', config('firefly.default_currency', 'EUR'));
$currency = TransactionCurrency::where('code', $currencyPreference->data)->first();
if ($ruleGroup === null) {
$array = RuleGroup::get(['order'])->pluck('order')->toArray();
$order = count($array) > 0 ? max($array) + 1 : 1;
$ruleGroup = RuleGroup::create(
[
'user_id' => $user->id,
'title' => (string)trans('firefly.rulegroup_for_bills_title', [], $lang->data),
'description' => (string)trans('firefly.rulegroup_for_bills_description', [], $lang->data),
'order' => $order,
'active' => 1,
]
);
}
// loop bills.
$order = 1;
/** @var Bill $bill */
foreach ($user->bills()->get() as $bill) {
if ($bill->match !== 'MIGRATED_TO_RULES') {
$rule = Rule::create(
[
'user_id' => $user->id,
'rule_group_id' => $ruleGroup->id,
'title' => (string)trans('firefly.rule_for_bill_title', ['name' => $bill->name], $lang->data),
'description' => (string)trans('firefly.rule_for_bill_description', ['name' => $bill->name], $lang->data),
'order' => $order,
'active' => 1,
'stop_processing' => 1,
]
);
// add default trigger
RuleTrigger::create(
[
'rule_id' => $rule->id,
'trigger_type' => 'user_action',
'trigger_value' => 'store-journal',
'active' => 1,
'stop_processing' => 0,
'order' => 1,
]
);
// add trigger for description
$match = implode(' ', explode(',', $bill->match));
RuleTrigger::create(
[
'rule_id' => $rule->id,
'trigger_type' => 'description_is',
'trigger_value' => $match,
'active' => 1,
'stop_processing' => 0,
'order' => 2,
]
);
// add triggers for amounts:
RuleTrigger::create(
[
'rule_id' => $rule->id,
'trigger_type' => 'amount_less',
'trigger_value' => round($bill->amount_max, $currency->decimal_places),
'active' => 1,
'stop_processing' => 0,
'order' => 3,
]
);
RuleTrigger::create(
[
'rule_id' => $rule->id,
'trigger_type' => 'amount_more',
'trigger_value' => round($bill->amount_min, $currency->decimal_places),
'active' => 1,
'stop_processing' => 0,
'order' => 4,
]
);
// create action
RuleAction::create(
[
'rule_id' => $rule->id,
'action_type' => 'link_to_bill',
'action_value' => $bill->name,
'order' => 1,
'active' => 1,
'stop_processing' => 0,
]
);
$order++;
//$bill->match = 'MIGRATED_TO_RULES';
$bill->save();
$this->line(sprintf('Updated bill #%d ("%s") so it will use rules.', $bill->id, $bill->name));
}
}
$this->line('Exit');
exit;
}
}
/**

View File

@@ -45,22 +45,19 @@ class BillFactory
*/
public function create(array $data): ?Bill
{
$matchArray = explode(',', $data['match']);
$matchArray = array_unique($matchArray);
$match = implode(',', $matchArray);
/** @var Bill $bill */
$bill = Bill::create(
[
'name' => $data['name'],
'match' => $match,
'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' => $data['automatch'],
'automatch' => true,
'active' => $data['active'],
]
);
@@ -94,7 +91,7 @@ class BillFactory
}
// then find by name:
if (strlen($billName) > 0) {
if (\strlen($billName) > 0) {
$bill = $this->findByName($billName);
if (null !== $bill) {
return $bill;

View File

@@ -71,7 +71,7 @@ class TagFactory
/** @var Tag $object */
foreach ($this->tags as $object) {
if ($object->tag === $tag) {
if (strtolower($object->tag) === strtolower($tag)) {
return $object;
}
}

View File

@@ -22,6 +22,7 @@ declare(strict_types=1);
namespace FireflyIII\Http\Controllers;
use ExpandedForm;
use FireflyIII\Helpers\Attachments\AttachmentHelperInterface;
use FireflyIII\Helpers\Collector\JournalCollectorInterface;
use FireflyIII\Http\Requests\BillFormRequest;
@@ -29,6 +30,8 @@ use FireflyIII\Models\Bill;
use FireflyIII\Models\Note;
use FireflyIII\Models\TransactionJournal;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\Transformers\BillTransformer;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
@@ -76,13 +79,15 @@ class BillController extends Controller
*
* @return View
*/
public function create(Request $request)
public function create(Request $request, CurrencyRepositoryInterface $repository)
{
$periods = [];
foreach (config('firefly.bill_periods') as $current) {
$periods[$current] = strtolower((string)trans('firefly.repeat_freq_' . $current));
}
$subTitle = trans('firefly.create_new_bill');
$subTitle = trans('firefly.create_new_bill');
$defaultCurrency = app('amount')->getDefaultCurrency();
$currencies = ExpandedForm::makeSelectList($repository->get());
// put previous url in session if not redirect from store (not "create another").
if (true !== session('bills.create.fromStore')) {
@@ -90,7 +95,7 @@ class BillController extends Controller
}
$request->session()->forget('bills.create.fromStore');
return view('bills.create', compact('periods', 'subTitle'));
return view('bills.create', compact('periods', 'subTitle', 'currencies', 'defaultCurrency'));
}
/**
@@ -270,7 +275,7 @@ class BillController extends Controller
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(BillFormRequest $request, BillRepositoryInterface $repository)
public function store(BillFormRequest $request, BillRepositoryInterface $repository, RuleGroupRepositoryInterface $ruleGroupRepository)
{
$billData = $request->getBillData();
$bill = $repository->store($billData);
@@ -291,16 +296,22 @@ class BillController extends Controller
$request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore
}
if (1 === (int)$request->get('create_another')) {
// @codeCoverageIgnoreStart
$request->session()->put('bills.create.fromStore', true);
return redirect(route('bills.create'))->withInput();
// @codeCoverageIgnoreEnd
// find first rule group, or create one:
$count = $ruleGroupRepository->count();
if ($count === 0) {
$data = [
'title' => (string)trans('firefly.rulegroup_for_bills_title'),
'description' => (string)trans('firefly.rulegroup_for_bills_description'),
];
$group = $ruleGroupRepository->store($data);
}
if ($count > 0) {
$group = $ruleGroupRepository->getActiveGroups(auth()->user())->first();
}
// redirect to previous URL.
return redirect($this->getPreviousUri('bills.create.uri'));
// redirect to page that will create a new rule.
return redirect(route('rules.create', [$group->id]) . '?fromBill=' . $bill->id);
}
/**

View File

@@ -34,6 +34,7 @@ use FireflyIII\Models\RuleAction;
use FireflyIII\Models\RuleGroup;
use FireflyIII\Models\RuleTrigger;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
use FireflyIII\TransactionRules\TransactionMatcher;
@@ -75,8 +76,11 @@ class RuleController extends Controller
*/
public function create(Request $request, RuleGroup $ruleGroup)
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;
@@ -89,12 +93,60 @@ class RuleController extends Controller
if ($request->old()) {
// process old triggers.
$oldTriggers = $this->getPreviousTriggers($request);
$triggerCount = count($oldTriggers);
$triggerCount = \count($oldTriggers);
// process old actions
$oldActions = $this->getPreviousActions($request);
$actionCount = count($oldActions);
$actionCount = \count($oldActions);
}
if ($billId > 0) {
$bill = $billRepository->find($billId);
// 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();
}
$subTitleIcon = 'fa-clone';
$subTitle = trans('firefly.make_new_rule', ['title' => $ruleGroup->title]);
@@ -107,7 +159,7 @@ class RuleController extends Controller
return view(
'rules.rule.create',
compact('subTitleIcon', 'oldTriggers', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle')
compact('subTitleIcon', 'oldTriggers', 'preFilled', 'bill', 'oldActions', 'triggerCount', 'actionCount', 'ruleGroup', 'subTitle')
);
}

View File

@@ -42,18 +42,15 @@ class BillFormRequest extends Request
public function getBillData()
{
return [
'name' => $this->string('name'),
'match' => $this->string('match'),
'amount_min' => $this->string('amount_min'),
'amount_currency_id_amount_min' => $this->integer('amount_currency_id_amount_min'),
'amount_currency_id_amount_max' => $this->integer('amount_currency_id_amount_max'),
'amount_max' => $this->string('amount_max'),
'date' => $this->date('date'),
'repeat_freq' => $this->string('repeat_freq'),
'skip' => $this->integer('skip'),
'automatch' => $this->boolean('automatch'),
'active' => $this->boolean('active'),
'notes' => $this->string('notes'),
'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'),
];
}
@@ -62,25 +59,22 @@ class BillFormRequest extends Request
*/
public function rules()
{
$nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name';
$matchRule = 'required|between:1,255|uniqueObjectForUser:bills,match';
$nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name';
if ($this->integer('id') > 0) {
$nameRule .= ',' . $this->integer('id');
$matchRule .= ',' . $this->integer('id');
// todo is a fix to do this better.
$nameRule .= ',' . $this->integer('id');
}
// is OK
$rules = [
'name' => $nameRule,
'match' => $matchRule,
'amount_min' => 'required|numeric|more:0',
'amount_max' => 'required|numeric|more:0',
'amount_currency_id_amount_min' => 'required|exists:transaction_currencies,id',
'amount_currency_id_amount_max' => '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',
'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;

View File

@@ -57,7 +57,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',];
'automatch', 'active','currency_id'];
/**
* @var array
*/

View File

@@ -47,6 +47,8 @@ class Rule extends Model
'order' => 'int',
'stop_processing' => 'boolean',
];
/** @var array */
protected $fillable = ['rule_group_id', 'order', 'active', 'title', 'description', 'user_id'];
/**
* @param string $value

View File

@@ -43,6 +43,9 @@ class RuleAction extends Model
'stop_processing' => 'boolean',
];
/** @var array */
protected $fillable = ['rule_id', 'action_type', 'action_value', 'order', 'active', 'stop_processing'];
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo

View File

@@ -43,6 +43,9 @@ class RuleTrigger extends Model
'stop_processing' => 'boolean',
];
/** @var array */
protected $fillable = ['rule_id', 'trigger_type', 'trigger_value', 'order', 'active', 'stop_processing'];
/**
* @codeCoverageIgnore
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo

View File

@@ -50,8 +50,6 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
*
* @return bool
*
*/
public function destroy(RuleGroup $ruleGroup, ?RuleGroup $moveTo): bool
{

View File

@@ -51,7 +51,7 @@ trait JournalServiceTrait
return; // @codeCoverageIgnore
}
foreach ($data['tags'] as $string) {
if (strlen($string) > 0) {
if (\strlen($string) > 0) {
$tag = $factory->findOrCreate($string);
$set[] = $tag->id;
}

View File

@@ -52,6 +52,34 @@ class ExpandedForm
return $this->currencyField($name, 'amount', $value, $options);
}
/**
* @param string $name
* @param null $value
* @param array $options
*
* @return string
* @throws \FireflyIII\Exceptions\FireflyException
* @throws \Throwable
*/
public function amountNoCurrency(string $name, $value = null, array $options = []): string
{
$label = $this->label($name, $options);
$options = $this->expandOptionArray($name, $label, $options);
$classes = $this->getHolderClasses($name);
$value = $this->fillFieldValue($name, $value);
$options['step'] = 'any';
unset($options['currency'], $options['placeholder']);
// make sure value is formatted nicely:
if (null !== $value && '' !== $value) {
$value = round($value, 8);
}
$html = view('form.amount-no-currency', compact('classes', 'name', 'label', 'value', 'options'))->render();
return $html;
}
/**
* @param string $name
* @param null $value