fix(invoices): honour defer_invoice_booking on MCP, REST v1 and inbox convert (#1921)
The #967 "Registrera men bokför inte" setting was only respected by the dashboard routes. Six other paths decided whether to post the issue-time verifikat with `accounting_method === 'accrual'` alone, so a company that had switched booking to the explicit Bokför step still got vouchers posted at issue through MCP, the REST v1 API and the invoice-inbox convert route: - lib/pending-operations/commit.ts: send_invoice, mark_invoice_sent, create_supplier_invoice_from_inbox executors - app/api/v1/.../invoices/[id]/send and mark-sent (commit + dry-run preview) - app/api/v1/.../supplier-invoices POST - extensions/general/invoice-inbox convert All of them now call booksInvoicesOnIssue() from lib/bookkeeping/booking-mode, the helper the dashboard already uses, and select defer_invoice_booking where the settings projection did not include it. Behaviour for accrual companies without the flag and for kontantmetoden companies is unchanged. Tests: one deferred-company case per door (8 new), verified to fail without the fix. skills/accounted-api regenerated for the changed v1 descriptions. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Fable 5
parent
8ddc77fdfd
commit
f08fc2c274
@@ -607,3 +607,35 @@ describe('DELETE /items/:id', () => {
|
||||
expect(body.data.deleted).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('POST /items/:id/convert honours defer_invoice_booking (#967)', () => {
|
||||
const route = findRoute('POST', '/items/:id/convert')
|
||||
|
||||
it('registers WITHOUT the registration JE when the company defers booking', async () => {
|
||||
const { createSupplierInvoiceRegistrationEntry } = await import('@/lib/bookkeeping/supplier-invoice-entries')
|
||||
vi.mocked(createSupplierInvoiceRegistrationEntry).mockClear()
|
||||
|
||||
const { supabase, enqueue } = createQueuedMockSupabase()
|
||||
enqueue({ data: makeInvoiceInboxItem({ status: 'received' }) })
|
||||
enqueue({ data: makeSupplier({ id: SUPPLIER_UUID }) })
|
||||
enqueue({ data: 42 })
|
||||
enqueue({ data: { id: 'invoice-1', status: 'registered' } })
|
||||
enqueue({ data: null, error: null })
|
||||
enqueue({ data: makeCompanySettings({ accounting_method: 'accrual', defer_invoice_booking: true }) })
|
||||
enqueue({ data: null, error: null })
|
||||
enqueue({ data: null, error: null })
|
||||
|
||||
const ctx = buildCtx(supabase)
|
||||
const request = createMockRequest('/items/item-1/convert', {
|
||||
method: 'POST',
|
||||
body: VALID_CONVERT_BODY,
|
||||
searchParams: { _id: 'item-1' },
|
||||
})
|
||||
const res = await route.handler(request, ctx)
|
||||
const { status, body } = await parseJsonResponse<{ data: { registration_journal_entry_id: string | null } }>(res)
|
||||
|
||||
expect(status).toBe(200)
|
||||
expect(body.data.registration_journal_entry_id).toBeNull()
|
||||
expect(createSupplierInvoiceRegistrationEntry).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -44,6 +44,7 @@ import {
|
||||
applyDomainStatusFromWebhook,
|
||||
} from './lib/custom-domains'
|
||||
import { createSupplierInvoiceRegistrationEntry } from '@/lib/bookkeeping/supplier-invoice-entries'
|
||||
import { booksInvoicesOnIssue } from '@/lib/bookkeeping/booking-mode'
|
||||
import { createSchedulesForSupplierInvoice } from '@/lib/bookkeeping/accruals/from-invoices'
|
||||
import { suggestBalanceAccount } from '@/lib/bookkeeping/accruals/account-suggestions'
|
||||
import { isSlpPensionAccount } from '@/lib/bookkeeping/slp-lines'
|
||||
@@ -2151,14 +2152,15 @@ export const invoiceInboxExtension: Extension = {
|
||||
|
||||
const { data: settings } = await ctx.supabase
|
||||
.from('company_settings')
|
||||
.select('accounting_method')
|
||||
.select('accounting_method, defer_invoice_booking')
|
||||
.eq('company_id', ctx.companyId)
|
||||
.single()
|
||||
|
||||
const accountingMethod = settings?.accounting_method || 'accrual'
|
||||
let registrationJournalEntryId: string | null = null
|
||||
|
||||
if (accountingMethod === 'accrual') {
|
||||
// #967: deferred companies register WITHOUT booking (same gate as
|
||||
// POST /api/supplier-invoices); ekonomi books later via Bokför.
|
||||
if (booksInvoicesOnIssue(settings)) {
|
||||
try {
|
||||
const journalEntry = await createSupplierInvoiceRegistrationEntry(
|
||||
ctx.supabase,
|
||||
|
||||
Reference in New Issue
Block a user