mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-11-02 12:15:55 +00:00
Fix tests for transaction storage.
This commit is contained in:
@@ -43,7 +43,6 @@ class StoreRequest extends FormRequest
|
||||
use ConvertsDataTypes, RecurrenceValidation, TransactionValidation, CurrencyValidation, GetRecurrenceData, ChecksLogin;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*
|
||||
@@ -51,26 +50,21 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$active = true;
|
||||
$applyRules = true;
|
||||
if (null !== $this->get('active')) {
|
||||
$active = $this->boolean('active');
|
||||
}
|
||||
if (null !== $this->get('apply_rules')) {
|
||||
$applyRules = $this->boolean('apply_rules');
|
||||
}
|
||||
$fields = [
|
||||
'type' => ['type', 'string'],
|
||||
'title' => ['title', 'string'],
|
||||
'description' => ['description', 'string'],
|
||||
'first_date' => ['first_date', 'date'],
|
||||
'repeat_until' => ['repeat_until', 'date'],
|
||||
'nr_of_repetitions' => ['nr_of_repetitions', 'integer'],
|
||||
'apply_rules' => ['apply_rules', 'boolean'],
|
||||
'active' => ['active', 'boolean'],
|
||||
'notes' => ['notes', 'nlString'],
|
||||
];
|
||||
$recurrence = $this->getAllData($fields);
|
||||
|
||||
return [
|
||||
'recurrence' => [
|
||||
'type' => $this->string('type'),
|
||||
'title' => $this->string('title'),
|
||||
'description' => $this->string('description'),
|
||||
'first_date' => $this->date('first_date'),
|
||||
'repeat_until' => $this->date('repeat_until'),
|
||||
'repetitions' => $this->integer('nr_of_repetitions'),
|
||||
'apply_rules' => $applyRules,
|
||||
'active' => $active,
|
||||
],
|
||||
'recurrence' => $recurrence,
|
||||
'transactions' => $this->getTransactionData(),
|
||||
'repetitions' => $this->getRepetitionData(),
|
||||
];
|
||||
@@ -93,7 +87,7 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
/** @var array $transaction */
|
||||
foreach ($transactions as $transaction) {
|
||||
$return[] = $this->getSingleRecurrenceData($transaction);
|
||||
$return[] = $this->getSingleTransactionData($transaction);
|
||||
}
|
||||
|
||||
return $return;
|
||||
@@ -115,12 +109,21 @@ class StoreRequest extends FormRequest
|
||||
}
|
||||
/** @var array $repetition */
|
||||
foreach ($repetitions as $repetition) {
|
||||
$return[] = [
|
||||
'type' => $repetition['type'],
|
||||
'moment' => $repetition['moment'],
|
||||
'skip' => (int) $repetition['skip'],
|
||||
'weekend' => (int) $repetition['weekend'],
|
||||
];
|
||||
$current = [];
|
||||
if (array_key_exists('type', $repetition)) {
|
||||
$current['type'] = $repetition['type'];
|
||||
}
|
||||
if (array_key_exists('moment', $repetition)) {
|
||||
$current['moment'] = $repetition['moment'];
|
||||
}
|
||||
if (array_key_exists('skip', $repetition)) {
|
||||
$current['skip'] = (int)$repetition['skip'];
|
||||
}
|
||||
if (array_key_exists('weekend', $repetition)) {
|
||||
$current['weekend'] = (int)$repetition['weekend'];
|
||||
}
|
||||
|
||||
$return[] = $current;
|
||||
}
|
||||
|
||||
return $return;
|
||||
@@ -142,12 +145,12 @@ class StoreRequest extends FormRequest
|
||||
'first_date' => 'required|date',
|
||||
'apply_rules' => [new IsBoolean],
|
||||
'active' => [new IsBoolean],
|
||||
'repeat_until' => sprintf('date|after:%s', $today->format('Y-m-d')),
|
||||
'repeat_until' => 'date',
|
||||
'nr_of_repetitions' => 'numeric|between:1,31',
|
||||
'repetitions.*.type' => 'required|in:daily,weekly,ndom,monthly,yearly',
|
||||
'repetitions.*.moment' => 'between:0,10',
|
||||
'repetitions.*.skip' => 'required|numeric|between:0,31',
|
||||
'repetitions.*.weekend' => 'required|numeric|min:1|max:4',
|
||||
'repetitions.*.skip' => 'numeric|between:0,31',
|
||||
'repetitions.*.weekend' => 'numeric|min:1|max:4',
|
||||
'transactions.*.description' => 'required|between:1,255',
|
||||
'transactions.*.amount' => 'required|numeric|gt:0',
|
||||
'transactions.*.foreign_amount' => 'numeric|gt:0',
|
||||
@@ -184,6 +187,7 @@ class StoreRequest extends FormRequest
|
||||
{
|
||||
$validator->after(
|
||||
function (Validator $validator) {
|
||||
$this->validateRecurringConfig($validator);
|
||||
$this->validateOneRecurrenceTransaction($validator);
|
||||
$this->validateOneRepetition($validator);
|
||||
$this->validateRecurrenceRepetition($validator);
|
||||
|
||||
@@ -40,7 +40,6 @@ class StoreRequest extends FormRequest
|
||||
use ConvertsDataTypes, GetRuleConfiguration, ChecksLogin;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get all data from the request.
|
||||
*
|
||||
@@ -48,31 +47,23 @@ class StoreRequest extends FormRequest
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
$strict = true;
|
||||
$active = true;
|
||||
$stopProcessing = false;
|
||||
if (null !== $this->get('active')) {
|
||||
$active = $this->boolean('active');
|
||||
}
|
||||
if (null !== $this->get('strict')) {
|
||||
$strict = $this->boolean('strict');
|
||||
}
|
||||
if (null !== $this->get('stop_processing')) {
|
||||
$stopProcessing = $this->boolean('stop_processing');
|
||||
}
|
||||
|
||||
return [
|
||||
'title' => $this->string('title'),
|
||||
'description' => $this->string('description'),
|
||||
'rule_group_id' => $this->integer('rule_group_id'),
|
||||
'rule_group_title' => $this->string('rule_group_title'),
|
||||
'trigger' => $this->string('trigger'),
|
||||
'strict' => $strict,
|
||||
'stop_processing' => $stopProcessing,
|
||||
'active' => $active,
|
||||
'triggers' => $this->getRuleTriggers(),
|
||||
'actions' => $this->getRuleActions(),
|
||||
$fields = [
|
||||
'title' => ['title', 'string'],
|
||||
'description' => ['description', 'string'],
|
||||
'rule_group_id' => ['rule_group_id', 'integer'],
|
||||
'order' => ['order', 'integer'],
|
||||
'rule_group_title' => ['rule_group_title', 'string'],
|
||||
'trigger' => ['trigger', 'string'],
|
||||
'strict' => ['strict', 'boolean'],
|
||||
'stop_processing' => ['stop_processing', 'boolean'],
|
||||
'active' => ['active', 'boolean'],
|
||||
];
|
||||
$data = $this->getAllData($fields);
|
||||
|
||||
$data['triggers'] = $this->getRuleTriggers();
|
||||
$data['actions'] = $this->getRuleActions();
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -87,8 +78,8 @@ class StoreRequest extends FormRequest
|
||||
$return[] = [
|
||||
'type' => $trigger['type'],
|
||||
'value' => $trigger['value'],
|
||||
'active' => $this->convertBoolean((string) ($trigger['active'] ?? 'false')),
|
||||
'stop_processing' => $this->convertBoolean((string) ($trigger['stop_processing'] ?? 'false')),
|
||||
'active' => $this->convertBoolean((string)($trigger['active'] ?? 'false')),
|
||||
'stop_processing' => $this->convertBoolean((string)($trigger['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -108,8 +99,8 @@ class StoreRequest extends FormRequest
|
||||
$return[] = [
|
||||
'type' => $action['type'],
|
||||
'value' => $action['value'],
|
||||
'active' => $this->convertBoolean((string) ($action['active'] ?? 'false')),
|
||||
'stop_processing' => $this->convertBoolean((string) ($action['stop_processing'] ?? 'false')),
|
||||
'active' => $this->convertBoolean((string)($action['active'] ?? 'false')),
|
||||
'stop_processing' => $this->convertBoolean((string)($action['stop_processing'] ?? 'false')),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -134,7 +125,7 @@ class StoreRequest extends FormRequest
|
||||
return [
|
||||
'title' => 'required|between:1,100|uniqueObjectForUser:rules,title',
|
||||
'description' => 'between:1,5000|nullable',
|
||||
'rule_group_id' => 'required|belongsToUser:rule_groups|required_without:rule_group_title',
|
||||
'rule_group_id' => 'belongsToUser:rule_groups|required_without:rule_group_title',
|
||||
'rule_group_title' => 'nullable|between:1,255|required_without:rule_group_id|belongsToUser:rule_groups,title',
|
||||
'trigger' => 'required|in:store-journal,update-journal',
|
||||
'triggers.*.type' => 'required|in:' . implode(',', $validTriggers),
|
||||
@@ -179,7 +170,7 @@ class StoreRequest extends FormRequest
|
||||
$triggers = $data['triggers'] ?? [];
|
||||
// need at least one trigger
|
||||
if (!is_countable($triggers) || 0 === count($triggers)) {
|
||||
$validator->errors()->add('title', (string) trans('validation.at_least_one_trigger'));
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_trigger'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +185,7 @@ class StoreRequest extends FormRequest
|
||||
$actions = $data['actions'] ?? [];
|
||||
// need at least one trigger
|
||||
if (!is_countable($actions) || 0 === count($actions)) {
|
||||
$validator->errors()->add('title', (string) trans('validation.at_least_one_action'));
|
||||
$validator->errors()->add('title', (string)trans('validation.at_least_one_action'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,8 +41,9 @@ class RecurrenceFactory
|
||||
{
|
||||
|
||||
use TransactionTypeTrait, RecurringTransactionTrait;
|
||||
|
||||
private MessageBag $errors;
|
||||
private User $user;
|
||||
private User $user;
|
||||
|
||||
|
||||
/**
|
||||
@@ -58,8 +59,8 @@ class RecurrenceFactory
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws FireflyException
|
||||
* @return Recurrence
|
||||
* @throws FireflyException
|
||||
*/
|
||||
public function create(array $data): Recurrence
|
||||
{
|
||||
@@ -72,26 +73,60 @@ class RecurrenceFactory
|
||||
|
||||
throw new FireflyException($message);
|
||||
}
|
||||
/** @var Carbon $firstDate */
|
||||
$firstDate = $data['recurrence']['first_date'];
|
||||
$firstDate = null;
|
||||
$repeatUntil = null;
|
||||
$repetitions = 0;
|
||||
$title = null;
|
||||
$description = '';
|
||||
$applyRules = true;
|
||||
$active = true;
|
||||
if (array_key_exists('first_date', $data['recurrence'])) {
|
||||
/** @var Carbon $firstDate */
|
||||
$firstDate = $data['recurrence']['first_date'];
|
||||
}
|
||||
if (array_key_exists('nr_of_repetitions', $data['recurrence'])) {
|
||||
$repetitions = (int)$data['recurrence']['nr_of_repetitions'];
|
||||
}
|
||||
if (array_key_exists('repeat_until', $data['recurrence'])) {
|
||||
$repeatUntil = $data['recurrence']['repeat_until'];
|
||||
}
|
||||
if (array_key_exists('title', $data['recurrence'])) {
|
||||
$title = $data['recurrence']['title'];
|
||||
}
|
||||
if (array_key_exists('description', $data['recurrence'])) {
|
||||
$description = $data['recurrence']['description'];
|
||||
}
|
||||
if (array_key_exists('apply_rules', $data['recurrence'])) {
|
||||
$applyRules = $data['recurrence']['apply_rules'];
|
||||
}
|
||||
if (array_key_exists('active', $data['recurrence'])) {
|
||||
$active = $data['recurrence']['active'];
|
||||
}
|
||||
if ($repetitions > 0 && null === $repeatUntil) {
|
||||
$repeatUntil = Carbon::create()->addyear();
|
||||
}
|
||||
|
||||
$repetitions = (int) $data['recurrence']['repetitions'];
|
||||
$recurrence = new Recurrence(
|
||||
$recurrence = new Recurrence(
|
||||
[
|
||||
'user_id' => $this->user->id,
|
||||
'transaction_type_id' => $type->id,
|
||||
'title' => $data['recurrence']['title'],
|
||||
'description' => $data['recurrence']['description'],
|
||||
'first_date' => $firstDate->format('Y-m-d'),
|
||||
'repeat_until' => $repetitions > 0 ? null : $data['recurrence']['repeat_until'],
|
||||
'title' => $title,
|
||||
'description' => $description,
|
||||
'first_date' => $firstDate ? $firstDate->format('Y-m-d') : null,
|
||||
'repeat_until' => $repetitions > 0 ? null : $repeatUntil->format('Y-m-d'),
|
||||
'latest_date' => null,
|
||||
'repetitions' => $data['recurrence']['repetitions'],
|
||||
'apply_rules' => $data['recurrence']['apply_rules'],
|
||||
'active' => $data['recurrence']['active'],
|
||||
'repetitions' => $repetitions,
|
||||
'apply_rules' => $applyRules,
|
||||
'active' => $active,
|
||||
]
|
||||
);
|
||||
$recurrence->save();
|
||||
|
||||
if (array_key_exists('notes', $data['recurrence'])) {
|
||||
$this->updateNote($recurrence, (string)$data['recurrence']['notes']);
|
||||
|
||||
}
|
||||
|
||||
$this->createRepetitions($recurrence, $data['repetitions'] ?? []);
|
||||
try {
|
||||
$this->createTransactions($recurrence, $data['transactions'] ?? []);
|
||||
|
||||
@@ -28,9 +28,11 @@ use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use FireflyIII\Repositories\RuleGroup\RuleGroupRepositoryInterface;
|
||||
use FireflyIII\Support\Search\OperatorQuerySearch;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Support\Collection;
|
||||
use Log;
|
||||
|
||||
/**
|
||||
* Class RuleRepository.
|
||||
@@ -367,19 +369,9 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
*/
|
||||
public function resetRuleOrder(RuleGroup $ruleGroup): bool
|
||||
{
|
||||
$ruleGroup->rules()->withTrashed()->whereNotNull('deleted_at')->update(['order' => 0]);
|
||||
|
||||
$set = $ruleGroup->rules()
|
||||
->orderBy('order', 'ASC')
|
||||
->orderBy('updated_at', 'DESC')
|
||||
->get();
|
||||
$count = 1;
|
||||
/** @var Rule $entry */
|
||||
foreach ($set as $entry) {
|
||||
$entry->order = $count;
|
||||
$entry->save();
|
||||
++$count;
|
||||
}
|
||||
$groupRepository = app(RuleGroupRepositoryInterface::class);
|
||||
$groupRepository->setUser($ruleGroup->user);
|
||||
$groupRepository->resetRuleOrder($ruleGroup);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -407,6 +399,43 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setOrder(Rule $rule, int $newOrder): void
|
||||
{
|
||||
$oldOrder = (int)$rule->order;
|
||||
$groupId = (int)$rule->rule_group_id;
|
||||
$maxOrder = $this->maxOrder($rule->ruleGroup);
|
||||
$newOrder = $newOrder > $maxOrder ? $maxOrder + 1 : $newOrder;
|
||||
Log::debug(sprintf('New order will be %d', $newOrder));
|
||||
|
||||
if ($newOrder > $oldOrder) {
|
||||
$this->user->rules()
|
||||
->where('rules.rule_group_id', $groupId)
|
||||
->where('rules.order', '<=', $newOrder)
|
||||
->where('rules.order', '>', $oldOrder)
|
||||
->where('rules.id', '!=', $rule->id)
|
||||
->decrement('rules.order', 1);
|
||||
$rule->order = $newOrder;
|
||||
Log::debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
|
||||
$rule->save();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->user->rules()
|
||||
->where('rules.rule_group_id', $groupId)
|
||||
->where('rules.order', '>=', $newOrder)
|
||||
->where('rules.order', '<', $oldOrder)
|
||||
->where('rules.id', '!=', $rule->id)
|
||||
->increment('rules.order', 1);
|
||||
$rule->order = $newOrder;
|
||||
Log::debug(sprintf('Order of rule #%d ("%s") is now %d', $rule->id, $rule->title, $newOrder));
|
||||
$rule->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
@@ -414,31 +443,48 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
*/
|
||||
public function store(array $data): Rule
|
||||
{
|
||||
/** @var RuleGroup $ruleGroup */
|
||||
$ruleGroup = $this->user->ruleGroups()->find($data['rule_group_id']);
|
||||
|
||||
// get max order:
|
||||
$order = $this->getHighestOrderInRuleGroup($ruleGroup);
|
||||
$ruleGroup = null;
|
||||
if (array_key_exists('rule_group_id', $data)) {
|
||||
$ruleGroup = $this->user->ruleGroups()->find($data['rule_group_id']);
|
||||
}
|
||||
if (array_key_exists('rule_group_title', $data)) {
|
||||
$ruleGroup = $this->user->ruleGroups()->where('title', $data['rule_group_title'])->first();
|
||||
}
|
||||
if (null === $ruleGroup) {
|
||||
throw new FireflyException('No such rule group.');
|
||||
}
|
||||
|
||||
// start by creating a new rule:
|
||||
$rule = new Rule;
|
||||
$rule->user()->associate($this->user->id);
|
||||
|
||||
$rule->rule_group_id = $data['rule_group_id'];
|
||||
$rule->order = ($order + 1);
|
||||
$rule->active = $data['active'];
|
||||
$rule->strict = $data['strict'];
|
||||
$rule->stop_processing = $data['stop_processing'];
|
||||
$rule->rule_group_id = $ruleGroup->id;
|
||||
$rule->order = 31337;
|
||||
$rule->active = array_key_exists('active', $data) ? $data['active'] : true;
|
||||
$rule->strict = array_key_exists('strict', $data) ? $data['strict'] : false;
|
||||
$rule->stop_processing = array_key_exists('stop_processing', $data) ? $data['stop_processing'] : false;
|
||||
$rule->title = $data['title'];
|
||||
$rule->description = strlen($data['description']) > 0 ? $data['description'] : null;
|
||||
|
||||
$rule->description = array_key_exists('stop_processing', $data) ? $data['stop_processing'] : null;
|
||||
$rule->save();
|
||||
$rule->refresh();
|
||||
|
||||
// save update trigger:
|
||||
$this->setRuleTrigger($data['trigger'] ?? 'store-journal', $rule);
|
||||
|
||||
// reset order:
|
||||
$this->resetRuleOrder($ruleGroup);
|
||||
Log::debug('Done with resetting.');
|
||||
if (array_key_exists('order', $data)) {
|
||||
Log::debug(sprintf('User has submitted order %d', $data['order']));
|
||||
$this->setOrder($rule, $data['order']);
|
||||
}
|
||||
|
||||
// start storing triggers:
|
||||
$this->storeTriggers($rule, $data);
|
||||
|
||||
// same for actions.
|
||||
$this->storeActions($rule, $data);
|
||||
$rule->refresh();
|
||||
|
||||
return $rule;
|
||||
}
|
||||
@@ -614,4 +660,12 @@ class RuleRepository implements RuleRepositoryInterface
|
||||
$trigger->stop_processing = false;
|
||||
$trigger->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function maxOrder(RuleGroup $ruleGroup): int
|
||||
{
|
||||
return (int)$ruleGroup->rules()->max('order');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,6 +189,19 @@ interface RuleRepositoryInterface
|
||||
*/
|
||||
public function store(array $data): Rule;
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
* @param int $newOrder
|
||||
*/
|
||||
public function setOrder(Rule $rule, int $newOrder): void;
|
||||
|
||||
/**
|
||||
* @param RuleGroup $ruleGroup
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function maxOrder(RuleGroup $ruleGroup): int;
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
* @param array $values
|
||||
|
||||
@@ -24,7 +24,9 @@ namespace FireflyIII\Repositories\RuleGroup;
|
||||
|
||||
use Exception;
|
||||
use FireflyIII\Models\Rule;
|
||||
use FireflyIII\Models\RuleAction;
|
||||
use FireflyIII\Models\RuleGroup;
|
||||
use FireflyIII\Models\RuleTrigger;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -365,10 +367,13 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
||||
$count = 1;
|
||||
/** @var Rule $entry */
|
||||
foreach ($set as $entry) {
|
||||
if ($entry->order !== $count) {
|
||||
if ((int)$entry->order !== $count) {
|
||||
Log::debug(sprintf('Rule #%d was on spot %d but must be on spot %d', $entry->id, $entry->order, $count));
|
||||
$entry->order = $count;
|
||||
$entry->save();
|
||||
}
|
||||
$this->resetRuleActionOrder($entry);
|
||||
$this->resetRuleTriggerOrder($entry);
|
||||
|
||||
++$count;
|
||||
}
|
||||
@@ -376,6 +381,51 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
*/
|
||||
private function resetRuleActionOrder(Rule $rule): void
|
||||
{
|
||||
$actions = $rule->ruleActions()
|
||||
->orderBy('order', 'ASC')
|
||||
->orderBy('active', 'DESC')
|
||||
->orderBy('action_type', 'ASC')
|
||||
->get();
|
||||
$index = 1;
|
||||
/** @var RuleAction $action */
|
||||
foreach ($actions as $action) {
|
||||
if ((int)$action->order !== $index) {
|
||||
$action->order = $index;
|
||||
$action->save();
|
||||
Log::debug(sprintf('Rule action #%d was on spot %d but must be on spot %d', $action->id, $action->order, $index));
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Rule $rule
|
||||
*/
|
||||
private function resetRuleTriggerOrder(Rule $rule): void
|
||||
{
|
||||
$triggers = $rule->ruleTriggers()
|
||||
->orderBy('order', 'ASC')
|
||||
->orderBy('active', 'DESC')
|
||||
->orderBy('trigger_type', 'ASC')
|
||||
->get();
|
||||
$index = 1;
|
||||
/** @var RuleTrigger $trigger */
|
||||
foreach ($triggers as $trigger) {
|
||||
$order = (int) $trigger->order;
|
||||
if ($order !== $index) {
|
||||
$trigger->order = $index;
|
||||
$trigger->save();
|
||||
Log::debug(sprintf('Rule trigger #%d was on spot %d but must be on spot %d', $trigger->id, $order, $index));
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -412,12 +462,14 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface
|
||||
'title' => $data['title'],
|
||||
'description' => $data['description'],
|
||||
'order' => 31337,
|
||||
'active' => $data['active'],
|
||||
'active' => array_key_exists('active', $data) ? $data['active'] : true,
|
||||
]
|
||||
);
|
||||
$newRuleGroup->save();
|
||||
$this->resetOrder();
|
||||
$this->setOrder($newRuleGroup, $data['order']);
|
||||
if (array_key_exists('order', $data)) {
|
||||
$this->setOrder($newRuleGroup, $data['order']);
|
||||
}
|
||||
|
||||
return $newRuleGroup;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ use FireflyIII\Factory\PiggyBankFactory;
|
||||
use FireflyIII\Factory\TransactionCurrencyFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceMeta;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
@@ -61,7 +62,7 @@ trait RecurringTransactionTrait
|
||||
'recurrence_id' => $recurrence->id,
|
||||
'repetition_type' => $array['type'],
|
||||
'repetition_moment' => $array['moment'] ?? '',
|
||||
'repetition_skip' => $array['skip'],
|
||||
'repetition_skip' => $array['skip'] ?? 0,
|
||||
'weekend' => $array['weekend'] ?? 1,
|
||||
]
|
||||
);
|
||||
@@ -69,6 +70,38 @@ trait RecurringTransactionTrait
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Recurrence $recurrence
|
||||
* @param string $note
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function updateNote(Recurrence $recurrence, string $note): bool
|
||||
{
|
||||
if ('' === $note) {
|
||||
$dbNote = $recurrence->notes()->first();
|
||||
if (null !== $dbNote) {
|
||||
try {
|
||||
$dbNote->delete();
|
||||
} catch (Exception $e) {
|
||||
Log::debug(sprintf('Error deleting note: %s', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
$dbNote = $recurrence->notes()->first();
|
||||
if (null === $dbNote) {
|
||||
$dbNote = new Note();
|
||||
$dbNote->noteable()->associate($recurrence);
|
||||
}
|
||||
$dbNote->text = trim($note);
|
||||
$dbNote->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store transactions of a recurring transactions. It's complex but readable.
|
||||
*
|
||||
@@ -82,8 +115,8 @@ trait RecurringTransactionTrait
|
||||
foreach ($transactions as $array) {
|
||||
$sourceTypes = config(sprintf('firefly.expected_source_types.source.%s', $recurrence->transactionType->type));
|
||||
$destTypes = config(sprintf('firefly.expected_source_types.destination.%s', $recurrence->transactionType->type));
|
||||
$source = $this->findAccount($sourceTypes, $array['source_id'], $array['source_name']);
|
||||
$destination = $this->findAccount($destTypes, $array['destination_id'], $array['destination_name']);
|
||||
$source = $this->findAccount($sourceTypes, $array['source_id'], null);
|
||||
$destination = $this->findAccount($destTypes, $array['destination_id'], null);
|
||||
|
||||
/** @var TransactionCurrencyFactory $factory */
|
||||
$factory = app(TransactionCurrencyFactory::class);
|
||||
@@ -107,7 +140,6 @@ trait RecurringTransactionTrait
|
||||
}
|
||||
|
||||
// TODO typeOverrule: the account validator may have another opinion on the transaction type.
|
||||
|
||||
$transaction = new RecurrenceTransaction(
|
||||
[
|
||||
'recurrence_id' => $recurrence->id,
|
||||
@@ -116,30 +148,36 @@ trait RecurringTransactionTrait
|
||||
'source_id' => $source->id,
|
||||
'destination_id' => $destination->id,
|
||||
'amount' => $array['amount'],
|
||||
'foreign_amount' => '' === (string)$array['foreign_amount'] ? null : (string)$array['foreign_amount'],
|
||||
'foreign_amount' => array_key_exists('foreign_amount', $array) ? (string)$array['foreign_amount'] : null,
|
||||
'description' => $array['description'],
|
||||
]
|
||||
);
|
||||
$transaction->save();
|
||||
|
||||
/** @var BudgetFactory $budgetFactory */
|
||||
$budgetFactory = app(BudgetFactory::class);
|
||||
$budgetFactory->setUser($recurrence->user);
|
||||
$budget = $budgetFactory->find($array['budget_id'], $array['budget_name']);
|
||||
$budget = null;
|
||||
if (array_key_exists('budget_id', $array)) {
|
||||
/** @var BudgetFactory $budgetFactory */
|
||||
$budgetFactory = app(BudgetFactory::class);
|
||||
$budgetFactory->setUser($recurrence->user);
|
||||
$budget = $budgetFactory->find($array['budget_id'], null);
|
||||
}
|
||||
|
||||
/** @var CategoryFactory $categoryFactory */
|
||||
$categoryFactory = app(CategoryFactory::class);
|
||||
$categoryFactory->setUser($recurrence->user);
|
||||
$category = $categoryFactory->findOrCreate($array['category_id'], $array['category_name']);
|
||||
$category = null;
|
||||
if (array_key_exists('category_id', $array)) {
|
||||
/** @var CategoryFactory $categoryFactory */
|
||||
$categoryFactory = app(CategoryFactory::class);
|
||||
$categoryFactory->setUser($recurrence->user);
|
||||
$category = $categoryFactory->findOrCreate($array['category_id'], null);
|
||||
}
|
||||
|
||||
// same for piggy bank
|
||||
$piggyId = (int)($array['piggy_bank_id'] ?? 0.0);
|
||||
$piggyName = $array['piggy_bank_name'] ?? '';
|
||||
$this->updatePiggyBank($transaction, $piggyId, $piggyName);
|
||||
if (array_key_exists('piggy_bank_id', $array)) {
|
||||
$this->updatePiggyBank($transaction, (int)$array['piggy_bank_id']);
|
||||
}
|
||||
|
||||
// same for tags
|
||||
$tags = $array['tags'] ?? [];
|
||||
$this->updateTags($transaction, $tags);
|
||||
if(array_key_exists('tags', $array)) {
|
||||
$this->updateTags($transaction, $array['tags']);
|
||||
}
|
||||
|
||||
// create recurrence transaction meta:
|
||||
if (null !== $budget) {
|
||||
@@ -246,14 +284,13 @@ trait RecurringTransactionTrait
|
||||
/**
|
||||
* @param RecurrenceTransaction $transaction
|
||||
* @param int $piggyId
|
||||
* @param string $piggyName
|
||||
*/
|
||||
protected function updatePiggyBank(RecurrenceTransaction $transaction, int $piggyId, string $piggyName): void
|
||||
protected function updatePiggyBank(RecurrenceTransaction $transaction, int $piggyId): void
|
||||
{
|
||||
/** @var PiggyBankFactory $factory */
|
||||
$factory = app(PiggyBankFactory::class);
|
||||
$factory->setUser($transaction->recurrence->user);
|
||||
$piggyBank = $factory->find($piggyId, $piggyName);
|
||||
$piggyBank = $factory->find($piggyId, null);
|
||||
if (null !== $piggyBank) {
|
||||
/** @var RecurrenceMeta $entry */
|
||||
$entry = $transaction->recurrenceTransactionMeta()->where('name', 'piggy_bank_id')->first();
|
||||
|
||||
@@ -33,31 +33,58 @@ trait GetRecurrenceData
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getSingleRecurrenceData(array $transaction): array
|
||||
protected function getSingleTransactionData(array $transaction): array
|
||||
{
|
||||
return [
|
||||
'amount' => $transaction['amount'],
|
||||
'currency_id' => isset($transaction['currency_id']) ? (int) $transaction['currency_id'] : null,
|
||||
'currency_code' => $transaction['currency_code'] ?? null,
|
||||
'foreign_amount' => $transaction['foreign_amount'] ?? null,
|
||||
'foreign_currency_id' => isset($transaction['foreign_currency_id']) ? (int) $transaction['foreign_currency_id'] : null,
|
||||
'foreign_currency_code' => $transaction['foreign_currency_code'] ?? null,
|
||||
'source_id' => isset($transaction['source_id']) ? (int) $transaction['source_id'] : null,
|
||||
'source_name' => isset($transaction['source_name']) ? (string) $transaction['source_name'] : null,
|
||||
'destination_id' => isset($transaction['destination_id']) ? (int) $transaction['destination_id'] : null,
|
||||
'destination_name' => isset($transaction['destination_name']) ? (string) $transaction['destination_name'] : null,
|
||||
'description' => $transaction['description'],
|
||||
'type' => $this->string('type'),
|
||||
$return = [];
|
||||
|
||||
// new and updated fields:
|
||||
'piggy_bank_id' => isset($transaction['piggy_bank_id']) ? (int) $transaction['piggy_bank_id'] : null,
|
||||
'piggy_bank_name' => $transaction['piggy_bank_name'] ?? null,
|
||||
'tags' => $transaction['tags'] ?? [],
|
||||
'budget_id' => isset($transaction['budget_id']) ? (int) $transaction['budget_id'] : null,
|
||||
'budget_name' => $transaction['budget_name'] ?? null,
|
||||
'category_id' => isset($transaction['category_id']) ? (int) $transaction['category_id'] : null,
|
||||
'category_name' => $transaction['category_name'] ?? null,
|
||||
];
|
||||
// amount + currency
|
||||
if (array_key_exists('amount', $transaction)) {
|
||||
$return['amount'] = $transaction['amount'];
|
||||
}
|
||||
if (array_key_exists('currency_id', $transaction)) {
|
||||
$return['currency_id'] = (int)$transaction['currency_id'];
|
||||
}
|
||||
if (array_key_exists('currency_code', $transaction)) {
|
||||
$return['currency_code'] = $transaction['currency_code'];
|
||||
}
|
||||
|
||||
// foreign amount + currency
|
||||
if (array_key_exists('foreign_amount', $transaction)) {
|
||||
$return['foreign_amount'] = $transaction['foreign_amount'];
|
||||
}
|
||||
if (array_key_exists('foreign_currency_id', $transaction)) {
|
||||
$return['foreign_currency_id'] = (int)$transaction['foreign_currency_id'];
|
||||
}
|
||||
if (array_key_exists('foreign_currency_code', $transaction)) {
|
||||
$return['foreign_currency_code'] = $transaction['foreign_currency_code'];
|
||||
}
|
||||
// source + dest
|
||||
if (array_key_exists('source_id', $transaction)) {
|
||||
$return['source_id'] = (int)$transaction['source_id'];
|
||||
}
|
||||
if (array_key_exists('destination_id', $transaction)) {
|
||||
$return['destination_id'] = (int)$transaction['destination_id'];
|
||||
}
|
||||
// description
|
||||
if (array_key_exists('description', $transaction)) {
|
||||
$return['description'] = $transaction['description'];
|
||||
}
|
||||
|
||||
if (array_key_exists('piggy_bank_id', $transaction)) {
|
||||
$return['piggy_bank_id'] = (int)$transaction['piggy_bank_id'];
|
||||
}
|
||||
|
||||
if (array_key_exists('tags', $transaction)) {
|
||||
$return['tags'] = $transaction['tags'];
|
||||
}
|
||||
if (array_key_exists('budget_id', $transaction)) {
|
||||
$return['budget_id'] = (int)$transaction['budget_id'];
|
||||
}
|
||||
if (array_key_exists('category_id', $transaction)) {
|
||||
$return['category_id'] = (int)$transaction['category_id'];
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,7 +36,22 @@ use Log;
|
||||
*/
|
||||
trait RecurrenceValidation
|
||||
{
|
||||
public function validateRecurringConfig(Validator $validator) {
|
||||
$data = $validator->getData();
|
||||
$reps = array_key_exists('nr_of_repetitions', $data) ? (int)$data['nr_of_repetitions'] : null;
|
||||
$repeatUntil = array_key_exists('repeat_until', $data) ? new Carbon($data['repeat_until']) : null;
|
||||
|
||||
if(null === $reps && null === $repeatUntil) {
|
||||
$validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until'));
|
||||
$validator->errors()->add('repeat_until', trans('validation.require_repeat_until'));
|
||||
return;
|
||||
}
|
||||
if($reps > 0 && null !== $repeatUntil) {
|
||||
$validator->errors()->add('nr_of_repetitions', trans('validation.require_repeat_until'));
|
||||
$validator->errors()->add('repeat_until', trans('validation.require_repeat_until'));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate account information input for recurrences which are being updated.
|
||||
|
||||
Reference in New Issue
Block a user