From 305ee59477bc13ea9bb904f0b8ba5eb0f4ab2f43 Mon Sep 17 00:00:00 2001 From: Ruben Carlo Benante Date: Wed, 8 Jul 2026 00:32:48 -0300 Subject: [PATCH] advance template installment on RecoReco spawn (v1.0.3) --- Model/FinancePersistence.php | 38 ++++++++++++++++++++++++++++++++++++ Plugin.php | 7 ++++++- VERSION | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Model/FinancePersistence.php b/Model/FinancePersistence.php index 4530b12..b8cf872 100644 --- a/Model/FinancePersistence.php +++ b/Model/FinancePersistence.php @@ -73,6 +73,19 @@ class FinancePersistence extends Base } } + /** + * recoreco:task:spawned -- RecoReco (calendar recurrence) just spawned a copy. Its ongoing card + * is the TEMPLATE that stays (unlike native recurrence, whose ongoing card is the new child), so + * advance the SOURCE template's installment. The clone already copied the current installment + * verbatim via onDuplication during RecoReco's duplicate() call. + */ + public function onRecoRecoSpawn(array &$payload) + { + if (! empty($payload['source_task_id'])) { + $this->advanceInstallment((int) $payload['source_task_id']); + } + } + /** * model:task:modification:prepare -- fires before UPDATE, $values by reference. The task id is * removed from $values by core, but it is the route parameter of the modification request. @@ -176,6 +189,31 @@ class FinancePersistence extends Base )); } + /** + * Advance a task's current installment by one, in place. A finite plan clamps at the total + * (p10/10 stays p10/10); an open-ended one (no total) increments unbounded (p2 -> p3). Cards + * with no numeric current installment are left alone. + */ + private function advanceInstallment($task_id) + { + $current = $this->taskMetadataModel->get($task_id, FinanceHelper::INSTALLMENT_CURRENT_KEY, ''); + + if ($current === '' || ! ctype_digit((string) $current)) { + return; + } + + $total = $this->taskMetadataModel->get($task_id, FinanceHelper::INSTALLMENT_TOTAL_KEY, ''); + $next = (int) $current + 1; + + if ($total !== '' && ctype_digit((string) $total) && $next > (int) $total) { + $next = (int) $total; + } + + $this->taskMetadataModel->save($task_id, array( + FinanceHelper::INSTALLMENT_CURRENT_KEY => (string) $next, + )); + } + private function intOrBlank($raw) { $raw = trim((string) $raw); diff --git a/Plugin.php b/Plugin.php index cf264c8..8b92ffe 100644 --- a/Plugin.php +++ b/Plugin.php @@ -34,6 +34,11 @@ class Plugin extends Base // and a manual Duplicate copies it verbatim. $this->hook->on('model:task:duplication:aftersave', array($persistence, 'onDuplication')); + // RecoReco (calendar recurrence) spawns a copy and emits this signal. The clone already got + // the finance verbatim (via onDuplication above); here we advance the SOURCE template's + // installment, since RecoReco's ongoing card is the template that stays. + $this->hook->on('recoreco:task:spawned', array($persistence, 'onRecoRecoSpawn')); + // The line-3 money badge on each board card, rendered directly under the title. Two hooks: // "private" is the normal board, "public" is the read-only board shared by token. $this->template->hook->attach('template:board:private:task:after-title', 'financeBuddy:board/task_money'); @@ -72,7 +77,7 @@ class Plugin extends Base public function getPluginVersion() { - return '1.0.2'; + return '1.0.3'; } public function getPluginHomepage() diff --git a/VERSION b/VERSION index 99eeab3..71cbcbc 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -FinanceBuddy v1.0.2 +FinanceBuddy v1.0.3