Files
accounted/lib/company/first-year-defaults.ts
T
Jakob WennbergandClaude Fable 5 f9ef8913ae refactor(onboarding): extract first-year defaults + shared TIC lookup client (journey PR A) (#1141)
First of four PRs replacing the onboarding wizard with the journey flow
(dev_docs/onboarding_migration_plan.md, local). No UI change.

- Move deriveFirstYearDefaults + parseStartMonthDay out of
  WelcomeOnboarding into lib/company/first-year-defaults.ts and unit-test
  them (11-vs-13-months boundary, UTC month seeding, malformed input).
- Add the missing computeFiscalPeriod unit tests (calendar year, brutet
  ar, first year short/extended, EF calendar-year rule, period names,
  BFL 3 kap. 6-18 month window errors).
- New shared fetchCompanyLookup() client: the single client path to the
  Lens-backed /lookup, typed outcomes (found / not_found / disabled /
  error / aborted), never throws. Fixes the 403/404 conflation: the
  dispatcher's 404 ("Extension not found") and feature-flag 503
  (EXTENSION_DISABLED) now degrade silently instead of rendering as
  "company not found"; only the TIC handler's own 404 does.
- Step2CompanyDetails consumes the helper; identical UX otherwise.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-24 13:29:56 +02:00

51 lines
1.9 KiB
TypeScript

/**
* First-fiscal-year defaults derived from TIC lookup data.
*
* Extracted from WelcomeOnboarding so both the wizard and the journey
* onboarding can share them (dev_docs/onboarding_migration_plan.md, PR A).
*/
/**
* Parse TIC v2's `startMonthDay` ("MM-DD": e.g. "07-01") into a month
* number 1-12. Returns null on missing / malformed input so the caller
* can fall through to the manual picker default.
*/
export function parseStartMonthDay(value: string | null | undefined): number | null {
if (!value) return null
const match = /^(\d{1,2})-\d{1,2}$/.exec(value)
if (!match) return null
const month = Number(match[1])
if (!Number.isInteger(month) || month < 1 || month > 12) return null
return month
}
/**
* Derive the first-year defaults from TIC's `registrationDate`.
* A company is treated as "first year" when registered less than 12 months
* ago: fits BFL's 6-18 month opening-period window comfortably. Returns
* both the toggle state and a seeded `first_year_start` (always the 1st of
* the registration month, the format the date inputs expect).
*
* `now` exists for tests; production callers omit it.
*/
export function deriveFirstYearDefaults(
registrationDate: number | null | undefined,
now: number = Date.now(),
): {
isFirstFiscalYear: boolean
firstYearStart: string | undefined
} {
if (!registrationDate || !Number.isFinite(registrationDate)) {
return { isFirstFiscalYear: false, firstYearStart: undefined }
}
const regDate = new Date(registrationDate)
if (Number.isNaN(regDate.getTime())) {
return { isFirstFiscalYear: false, firstYearStart: undefined }
}
const monthsAgo = (now - regDate.getTime()) / (1000 * 60 * 60 * 24 * 30.44)
if (monthsAgo >= 12) return { isFirstFiscalYear: false, firstYearStart: undefined }
const year = regDate.getUTCFullYear()
const month = String(regDate.getUTCMonth() + 1).padStart(2, '0')
return { isFirstFiscalYear: true, firstYearStart: `${year}-${month}-01` }
}