* fix(bookkeeping): harden correction account changes

* feat(tax): enhance tax deadline generation with new settings and filing methods

- Added new company settings: tax_turnover_over_40m, vat_has_eu_trade, vat_filing_method, periodisk_sammanstallning_enabled, and periodisk_sammanstallning_filing_method.
- Updated deadline generation logic to accommodate new settings affecting VAT and employer declaration deadlines.
- Implemented tests for new functionality, ensuring that completed obligations are preserved and not replaced by new pending rows.
- Introduced a cron job to backfill missing tax deadlines for companies with settings but no upcoming deadlines.
- Updated API routes for generating tax deadlines and handling cron jobs.
- Modified database schema to include new columns for tax filing profiles and constraints for filing methods.

* fix(invoices): record credit note reconciliation guard

* fix(tax): correct automatic deadline settings

* fix(tax): key AGI deadline to VAT taxable base and add storforetag payment deadline

The 26th filing day for the skattedeklaration (AGI and VAT together) hinges
on one statutory measure, a VAT taxable base above SEK 40 million (SFL 26
kap.), not a separate employer turnover. Drop employer_turnover_over_40m and
derive the AGI schedule from vat_registered plus vat_taxable_base_over_40m,
so a non-VAT-reporting employer is never shown the 26th when its binding
date is the 12th.

Also:
- add a skatteinbetalning deadline row (12th, 17 January) for storforetag,
  whose deducted tax and employer contributions are due before the 26th
  filing date
- normalize legally incoherent over-40m flag combinations to the earlier
  small-company schedule in a follow-up migration
- replace hardcoded 27 December dates with the banking-day adjustment
- extend the 40m help text to cover the SKV-decided early filing election
  and the payment-still-on-the-12th rule
- document the regeneration race repaired by the daily backfill cron

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(migrations): add AGI and VAT filing logic with employer column removal

