* fix(bookkeeping): let a backfilled first räkenskapsår start mid-month (#2237) POST /api/bookkeeping/fiscal-periods decided "first period" as "no period exists at all", so a company that imported 2024+ from Fortnox and then created its actual first year by hand (2022-07-22, the registration date) was refused with the 1st-of-month error, while the DB trigger enforce_first_of_month_for_subsequent_periods would have accepted the row. The route now mirrors the trigger: first = no existing period starts earlier. The 1st-of-month rule (BFL 3 kap. 1 §) keeps binding subsequent years, and its message now says which years it binds and why instead of only refusing. Tests: prepend with a mid-month start passes; a mid-month start for a non-earliest period is still a 400 that names the rule. Closes #2237 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VnConrmMCxJRQ5kfiPPWyy * chore: carry the DECISIONS.md line for this PR in #2247 instead (append-only log conflicts on every merge) --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
Jakob Wennberg
parent
d69de86b71
commit
cc18e9d530
@@ -49,13 +49,15 @@ describe('validatePeriodDuration', () => {
|
||||
})
|
||||
|
||||
it('returns error when start is not 1st of month (default)', () => {
|
||||
expect(validatePeriodDuration('2025-01-15', '2025-12-31')).toBe(
|
||||
'Period start must be the 1st of a month'
|
||||
)
|
||||
const result = validatePeriodDuration('2025-01-15', '2025-12-31')
|
||||
expect(result).toContain('Period start must be the 1st of a month')
|
||||
// Says what IS allowed and why, not only "no" (issue #2237).
|
||||
expect(result).toContain('first fiscal year may start mid-month')
|
||||
expect(result).toContain('BFL 3 kap.')
|
||||
})
|
||||
|
||||
it('returns error when start is not 1st of month (isFirstPeriod: false)', () => {
|
||||
expect(validatePeriodDuration('2025-03-25', '2025-12-31', { isFirstPeriod: false })).toBe(
|
||||
expect(validatePeriodDuration('2025-03-25', '2025-12-31', { isFirstPeriod: false })).toContain(
|
||||
'Period start must be the 1st of a month'
|
||||
)
|
||||
})
|
||||
|
||||
@@ -47,9 +47,11 @@ export function validatePeriodDuration(start: string, end: string, options?: Val
|
||||
return 'Period end must be after period start'
|
||||
}
|
||||
|
||||
// start must be 1st of month: unless this is the first fiscal period (BFL 3 kap.)
|
||||
// start must be 1st of month: unless this is the first fiscal period (BFL 3
|
||||
// kap. 1 § for subsequent years, 3 kap. 3 § for the first). Say why and what
|
||||
// is allowed, not only "no" (issue #2237).
|
||||
if (startParts.day !== 1 && !options?.isFirstPeriod) {
|
||||
return 'Period start must be the 1st of a month'
|
||||
return "Period start must be the 1st of a month: only the company's first fiscal year may start mid-month (BFL 3 kap. 1 and 3 §§)"
|
||||
}
|
||||
|
||||
// end must be last day of month
|
||||
|
||||
Reference in New Issue
Block a user