Workstream B Go sweep — matches mig 098. Every place the deadline-rules service reads/writes the per-rule identifier now uses the new column name and the new struct field. Distinct from rule_code (legal citation) and from proceeding_types.code (the proceeding's 3-segment code). Touch points: - models.DeadlineRule.Code → SubmissionCode (db + json tags renamed in lockstep — JSON contract `submission_code` is the new shape). - deadline_rule_service: ruleColumns SELECT list updated. - rule_editor_service: CreateRuleInput.Code → SubmissionCode (json tag too), INSERT + CloneAsDraft SELECT updated. - projection_service: lookupRuleByCode → lookupRuleBySubmissionCode (SQL WHERE clause + error message); every r.Code / parent.Code / rule.Code / first.Code / src.rule.Code read renamed. - fristenrechner: r.Code / prev.Code / rule.Code reads renamed in Calculate (parent-anchor + override-key + computed-by-code map) and in CalculateRule's LocalCode emission; the proceeding-code+submission- code resolver query uses `submission_code = $2`. - event_trigger_service / deadline_calculator: r.Code reads renamed. UIDeadline.Code (the calculator's wire response) is unchanged — that field is a separate API contract pointing at the same value; renaming it would force every frontend deadline-renderer through a contract break that isn't part of this workstream. Test fixtures updated to the new SubmissionCode field name; live-DB tests updated to the post-mig-098 prefixed values (`inf.sod` → `upc.inf.cfi.sod` etc.). New submission_codes_shape_test asserts every active+published row matches the 4+-segment proceeding-prefixed shape (sibling of TestProceedingCodeShape; mirrors mig 098 §6.1). go build ./... clean. go test ./internal/... green.
90 lines
2.8 KiB
Go
90 lines
2.8 KiB
Go
package services
|
|
|
|
import (
|
|
"time"
|
|
|
|
"mgit.msbls.de/m/paliad/internal/models"
|
|
)
|
|
|
|
// CalculatedDeadline is one computed deadline (rule + due date + adjustment info).
|
|
type CalculatedDeadline struct {
|
|
RuleCode string `json:"rule_code"`
|
|
RuleID string `json:"rule_id"`
|
|
Title string `json:"title"`
|
|
DueDate string `json:"due_date"` // YYYY-MM-DD, after holiday/weekend adjust
|
|
OriginalDueDate string `json:"original_due_date"` // YYYY-MM-DD, before adjust
|
|
WasAdjusted bool `json:"was_adjusted"`
|
|
}
|
|
|
|
// DeadlineCalculator turns rules into dates given a trigger event.
|
|
type DeadlineCalculator struct {
|
|
holidays *HolidayService
|
|
}
|
|
|
|
// NewDeadlineCalculator wires the calculator to the holiday service.
|
|
func NewDeadlineCalculator(holidays *HolidayService) *DeadlineCalculator {
|
|
return &DeadlineCalculator{holidays: holidays}
|
|
}
|
|
|
|
// CalculateEndDate applies a single rule's duration + timing to the event date,
|
|
// then bumps forward off non-working days for the given (country, regime).
|
|
// Returns (adjusted, original, didAdjust).
|
|
func (c *DeadlineCalculator) CalculateEndDate(eventDate time.Time, rule models.DeadlineRule, country, regime string) (time.Time, time.Time, bool) {
|
|
endDate := eventDate
|
|
|
|
timing := "after"
|
|
if rule.Timing != nil {
|
|
timing = *rule.Timing
|
|
}
|
|
|
|
sign := 1
|
|
if timing == "before" {
|
|
sign = -1
|
|
}
|
|
|
|
switch rule.DurationUnit {
|
|
case "days":
|
|
endDate = endDate.AddDate(0, 0, sign*rule.DurationValue)
|
|
case "weeks":
|
|
endDate = endDate.AddDate(0, 0, sign*rule.DurationValue*7)
|
|
case "months":
|
|
endDate = endDate.AddDate(0, sign*rule.DurationValue, 0)
|
|
}
|
|
|
|
original := endDate
|
|
adjusted, _, wasAdjusted := c.holidays.AdjustForNonWorkingDays(endDate, country, regime)
|
|
return adjusted, original, wasAdjusted
|
|
}
|
|
|
|
// CalculateFromRules calculates deadlines for a slice of rules using the
|
|
// given (country, regime) for non-working-day adjustment. Rules with
|
|
// duration == 0 (court-set hearings, decisions) return the event date itself.
|
|
func (c *DeadlineCalculator) CalculateFromRules(eventDate time.Time, rules []models.DeadlineRule, country, regime string) []CalculatedDeadline {
|
|
results := make([]CalculatedDeadline, 0, len(rules))
|
|
for _, r := range rules {
|
|
var adjusted, original time.Time
|
|
var wasAdjusted bool
|
|
|
|
if r.DurationValue > 0 {
|
|
adjusted, original, wasAdjusted = c.CalculateEndDate(eventDate, r, country, regime)
|
|
} else {
|
|
adjusted, original = eventDate, eventDate
|
|
}
|
|
|
|
code := ""
|
|
if r.SubmissionCode != nil {
|
|
code = *r.SubmissionCode
|
|
}
|
|
|
|
results = append(results, CalculatedDeadline{
|
|
RuleCode: code,
|
|
RuleID: r.ID.String(),
|
|
Title: r.Name,
|
|
DueDate: adjusted.Format("2006-01-02"),
|
|
OriginalDueDate: original.Format("2006-01-02"),
|
|
WasAdjusted: wasAdjusted,
|
|
})
|
|
}
|
|
return results
|
|
}
|