diff --git a/app/Api/V1/Requests/Models/RuleGroup/UpdateRequest.php b/app/Api/V1/Requests/Models/RuleGroup/UpdateRequest.php index 8e4ed742cd..c41e927dd1 100644 --- a/app/Api/V1/Requests/Models/RuleGroup/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/RuleGroup/UpdateRequest.php @@ -44,17 +44,15 @@ class UpdateRequest extends FormRequest */ public function getAll(): array { - $active = true; - - if (null !== $this->get('active')) { - $active = $this->boolean('active'); - } - - return [ - 'title' => $this->string('title'), - 'description' => $this->string('description'), - 'active' => $active, + // This is the way. + $fields = [ + 'title' => ['title', 'string'], + 'description' => ['description', 'nlString'], + 'active' => ['active', 'boolean'], + 'order' => ['order', 'integer'], ]; + + return $this->getAllData($fields); } /** @@ -65,8 +63,9 @@ class UpdateRequest extends FormRequest public function rules(): array { $ruleGroup = $this->route()->parameter('ruleGroup'); + return [ - 'title' => 'required|between:1,100|uniqueObjectForUser:rule_groups,title,' . $ruleGroup->id, + 'title' => 'between:1,100|uniqueObjectForUser:rule_groups,title,' . $ruleGroup->id, 'description' => 'between:1,5000|nullable', 'active' => [new IsBoolean], ]; diff --git a/app/Api/V1/Requests/Models/Tag/UpdateRequest.php b/app/Api/V1/Requests/Models/Tag/UpdateRequest.php index ed43076950..86c17ee38e 100644 --- a/app/Api/V1/Requests/Models/Tag/UpdateRequest.php +++ b/app/Api/V1/Requests/Models/Tag/UpdateRequest.php @@ -47,13 +47,14 @@ class UpdateRequest extends FormRequest */ public function getAll(): array { - $data = [ - 'tag' => $this->string('tag'), - 'date' => $this->date('date'), - 'description' => $this->string('description'), - 'has_location' => true, // pretend location is present. + // This is the way. + $fields = [ + 'tag' => ['tag', 'string'], + 'date' => ['date', 'date'], + 'description' => ['description', 'string'], ]; - $data = $this->appendLocationData($data, null); + $data = $this->getAllData($fields); + $data = $this->appendLocationData($data, null); return $data; } @@ -66,9 +67,9 @@ class UpdateRequest extends FormRequest public function rules(): array { $tag = $this->route()->parameter('tagOrId'); - + // TODO is uniqueObjectForUser not obsolete? $rules = [ - 'tag' => 'required|min:1|uniqueObjectForUser:tags,tag,' . $tag->id, + 'tag' => 'min:1|uniqueObjectForUser:tags,tag,' . $tag->id, 'description' => 'min:1|nullable', 'date' => 'date|nullable', ]; diff --git a/app/Repositories/RuleGroup/RuleGroupRepository.php b/app/Repositories/RuleGroup/RuleGroupRepository.php index b67da9bc7a..8b3889d09f 100644 --- a/app/Repositories/RuleGroup/RuleGroupRepository.php +++ b/app/Repositories/RuleGroup/RuleGroupRepository.php @@ -28,6 +28,7 @@ use FireflyIII\User; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Collection; use Log; +use DB; /** * Class RuleGroupRepository. @@ -357,11 +358,25 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface public function update(RuleGroup $ruleGroup, array $data): RuleGroup { // update the account: - $ruleGroup->title = $data['title']; - $ruleGroup->description = $data['description']; - $ruleGroup->active = $data['active']; + if (array_key_exists('title', $data)) { + $ruleGroup->title = $data['title']; + } + if (array_key_exists('description', $data)) { + $ruleGroup->description = $data['description']; + } + if (array_key_exists('active', $data)) { + $ruleGroup->active = $data['active']; + } + // order + if (array_key_exists('order', $data) && $ruleGroup->order !== $data['order']) { + $this->correctRuleGroupOrder(); + $max = $this->maxOrder(); + // TODO also for bills and accounts: + $data['order'] = $data['order'] > $max ? $max : $data['order']; + $ruleGroup = $this->updateOrder($ruleGroup, $ruleGroup->order, $data['order']); + } + $ruleGroup->save(); - $this->resetRuleGroupOrder(); return $ruleGroup; } @@ -401,6 +416,59 @@ class RuleGroupRepository implements RuleGroupRepositoryInterface $search->orderBy('rule_groups.order', 'ASC') ->orderBy('rule_groups.title', 'ASC'); - return $search->take($limit)->get(['id','title','description']); + return $search->take($limit)->get(['id', 'title', 'description']); + } + + /** + * @inheritDoc + */ + public function correctRuleGroupOrder(): void + { + $set = $this->user + ->ruleGroups() + ->orderBy('order', 'ASC') + ->orderBy('active', 'DESC') + ->orderBy('title', 'ASC') + ->get(['rule_groups.id']); + $index = 1; + /** @var RuleGroup $ruleGroup */ + foreach ($set as $ruleGroup) { + if ($ruleGroup->order !== $index) { + $ruleGroup->order = $index; + $ruleGroup->save(); + } + $index++; + } + } + + /** + * @inheritDoc + */ + public function updateOrder(RuleGroup $ruleGroup, int $oldOrder, int $newOrder): RuleGroup + { + if ($newOrder > $oldOrder) { + $this->user->ruleGroups()->where('order', '<=', $newOrder)->where('order', '>', $oldOrder) + ->where('rule_groups.id', '!=', $ruleGroup->id) + ->update(['order' => DB::raw('rule_groups.order-1')]); + $ruleGroup->order = $newOrder; + $ruleGroup->save(); + } + if ($newOrder < $oldOrder) { + $this->user->ruleGroups()->where('order', '>=', $newOrder)->where('order', '<', $oldOrder) + ->where('rule_groups.id', '!=', $ruleGroup->id) + ->update(['order' => DB::raw('rule_groups.order+1')]); + $ruleGroup->order = $newOrder; + $ruleGroup->save(); + } + + return $ruleGroup; + } + + /** + * @inheritDoc + */ + public function maxOrder(): int + { + return (int)$this->user->ruleGroups()->max('order'); } } diff --git a/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php b/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php index 8845b69e6e..760edde6f7 100644 --- a/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php +++ b/app/Repositories/RuleGroup/RuleGroupRepositoryInterface.php @@ -31,6 +31,29 @@ use Illuminate\Support\Collection; */ interface RuleGroupRepositoryInterface { + + /** + * Make sure rule group order is correct in DB. + */ + public function correctRuleGroupOrder(): void; + + /** + * + * @param RuleGroup $ruleGroup + * @param int $oldOrder + * @param int $newOrder + * + * @return RuleGroup + */ + public function updateOrder(RuleGroup $ruleGroup, int $oldOrder, int $newOrder): RuleGroup; + + /** + * Get highest possible order for a rule group. + * + * @return int + */ + public function maxOrder(): int; + /** * Delete everything. */ diff --git a/app/Repositories/Tag/TagRepository.php b/app/Repositories/Tag/TagRepository.php index ceb605c5c5..faf4854615 100644 --- a/app/Repositories/Tag/TagRepository.php +++ b/app/Repositories/Tag/TagRepository.php @@ -28,8 +28,6 @@ use FireflyIII\Factory\TagFactory; use FireflyIII\Helpers\Collector\GroupCollectorInterface; use FireflyIII\Models\Attachment; use FireflyIII\Models\Location; -use FireflyIII\Models\RuleAction; -use FireflyIII\Models\RuleTrigger; use FireflyIII\Models\Tag; use FireflyIII\Models\TransactionType; use FireflyIII\User; @@ -317,7 +315,7 @@ class TagRepository implements TagRepositoryInterface /** @var array $journal */ foreach ($journals as $journal) { - $currencyId = (int) $journal['currency_id']; + $currencyId = (int)$journal['currency_id']; $sums[$currencyId] = $sums[$currencyId] ?? [ 'currency_id' => $currencyId, 'currency_name' => $journal['currency_name'], @@ -331,7 +329,7 @@ class TagRepository implements TagRepositoryInterface ]; // add amount to correct type: - $amount = app('steam')->positive((string) $journal['amount']); + $amount = app('steam')->positive((string)$journal['amount']); $type = $journal['transaction_type_type']; if (TransactionType::WITHDRAWAL === $type) { $amount = bcmul($amount, '-1'); @@ -352,7 +350,7 @@ class TagRepository implements TagRepositoryInterface TransactionType::OPENING_BALANCE => '0', ]; // add foreign amount to correct type: - $amount = app('steam')->positive((string) $journal['foreign_amount']); + $amount = app('steam')->positive((string)$journal['foreign_amount']); $type = $journal['transaction_type_type']; if (TransactionType::WITHDRAWAL === $type) { $amount = bcmul($amount, '-1'); @@ -361,6 +359,7 @@ class TagRepository implements TagRepositoryInterface } } + return $sums; } @@ -395,7 +394,7 @@ class TagRepository implements TagRepositoryInterface Log::debug(sprintf('Each coin in a tag earns it %s points', $pointsPerCoin)); /** @var Tag $tag */ foreach ($tags as $tag) { - $amount = (string) $tag->amount_sum; + $amount = (string)$tag->amount_sum; $amount = '' === $amount ? '0' : $amount; $amountMin = bcsub($amount, $min); $pointsForTag = bcmul($amountMin, $pointsPerCoin); @@ -440,16 +439,24 @@ class TagRepository implements TagRepositoryInterface */ public function update(Tag $tag, array $data): Tag { - $tag->tag = $data['tag']; - $tag->date = $data['date']; - $tag->description = $data['description']; - $tag->latitude = null; - $tag->longitude = null; - $tag->zoomLevel = null; + if (array_key_exists('tag', $data)) { + $tag->tag = $data['tag']; + } + if (array_key_exists('date', $data)) { + $tag->date = $data['date']; + } + if (array_key_exists('description', $data)) { + $tag->description = $data['description']; + } + + $tag->latitude = null; + $tag->longitude = null; + $tag->zoomLevel = null; $tag->save(); // update, delete or create location: $updateLocation = $data['update_location'] ?? false; + $deleteLocation = $data['remove_location'] ?? false; // location must be updated? if (true === $updateLocation) { @@ -472,6 +479,9 @@ class TagRepository implements TagRepositoryInterface $location->save(); } } + if(true === $deleteLocation) { + $tag->locations()->delete(); + } return $tag; } @@ -486,7 +496,7 @@ class TagRepository implements TagRepositoryInterface $max = '0'; /** @var Tag $tag */ foreach ($tags as $tag) { - $amount = (string) $tag->amount_sum; + $amount = (string)$tag->amount_sum; $amount = '' === $amount ? '0' : $amount; $max = 1 === bccomp($amount, $max) ? $amount : $max; @@ -508,7 +518,7 @@ class TagRepository implements TagRepositoryInterface /** @var Tag $tag */ foreach ($tags as $tag) { - $amount = (string) $tag->amount_sum; + $amount = (string)$tag->amount_sum; $amount = '' === $amount ? '0' : $amount; if (null === $min) { diff --git a/app/Services/Internal/Update/JournalUpdateService.php b/app/Services/Internal/Update/JournalUpdateService.php index 88ffddd045..ee893e6154 100644 --- a/app/Services/Internal/Update/JournalUpdateService.php +++ b/app/Services/Internal/Update/JournalUpdateService.php @@ -139,12 +139,14 @@ class JournalUpdateService $this->updateField('date'); $this->updateField('order'); + $this->transactionJournal->save(); $this->transactionJournal->refresh(); $this->updateCategory(); $this->updateBudget(); $this->updateTags(); + $this->updateReconciled(); $this->updateNotes(); $this->updateMeta(); $this->updateCurrency(); @@ -750,4 +752,14 @@ class JournalUpdateService } Log::debug('No type field present.'); } + + /** + * + */ + private function updateReconciled(): void + { + if (array_key_exists('reconciled', $this->data) && is_bool($this->data['reconciled'])) { + $this->transactionJournal->transactions()->update(['reconciled' => $this->data['reconciled']]); + } + } } diff --git a/app/Support/Request/AppendsLocationData.php b/app/Support/Request/AppendsLocationData.php index 1cb9419929..a5e7b8769a 100644 --- a/app/Support/Request/AppendsLocationData.php +++ b/app/Support/Request/AppendsLocationData.php @@ -87,8 +87,6 @@ trait AppendsLocationData $longitudeKey = $this->getLocationKey($prefix, 'longitude'); $latitudeKey = $this->getLocationKey($prefix, 'latitude'); $zoomLevelKey = $this->getLocationKey($prefix, 'zoom_level'); - $hasLocationKey = $this->getLocationKey($prefix, 'has_location'); - $hasLocation = $this->boolean($hasLocationKey) || true === ($data['has_location'] ?? false); $isValidPOST = $this->isValidPost($prefix); $isValidPUT = $this->isValidPUT($prefix); $isValidEmptyPUT = $this->isValidEmptyPUT($prefix); @@ -202,10 +200,11 @@ trait AppendsLocationData return ( null === $this->get($longitudeKey) && null === $this->get($latitudeKey) - && null === $this->has($zoomLevelKey)) - && (('PUT' === $this->method() && $this->routeIs('*.update')) + && null === $this->get($zoomLevelKey)) + && ('PUT' === $this->method() || ('POST' === $this->method() && $this->routeIs('*.update')) ); + } } diff --git a/app/Support/Request/ConvertsDataTypes.php b/app/Support/Request/ConvertsDataTypes.php index 695a5d9db6..e2ff0e08fa 100644 --- a/app/Support/Request/ConvertsDataTypes.php +++ b/app/Support/Request/ConvertsDataTypes.php @@ -265,6 +265,9 @@ trait ConvertsDataTypes if (null === $value) { return false; } + if ('' === $value) { + return false; + } if ('true' === $value) { return true; } diff --git a/app/Transformers/TransactionGroupTransformer.php b/app/Transformers/TransactionGroupTransformer.php index 201f4afba8..f915418cc6 100644 --- a/app/Transformers/TransactionGroupTransformer.php +++ b/app/Transformers/TransactionGroupTransformer.php @@ -538,7 +538,7 @@ class TransactionGroupTransformer extends AbstractTransformer 'sepa_cc' => $metaFieldData['sepa_cc'], 'sepa_ct_op' => $metaFieldData['sepa_ct_op'], 'sepa_ct_id' => $metaFieldData['sepa_ct_id'], - 'sepa_db' => $metaFieldData['sepa_ddb'], + 'sepa_db' => $metaFieldData['sepa_db'], 'sepa_country' => $metaFieldData['sepa_country'], 'sepa_ep' => $metaFieldData['sepa_ep'], 'sepa_ci' => $metaFieldData['sepa_ci'],