Wires the project context into the Determinator row stack so a UPC INF
matter doesn't need to be hand-walked through five obvious cascade picks.
Auto-walk descends single-option chains as `is-prefilled` rows, the inbox
row vanishes for UPC matters (CMS implied), and the first prefilled row
carries the project reference inline ("aus Akte: HL-2024-001").
Backend: `internal/services/proceeding_mapping.go` adds
MapLitigationToFristenrechner — single source of truth for bridging the
litigation conceptual codes (INF / REV / APP / CCR / AMD / APM / OPP) onto
fristenrechner codes (UPC_INF / DE_INF / EPA_OPP / …). Ambiguous combos
(APP+DE, ZPO_CIVIL, AMD+DE) return ok=false; callers degrade to "no
narrowing" instead of guessing. Table-driven test covers every documented
mapping plus the ambiguous-degrade cases.
Frontend: `buildRowStack` filters cascade children by project context
along the proceeding axis (kebab segment lookup against the project's
fristenrechner code); auto-walks while filtered scope narrows to one;
caps depth via `cascadeAutoWalkStopAfter` after an "ändern" on a prefilled
row so the user lands at an active chip set without the auto-walk
re-engaging. Result panel narrows on the post-auto-walk effective slug,
not the URL slug. A one-time inline tooltip ("Diese Schritte ergeben sich
aus Ihrer Akte") surfaces when ≥2 rows render prefilled — dismissal flag
persists in localStorage.
Narrowing is purely additive: an Akte without a fristenrechner code
(11/11 live projects pre-Slice-5 were NULL) degrades to today's
forum-only behaviour. Slice 3 (mobile polish + search relocation) follows.
Refs: docs/design-determinator-row-cascade-2026-05-13.md §10 Slice 2 + §4 + §5.
55 lines
1.8 KiB
Go
55 lines
1.8 KiB
Go
package services
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestMapLitigationToFristenrechner(t *testing.T) {
|
|
type tc struct {
|
|
litigation, jurisdiction string
|
|
wantCode string
|
|
wantFlags []string
|
|
wantOK bool
|
|
}
|
|
cases := []tc{
|
|
// Unambiguous UPC fold-ins.
|
|
{"INF", "UPC", "UPC_INF", nil, true},
|
|
{"REV", "UPC", "UPC_REV", nil, true},
|
|
{"APP", "UPC", "UPC_APP", nil, true},
|
|
{"APM", "UPC", "UPC_PI", nil, true},
|
|
// CCR + UPC = UPC_INF with the with_ccr flag.
|
|
{"CCR", "UPC", "UPC_INF", []string{"with_ccr"}, true},
|
|
// AMD + UPC = UPC_INF with the with_amend flag.
|
|
{"AMD", "UPC", "UPC_INF", []string{"with_amend"}, true},
|
|
// DE first-instance / Nichtigkeit mappings.
|
|
{"INF", "DE", "DE_INF", nil, true},
|
|
{"REV", "DE", "DE_NULL", nil, true},
|
|
{"CCR", "DE", "DE_NULL", nil, true},
|
|
// EPA opposition.
|
|
{"OPP", "EPA", "EPA_OPP", nil, true},
|
|
// Ambiguous: APP+DE has both OLG and BGH analogues; project
|
|
// model can't disambiguate, so degrade.
|
|
{"APP", "DE", "", nil, false},
|
|
// No analogue: ZPO_CIVIL → nothing in fristenrechner.
|
|
{"ZPO_CIVIL", "DE", "", nil, false},
|
|
// AMD only fires on UPC; DE has no analogue.
|
|
{"AMD", "DE", "", nil, false},
|
|
// APM only fires on UPC.
|
|
{"APM", "EPA", "", nil, false},
|
|
// Unknown codes / jurisdictions → ok=false.
|
|
{"XXX", "UPC", "", nil, false},
|
|
{"INF", "ZZZ", "", nil, false},
|
|
{"", "", "", nil, false},
|
|
}
|
|
for _, c := range cases {
|
|
gotCode, gotFlags, gotOK := MapLitigationToFristenrechner(c.litigation, c.jurisdiction)
|
|
if gotCode != c.wantCode || gotOK != c.wantOK || !reflect.DeepEqual(gotFlags, c.wantFlags) {
|
|
t.Errorf("MapLitigationToFristenrechner(%q, %q) = (%q, %v, %v); want (%q, %v, %v)",
|
|
c.litigation, c.jurisdiction,
|
|
gotCode, gotFlags, gotOK,
|
|
c.wantCode, c.wantFlags, c.wantOK)
|
|
}
|
|
}
|
|
}
|