From 45521632291dfcdf045078740ed6a3152bdd4708 Mon Sep 17 00:00:00 2001 From: Frank Karlitschek Date: Wed, 12 Aug 2026 14:57:01 +0200 Subject: [PATCH] feat(entitlements): default a full-time year to 28 days of annual leave MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 25 was a placeholder. 28 is the full-time annual allowance, so it is the number a fresh instance should start from and the one the admin form should offer. The value is declared twice — once in the config lexicon, once as the admin form's field default — and AdminDeclarativeSettingsTest fails if the two disagree, so both move together, along with the settings tables in the README and the specification. The 25s left in the service tests are deliberate: they stub getDefaultEntitlement() to prove the code reads the configured value rather than a constant, and a stub that differs from the real default tests that more strongly, not less. Existing installations are unaffected: a lexicon default applies only to a key that was never set, and ensureEntitlement() consults it only when creating a row, so stored entitlements keep their current allowance. Moving current staff to 28 is a deliberate HR bulk-set, not a silent migration. Co-Authored-By: Claude Opus 5 (1M context) --- README.md | 2 +- SPECIFICATION.md | 2 +- lib/ConfigLexicon.php | 4 ++-- lib/Settings/AdminDeclarativeSettings.php | 2 +- tests/Unit/ConfigLexiconTest.php | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e365a68..fdb5915 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ settings form, so there is no bespoke admin UI to learn. | Setting | Default | What it does | |---|---|---| | HR group | `hr` | Which Nextcloud group holds HR powers | -| Default annual entitlement | 25 days | Seed for new entitlement rows | +| Default annual entitlement | 28 days | Seed for new entitlement rows | | Escalation window | 3 working days | How long a manager may sit on a request before HR is pulled in | | Reminder lead time | 1 day | How long before escalation the manager is nudged | | Carry-over policy | `capped` | `none`, `unlimited` or `capped` | diff --git a/SPECIFICATION.md b/SPECIFICATION.md index 2d685a1..102d167 100644 --- a/SPECIFICATION.md +++ b/SPECIFICATION.md @@ -663,7 +663,7 @@ new "Absence" settings section or "Personal info"/"Administration"): | Setting | Default | Notes | |---------|---------|-------| | HR group id | `hr` | Which NC group is HR (§2). | -| Default annual entitlement (days) | 25 | Seed for new entitlement rows. | +| Default annual entitlement (days) | 28 | Seed for new entitlement rows. | | Escalation window | 3 working days | For EscalationJob (§5.4). | | Reminder lead time | 1 day before escalation | For ReminderJob. | | Carry-over policy | `capped` | `none` / `unlimited` / `capped`. | diff --git a/lib/ConfigLexicon.php b/lib/ConfigLexicon.php index ccaf828..9d866f1 100644 --- a/lib/ConfigLexicon.php +++ b/lib/ConfigLexicon.php @@ -55,8 +55,8 @@ public function getAppConfigs(): array { return [ new Entry(self::KEY_HR_GROUP, ValueType::STRING, 'hr', 'Group whose members have the HR role'), - new Entry(self::KEY_DEFAULT_ENTITLEMENT, ValueType::FLOAT, 25.0, - 'Default annual-leave entitlement in working days'), + new Entry(self::KEY_DEFAULT_ENTITLEMENT, ValueType::FLOAT, 28.0, + 'Default annual-leave entitlement in working days (a full-time year)'), new Entry(self::KEY_ESCALATION_WINDOW, ValueType::INT, 3, 'Days before an unanswered pending request is escalated to HR', lazy: true), new Entry(self::KEY_REMINDER_LEAD, ValueType::INT, 1, diff --git a/lib/Settings/AdminDeclarativeSettings.php b/lib/Settings/AdminDeclarativeSettings.php index 491b165..813cd92 100644 --- a/lib/Settings/AdminDeclarativeSettings.php +++ b/lib/Settings/AdminDeclarativeSettings.php @@ -56,7 +56,7 @@ public function getSchema(): array { 'id' => ConfigLexicon::KEY_DEFAULT_ENTITLEMENT, 'title' => $this->l->t('Default annual entitlement (days)'), 'type' => DeclarativeSettingsTypes::NUMBER, - 'default' => 25.0, + 'default' => 28.0, ], [ 'id' => ConfigLexicon::KEY_ESCALATION_WINDOW, diff --git a/tests/Unit/ConfigLexiconTest.php b/tests/Unit/ConfigLexiconTest.php index abf7b45..a8c0fa0 100644 --- a/tests/Unit/ConfigLexiconTest.php +++ b/tests/Unit/ConfigLexiconTest.php @@ -71,7 +71,7 @@ public function testDefaultsAndTypesMatchTheDocumentedBehaviour(): void { $this->assertSame('hr', $entries[ConfigLexicon::KEY_HR_GROUP]->getDefault(Preset::NONE)); $this->assertSame(ValueType::FLOAT, $entries[ConfigLexicon::KEY_DEFAULT_ENTITLEMENT]->getValueType()); - $this->assertSame('25', $entries[ConfigLexicon::KEY_DEFAULT_ENTITLEMENT]->getDefault(Preset::NONE)); + $this->assertSame('28', $entries[ConfigLexicon::KEY_DEFAULT_ENTITLEMENT]->getDefault(Preset::NONE)); $this->assertSame(ValueType::FLOAT, $entries[ConfigLexicon::KEY_CARRYOVER_CAP]->getValueType()); $this->assertSame(ValueType::INT, $entries[ConfigLexicon::KEY_ESCALATION_WINDOW]->getValueType());