From 447511634d2d265f0b6ab5718a38da35bd15c48b Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Sat, 25 Apr 2026 22:36:10 +0200 Subject: [PATCH] feat(form-builder): add ApplyStatus, DismissalReasonType, BindingTargetType enums (WS-6) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DismissalReasonType has six values; manually_resolved is intentionally absent because Resolve and Dismiss are separate workflows (RFC V2). Refs: RFC-WS-6.md §3 (Q4 partial-status separation), §4 (V2 dismiss enum) Co-Authored-By: Claude Opus 4.7 (1M context) --- api/app/Enums/FormBuilder/ApplyStatus.php | 38 ++++++++++++++ .../Enums/FormBuilder/BindingTargetType.php | 19 +++++++ .../Enums/FormBuilder/DismissalReasonType.php | 40 +++++++++++++++ .../Enums/FormBuilder/ApplyStatusTest.php | 41 +++++++++++++++ .../FormBuilder/BindingTargetTypeTest.php | 25 ++++++++++ .../FormBuilder/DismissalReasonTypeTest.php | 50 +++++++++++++++++++ 6 files changed, 213 insertions(+) create mode 100644 api/app/Enums/FormBuilder/ApplyStatus.php create mode 100644 api/app/Enums/FormBuilder/BindingTargetType.php create mode 100644 api/app/Enums/FormBuilder/DismissalReasonType.php create mode 100644 api/tests/Unit/Enums/FormBuilder/ApplyStatusTest.php create mode 100644 api/tests/Unit/Enums/FormBuilder/BindingTargetTypeTest.php create mode 100644 api/tests/Unit/Enums/FormBuilder/DismissalReasonTypeTest.php diff --git a/api/app/Enums/FormBuilder/ApplyStatus.php b/api/app/Enums/FormBuilder/ApplyStatus.php new file mode 100644 index 00000000..a6e28edb --- /dev/null +++ b/api/app/Enums/FormBuilder/ApplyStatus.php @@ -0,0 +1,38 @@ + 'Wachtrij', + self::COMPLETED => 'Voltooid', + self::PARTIAL => 'Gedeeltelijk mislukt', + self::FAILED => 'Mislukt', + }; + } +} diff --git a/api/app/Enums/FormBuilder/BindingTargetType.php b/api/app/Enums/FormBuilder/BindingTargetType.php new file mode 100644 index 00000000..9f50c3de --- /dev/null +++ b/api/app/Enums/FormBuilder/BindingTargetType.php @@ -0,0 +1,19 @@ + 'Formulier verwijderd', + self::TARGET_ENTITY_DELETED => 'Doel-entiteit verwijderd', + self::BINDING_REMOVED => 'Binding verwijderd', + self::DUPLICATE_SUBMISSION => 'Dubbele inzending', + self::DATA_QUALITY_ISSUE => 'Datakwaliteit-probleem', + self::OTHER => 'Anders', + }; + } +} diff --git a/api/tests/Unit/Enums/FormBuilder/ApplyStatusTest.php b/api/tests/Unit/Enums/FormBuilder/ApplyStatusTest.php new file mode 100644 index 00000000..9a7f3f1f --- /dev/null +++ b/api/tests/Unit/Enums/FormBuilder/ApplyStatusTest.php @@ -0,0 +1,41 @@ + $case->value, ApplyStatus::cases()); + sort($values); + $this->assertSame(['completed', 'failed', 'partial', 'pending'], $values); + } + + public function test_is_terminal_truth_table(): void + { + $this->assertFalse(ApplyStatus::PENDING->isTerminal()); + $this->assertTrue(ApplyStatus::COMPLETED->isTerminal()); + $this->assertTrue(ApplyStatus::PARTIAL->isTerminal()); + $this->assertTrue(ApplyStatus::FAILED->isTerminal()); + } + + public function test_is_open_truth_table(): void + { + $this->assertTrue(ApplyStatus::PENDING->isOpen()); + $this->assertFalse(ApplyStatus::COMPLETED->isOpen()); + $this->assertTrue(ApplyStatus::PARTIAL->isOpen()); + $this->assertTrue(ApplyStatus::FAILED->isOpen()); + } + + public function test_label_returns_non_empty_dutch_string_for_each_case(): void + { + foreach (ApplyStatus::cases() as $case) { + $this->assertNotSame('', $case->label()); + } + } +} diff --git a/api/tests/Unit/Enums/FormBuilder/BindingTargetTypeTest.php b/api/tests/Unit/Enums/FormBuilder/BindingTargetTypeTest.php new file mode 100644 index 00000000..72f1d1ba --- /dev/null +++ b/api/tests/Unit/Enums/FormBuilder/BindingTargetTypeTest.php @@ -0,0 +1,25 @@ + $case->value, BindingTargetType::cases()); + sort($values); + $this->assertSame(['collection', 'relation', 'scalar'], $values); + } + + public function test_from_string_round_trip(): void + { + $this->assertSame(BindingTargetType::SCALAR, BindingTargetType::from('scalar')); + $this->assertSame(BindingTargetType::COLLECTION, BindingTargetType::from('collection')); + $this->assertSame(BindingTargetType::RELATION, BindingTargetType::from('relation')); + } +} diff --git a/api/tests/Unit/Enums/FormBuilder/DismissalReasonTypeTest.php b/api/tests/Unit/Enums/FormBuilder/DismissalReasonTypeTest.php new file mode 100644 index 00000000..64e5e126 --- /dev/null +++ b/api/tests/Unit/Enums/FormBuilder/DismissalReasonTypeTest.php @@ -0,0 +1,50 @@ + $case->value, DismissalReasonType::cases()); + sort($values); + $this->assertSame([ + 'binding_removed', + 'data_quality_issue', + 'duplicate_submission', + 'other', + 'schema_deleted', + 'target_entity_deleted', + ], $values); + } + + public function test_manually_resolved_is_intentionally_absent(): void + { + $values = array_map(fn (DismissalReasonType $case) => $case->value, DismissalReasonType::cases()); + $this->assertNotContains('manually_resolved', $values); + } + + public function test_requires_note_only_for_other(): void + { + $this->assertTrue(DismissalReasonType::OTHER->requiresNote()); + + foreach (DismissalReasonType::cases() as $case) { + if ($case === DismissalReasonType::OTHER) { + continue; + } + $this->assertFalse($case->requiresNote(), "{$case->value} must not require a note"); + } + } + + public function test_label_returns_non_empty_dutch_string_for_each_case(): void + { + foreach (DismissalReasonType::cases() as $case) { + $this->assertNotSame('', $case->label()); + } + } +}