* feat(settings): implement VAT registration logic and update related flags; enhance deadline handling

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-07-17 00:52:57 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 1443235cec
commit a5e37d3510
32 changed files with 1978 additions and 259 deletions
+154 -7
View File
@@ -19,14 +19,21 @@ vi.mock('@/lib/auth/require-write', () => ({
requireWritePermission: (...args: unknown[]) => requireWriteMock(...args),
}))
vi.mock('@/lib/tax/deadline-generator', () => ({
didTaxFieldsChange: vi.fn().mockReturnValue(false),
regenerateTaxDeadlinesForUser: vi.fn().mockResolvedValue(undefined),
shouldRegenerateTaxDeadlines: vi.fn(
(changed: boolean, count: number) => changed || count === 0,
),
const deadlineMocks = vi.hoisted(() => ({
regenerate: vi.fn().mockResolvedValue(undefined),
}))
// Mock only the function that writes to the database. The field detector,
// settings normalizer, and regeneration predicate stay real so these tests
// fail if a new tax-relevant field stops triggering regeneration.
vi.mock('@/lib/tax/deadline-generator', async (importOriginal) => {
const actual = await importOriginal<typeof import('@/lib/tax/deadline-generator')>()
return {
...actual,
regenerateTaxDeadlinesForUser: deadlineMocks.regenerate,
}
})
import { PUT } from '../route'
import { regenerateTaxDeadlinesForUser } from '@/lib/tax/deadline-generator'
@@ -87,6 +94,37 @@ describe('PUT /api/settings', () => {
expect(status).toBe(200)
expect(body.data.company_name).toBe('New Name')
expect(deadlineMocks.regenerate).not.toHaveBeenCalled()
})
it('regenerates deadlines when unchanged tax settings are saved', async () => {
const settings = {
company_id: 'company-1',
entity_type: 'aktiebolag',
moms_period: 'monthly',
f_skatt: true,
vat_registered: false,
pays_salaries: false,
fiscal_year_start_month: 1,
onboarding_complete: true,
}
enqueueMany([
{ data: settings },
{ data: { id: 's1', ...settings } },
])
const request = createMockRequest('/api/settings', {
method: 'PUT',
body: { f_skatt: true, vat_registered: false },
})
const response = await PUT(request, { params: Promise.resolve({}) })
expect(response.status).toBe(200)
expect(deadlineMocks.regenerate).toHaveBeenCalledWith(
supabase,
'company-1',
expect.objectContaining({ entity_type: 'aktiebolag', f_skatt: true }),
)
})
it('updates all three reminder thresholds', async () => {
@@ -149,9 +187,11 @@ describe('PUT /api/settings', () => {
{ data: null, count: 0 }, // no system deadlines -> self-heal generation
])
// A save with NO tax-relevant field: only the zero-count self-heal path
// can trigger regeneration here.
const request = createMockRequest('/api/settings', {
method: 'PUT',
body: { f_skatt: true },
body: { company_name: 'Self Heal AB' },
})
const response = await PUT(request, { params: Promise.resolve({}) })
const { status } = await parseJsonResponse(response)
@@ -160,6 +200,65 @@ describe('PUT /api/settings', () => {
expect(vi.mocked(regenerateTaxDeadlinesForUser)).toHaveBeenCalledOnce()
})
it('clears VAT-dependent flags when VAT registration is turned off', async () => {
const settings = {
company_id: 'company-1',
entity_type: 'aktiebolag',
vat_registered: true,
vat_number: 'SE556012579001',
moms_period: 'quarterly',
vat_taxable_base_over_40m: false,
vat_has_eu_trade: true,
periodisk_sammanstallning_enabled: true,
onboarding_complete: true,
}
enqueueMany([
{ data: settings },
{
data: {
...settings,
id: 's1',
vat_registered: false,
vat_has_eu_trade: false,
periodisk_sammanstallning_enabled: false,
},
},
])
// Without the coercion this request 400s: the stored PS flag stays
// effective while registration is being switched off.
const request = createMockRequest('/api/settings', {
method: 'PUT',
body: { vat_registered: false },
})
const response = await PUT(request, { params: Promise.resolve({}) })
const { status } = await parseJsonResponse(response)
expect(status).toBe(200)
expect(deadlineMocks.regenerate).toHaveBeenCalledOnce()
})
it('still rejects explicitly enabling the EU sales list without EU trade', async () => {
enqueue({
data: {
entity_type: 'aktiebolag',
vat_registered: true,
vat_number: 'SE556012579001',
moms_period: 'quarterly',
vat_has_eu_trade: false,
onboarding_complete: true,
},
})
const request = createMockRequest('/api/settings', {
method: 'PUT',
body: { periodisk_sammanstallning_enabled: true },
})
const response = await PUT(request, { params: Promise.resolve({}) })
expect(response.status).toBe(400)
})
it('does not regenerate tax deadlines when the company already has some', async () => {
enqueueMany([
{ data: { entity_type: 'aktiebolag', onboarding_complete: true } }, // oldSettings
@@ -202,6 +301,54 @@ describe('PUT /api/settings', () => {
expect(supabase.from).toHaveBeenCalledTimes(1)
})
it('rejects quarterly VAT when the VAT taxable base is above SEK 40 million', async () => {
enqueue({
data: {
entity_type: 'aktiebolag',
vat_registered: true,
vat_number: 'SE556012579001',
moms_period: 'quarterly',
vat_taxable_base_over_40m: false,
onboarding_complete: true,
},
})
const request = createMockRequest('/api/settings', {
method: 'PUT',
body: { vat_taxable_base_over_40m: true },
})
const response = await PUT(request, { params: Promise.resolve({}) })
expect(response.status).toBe(400)
expect(supabase.from).toHaveBeenCalledTimes(1)
})
it('allows EU-trade changes with quarterly VAT and regenerates deadlines', async () => {
const settings = {
company_id: 'company-1',
entity_type: 'aktiebolag',
vat_registered: true,
vat_number: 'SE556012579001',
moms_period: 'quarterly',
vat_taxable_base_over_40m: false,
vat_has_eu_trade: true,
onboarding_complete: true,
}
enqueueMany([
{ data: { ...settings, vat_has_eu_trade: false } },
{ data: settings },
])
const request = createMockRequest('/api/settings', {
method: 'PUT',
body: { vat_has_eu_trade: true },
})
const response = await PUT(request, { params: Promise.resolve({}) })
expect(response.status).toBe(200)
expect(deadlineMocks.regenerate).toHaveBeenCalledOnce()
})
it('returns 404 when the settings row does not exist', async () => {
enqueueMany([
{ data: { onboarding_complete: false } },
+61 -24
View File
@@ -1,6 +1,12 @@
import { NextResponse } from 'next/server'
import { withRouteContext } from '@/lib/api/with-route-context'
import { didTaxFieldsChange, regenerateTaxDeadlinesForUser, shouldRegenerateTaxDeadlines } from '@/lib/tax/deadline-generator'
import {
DEADLINE_SETTINGS_SELECT,
hasTaxRelevantFields,
regenerateTaxDeadlinesForUser,
shouldRegenerateTaxDeadlines,
toDeadlineSettings,
} from '@/lib/tax/deadline-generator'
import { validateBody } from '@/lib/api/validate'
import { UpdateSettingsSchema } from '@/lib/api/schemas'
@@ -36,11 +42,11 @@ export const GET = withRouteContext(
export const PUT = withRouteContext(
'settings.update',
async (request, { supabase, companyId }) => {
async (request, { supabase, companyId, log }) => {
// Fetch current settings to check for tax-relevant changes
const { data: oldSettings } = await supabase
.from('company_settings')
.select('entity_type, moms_period, f_skatt, vat_registered, vat_number, pays_salaries, fiscal_year_start_month, onboarding_complete, salary_vacation_year_basis, reminder_days_level_1, reminder_days_level_2, reminder_days_level_3')
.select(`${DEADLINE_SETTINGS_SELECT}, vat_number, onboarding_complete, salary_vacation_year_basis, reminder_days_level_1, reminder_days_level_2, reminder_days_level_3`)
.eq('company_id', companyId)
.single()
@@ -106,8 +112,23 @@ export const PUT = withRouteContext(
}
}
// Turning VAT registration off retires the VAT-dependent flags, and
// dropping EU trade retires the EU sales list: stale true values would
// otherwise block the save below or silently resurrect wrong deadlines
// when registration is re-enabled later. Same coherence rule as the
// 20260717070000 migration and the tax settings form.
if (body.vat_registered === false) {
body.vat_taxable_base_over_40m = false
body.vat_has_eu_trade = false
body.periodisk_sammanstallning_enabled = false
}
if (body.vat_has_eu_trade === false) {
body.periodisk_sammanstallning_enabled = false
}
// Validate: VAT-registered must have VAT number (ML 11 kap. 8§) and moms period (SFL 26 kap.)
const effectiveVatRegistered = body.vat_registered ?? oldSettings?.vat_registered
const effectiveMomsPeriod = body.moms_period ?? oldSettings?.moms_period
if (effectiveVatRegistered === true) {
const effectiveVatNumber = body.vat_number ?? oldSettings?.vat_number
if (!effectiveVatNumber) {
@@ -116,7 +137,6 @@ export const PUT = withRouteContext(
{ status: 400 }
)
}
const effectiveMomsPeriod = body.moms_period ?? oldSettings?.moms_period
if (!effectiveMomsPeriod) {
return NextResponse.json(
{ error: 'Momsperiod krävs när företaget är momsregistrerat (SFL 26 kap.)' },
@@ -125,6 +145,27 @@ export const PUT = withRouteContext(
}
}
const effectiveVatTaxableBaseOver40m =
body.vat_taxable_base_over_40m ?? oldSettings?.vat_taxable_base_over_40m ?? false
if (effectiveVatRegistered && effectiveVatTaxableBaseOver40m && effectiveMomsPeriod !== 'monthly') {
return NextResponse.json(
{ error: 'Företag med beskattningsunderlag över 40 miljoner kronor måste redovisa moms varje månad.' },
{ status: 400 },
)
}
const effectivePsEnabled =
body.periodisk_sammanstallning_enabled ??
oldSettings?.periodisk_sammanstallning_enabled ??
false
const effectiveEuTrade = body.vat_has_eu_trade ?? oldSettings?.vat_has_eu_trade ?? false
if (effectivePsEnabled && (!effectiveVatRegistered || !effectiveEuTrade)) {
return NextResponse.json(
{ error: 'Periodisk sammanställning kräver momsregistrering och EU-handel.' },
{ status: 400 },
)
}
const { data, error } = await supabase
.from('company_settings')
.update(body)
@@ -139,39 +180,35 @@ export const PUT = withRouteContext(
return NextResponse.json({ error: error.message }, { status: 500 })
}
// Regenerate tax deadlines when a tax-relevant field changed OR when the
// company has no system-generated deadlines yet. The latter is the common
// case: tax settings are filled at onboarding, so a later save with no
// tax-field change never triggered generation and the deadlines page stayed
// empty even though the settings were "filled in". Backfilling when the set
// is empty is safe: there is no existing progress/status to clobber.
const taxFieldsChanged = Boolean(oldSettings && didTaxFieldsChange(oldSettings, data))
// Regenerate when the save touches tax-relevant fields: the statutory
// dates are derived from them, and re-running also repairs rows created
// by older schedule logic or lost to an earlier generation failure. The
// generator preserves completed rows, so filing progress survives.
// Additionally self-heal when the company has no system deadlines at all:
// tax settings are filled at onboarding, so an unrelated later save may be
// the first chance to backfill an empty set.
const taxFieldsInBody = hasTaxRelevantFields(body)
let existingSystemDeadlineCount = 0
if (!taxFieldsChanged) {
if (!taxFieldsInBody) {
const { count, error: countError } = await supabase
.from('deadlines')
.select('id', { count: 'exact', head: true })
.eq('company_id', companyId)
.eq('source', 'system')
.eq('deadline_type', 'tax')
// Fail safe: on a count error, assume deadlines already exist so we do
// NOT delete+regenerate on a transient failure (regeneration would reset
// is_completed/status). A non-zero placeholder keeps the self-heal off.
// the status of pending rows). A non-zero placeholder keeps the
// self-heal off.
existingSystemDeadlineCount = countError ? 1 : (count ?? 0)
}
if (shouldRegenerateTaxDeadlines(taxFieldsChanged, existingSystemDeadlineCount)) {
if (shouldRegenerateTaxDeadlines(taxFieldsInBody, existingSystemDeadlineCount)) {
try {
await regenerateTaxDeadlinesForUser(supabase, companyId, {
entity_type: data.entity_type,
moms_period: data.moms_period,
f_skatt: data.f_skatt,
vat_registered: data.vat_registered,
pays_salaries: data.pays_salaries ?? false,
fiscal_year_start_month: data.fiscal_year_start_month,
})
console.log('Tax deadlines regenerated after settings change')
await regenerateTaxDeadlinesForUser(supabase, companyId, toDeadlineSettings(data))
log.info('tax deadlines regenerated after settings change')
} catch (err) {
console.error('Failed to regenerate tax deadlines:', err)
log.error('failed to regenerate tax deadlines', err as Error)
// Don't fail the settings update if deadline generation fails
}
}
@@ -0,0 +1,96 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { NextResponse } from 'next/server'
const mocks = vi.hoisted(() => ({
createClient: vi.fn(() => ({ kind: 'service-client' })),
annual: vi.fn(),
backfill: vi.fn(),
}))
vi.mock('@supabase/supabase-js', () => ({
createClient: mocks.createClient,
}))
vi.mock('@/lib/auth/cron', () => ({
verifyCronSecret: vi.fn(() => null),
}))
vi.mock('@/lib/tax/deadline-generator', () => ({
generateNewYearDeadlines: mocks.annual,
backfillMissingTaxDeadlines: mocks.backfill,
}))
import { verifyCronSecret } from '@/lib/auth/cron'
import { GET } from '../route'
const originalUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
const originalServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY
function cronRequest(): Request {
return new Request('http://localhost:3000/api/tax-deadlines/cron')
}
beforeEach(() => {
vi.clearAllMocks()
vi.useFakeTimers()
vi.setSystemTime(new Date('2026-07-16T00:00:00.000Z'))
process.env.NEXT_PUBLIC_SUPABASE_URL = 'https://example.supabase.co'
process.env.SUPABASE_SERVICE_ROLE_KEY = 'service-key'
mocks.annual.mockResolvedValue({ usersProcessed: 0, totalCreated: 0 })
mocks.backfill.mockResolvedValue({
companiesScanned: 10,
companiesRepaired: 2,
totalCreated: 24,
})
})
afterEach(() => {
vi.useRealTimers()
process.env.NEXT_PUBLIC_SUPABASE_URL = originalUrl
process.env.SUPABASE_SERVICE_ROLE_KEY = originalServiceKey
})
describe('GET /api/tax-deadlines/cron', () => {
it('repairs companies with missing deadlines on the daily run', async () => {
const response = await GET(cronRequest())
expect(response.status).toBe(200)
await expect(response.json()).resolves.toMatchObject({
success: true,
isAnnualRun: false,
companiesScanned: 10,
companiesRepaired: 2,
totalCreated: 24,
})
expect(mocks.backfill).toHaveBeenCalledOnce()
expect(mocks.annual).not.toHaveBeenCalled()
})
it('extends every company horizon before running recovery on January 2', async () => {
vi.setSystemTime(new Date('2027-01-02T00:00:00.000Z'))
mocks.annual.mockResolvedValue({ usersProcessed: 8, totalCreated: 80 })
const response = await GET(cronRequest())
const body = await response.json()
expect(body).toMatchObject({
isAnnualRun: true,
usersProcessed: 8,
totalCreated: 104,
})
expect(mocks.annual).toHaveBeenCalledOnce()
expect(mocks.backfill).toHaveBeenCalledOnce()
})
it('returns 401 without creating a database client when cron auth fails', async () => {
vi.mocked(verifyCronSecret).mockReturnValueOnce(
NextResponse.json({ error: 'Unauthorized' }, { status: 401 }),
)
const response = await GET(cronRequest())
expect(response.status).toBe(401)
expect(mocks.createClient).not.toHaveBeenCalled()
expect(mocks.backfill).not.toHaveBeenCalled()
})
})
+40 -8
View File
@@ -1,12 +1,14 @@
import { createClient } from '@supabase/supabase-js'
import { NextResponse } from 'next/server'
import { generateNewYearDeadlines } from '@/lib/tax/deadline-generator'
import {
backfillMissingTaxDeadlines,
generateNewYearDeadlines,
} from '@/lib/tax/deadline-generator'
import { withCronContext } from '@/lib/api/with-cron-context'
import { errorResponseFromCode } from '@/lib/errors/get-structured-error'
/**
* GET /api/tax-deadlines/cron: annual on January 2nd 00:00.
* Generates the next year's tax deadlines for every company.
* GET /api/tax-deadlines/cron: daily recovery plus annual horizon extension.
*/
export const GET = withCronContext('cron.tax_deadlines', async (_request, ctx) => {
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL
@@ -20,16 +22,46 @@ export const GET = withCronContext('cron.tax_deadlines', async (_request, ctx) =
}
const supabase = createClient(supabaseUrl, supabaseServiceKey)
const result = await generateNewYearDeadlines(supabase)
const now = new Date()
const isAnnualRun = now.getUTCMonth() === 0 && now.getUTCDate() === 2
// Each step logs its own failure before rethrowing so a partial failure
// names the failed step in the audit trail instead of surfacing as an
// anonymous cron error.
let annual = { usersProcessed: 0, totalCreated: 0 }
if (isAnnualRun) {
try {
annual = await generateNewYearDeadlines(supabase)
} catch (err) {
ctx.log.error('new-year deadline generation failed', err as Error)
throw err
}
}
let recovery
try {
recovery = await backfillMissingTaxDeadlines(supabase)
} catch (err) {
ctx.log.error('tax deadline backfill failed', err as Error)
throw err
}
const totalCreated = annual.totalCreated + recovery.totalCreated
ctx.log.info('tax deadlines cron summary', {
usersProcessed: result.usersProcessed,
totalCreated: result.totalCreated,
isAnnualRun,
usersProcessed: annual.usersProcessed,
companiesScanned: recovery.companiesScanned,
companiesRepaired: recovery.companiesRepaired,
totalCreated,
})
return NextResponse.json({
success: true,
usersProcessed: result.usersProcessed,
totalCreated: result.totalCreated,
isAnnualRun,
usersProcessed: annual.usersProcessed,
companiesScanned: recovery.companiesScanned,
companiesRepaired: recovery.companiesRepaired,
totalCreated,
})
})
@@ -0,0 +1,106 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { NextResponse } from 'next/server'
import { createMockRequest, createQueuedMockSupabase, parseJsonResponse } from '@/tests/helpers'
const { supabase, enqueue, reset } = createQueuedMockSupabase()
const mocks = vi.hoisted(() => ({
regenerate: vi.fn(),
}))
const requireAuthMock = vi.fn()
vi.mock('@/lib/auth/require-auth', () => ({
requireAuth: (...args: unknown[]) => requireAuthMock(...args),
}))
vi.mock('@/lib/company/context', () => ({
getActiveCompanyId: vi.fn().mockResolvedValue('company-1'),
requireCompanyId: vi.fn().mockResolvedValue('company-1'),
}))
const requireWriteMock = vi.fn()
vi.mock('@/lib/auth/require-write', () => ({
requireWritePermission: (...args: unknown[]) => requireWriteMock(...args),
}))
vi.mock('@/lib/tax/deadline-generator', () => ({
DEADLINE_SETTINGS_SELECT: 'company_id, entity_type',
regenerateTaxDeadlinesForUser: mocks.regenerate,
toDeadlineSettings: vi.fn((settings: Record<string, unknown>) => settings),
}))
import { POST } from '../route'
function request(): Request {
return createMockRequest('/api/tax-deadlines/generate', { method: 'POST' })
}
beforeEach(() => {
vi.clearAllMocks()
reset()
requireAuthMock.mockResolvedValue({ user: { id: 'user-1' }, supabase, error: null })
requireWriteMock.mockResolvedValue({ ok: true })
mocks.regenerate.mockResolvedValue({ created: 12, deleted: 0 })
})
describe('POST /api/tax-deadlines/generate', () => {
it('returns 401 when unauthenticated', async () => {
requireAuthMock.mockResolvedValue({
user: null,
supabase,
error: NextResponse.json({ error: 'Unauthorized' }, { status: 401 }),
})
const response = await POST(request(), { params: Promise.resolve({}) })
expect(response.status).toBe(401)
expect(mocks.regenerate).not.toHaveBeenCalled()
})
it('returns 403 without write permission', async () => {
requireWriteMock.mockResolvedValue({
ok: false,
response: NextResponse.json({ error: 'Forbidden' }, { status: 403 }),
})
const response = await POST(request(), { params: Promise.resolve({}) })
expect(response.status).toBe(403)
expect(mocks.regenerate).not.toHaveBeenCalled()
})
it('returns 404 when company settings are missing', async () => {
enqueue({ data: null, error: { code: 'PGRST116', message: 'No rows returned' } })
const response = await POST(request(), { params: Promise.resolve({}) })
expect(response.status).toBe(404)
})
it('regenerates the current company deadlines', async () => {
enqueue({ data: { company_id: 'company-1', entity_type: 'aktiebolag' } })
const response = await POST(request(), { params: Promise.resolve({}) })
const { status, body } = await parseJsonResponse<{
success: boolean
created: number
deleted: number
}>(response)
expect(status).toBe(200)
expect(body).toEqual({ success: true, created: 12, deleted: 0 })
expect(mocks.regenerate).toHaveBeenCalledWith(
supabase,
'company-1',
expect.objectContaining({ entity_type: 'aktiebolag' }),
)
})
it('returns 500 when generation fails', async () => {
enqueue({ data: { company_id: 'company-1', entity_type: 'aktiebolag' } })
mocks.regenerate.mockRejectedValueOnce(new Error('insert failed'))
const response = await POST(request(), { params: Promise.resolve({}) })
expect(response.status).toBe(500)
})
})
+11 -10
View File
@@ -1,6 +1,10 @@
import { NextResponse } from 'next/server'
import { withRouteContext } from '@/lib/api/with-route-context'
import { regenerateTaxDeadlinesForUser } from '@/lib/tax/deadline-generator'
import {
DEADLINE_SETTINGS_SELECT,
regenerateTaxDeadlinesForUser,
toDeadlineSettings,
} from '@/lib/tax/deadline-generator'
/**
* POST /api/tax-deadlines/generate
@@ -14,7 +18,7 @@ export const POST = withRouteContext(
// Fetch company settings
const { data: settings, error: settingsError } = await supabase
.from('company_settings')
.select('entity_type, moms_period, f_skatt, vat_registered, pays_salaries, fiscal_year_start_month')
.select(DEADLINE_SETTINGS_SELECT)
.eq('company_id', companyId)
.single()
@@ -26,14 +30,11 @@ export const POST = withRouteContext(
}
try {
const result = await regenerateTaxDeadlinesForUser(supabase, companyId, {
entity_type: settings.entity_type,
moms_period: settings.moms_period,
f_skatt: settings.f_skatt,
vat_registered: settings.vat_registered,
pays_salaries: settings.pays_salaries ?? false,
fiscal_year_start_month: settings.fiscal_year_start_month,
})
const result = await regenerateTaxDeadlinesForUser(
supabase,
companyId,
toDeadlineSettings(settings),
)
return NextResponse.json({
success: true,