The Transaktioner inbox lists unbooked skattekonto rows next to unbooked bank rows, but the sidebar badge and the Hem "Att göra" list counted bank rows only, so a migrated tax account waited in the inbox unseen. - lib/worklist: new category book_skattekonto with the inbox's own predicate (status = 'booked', no verifikat, not ignored); aggregate includes it in counts and total. - Hem: a "Bokföra skattekontohändelser" row under Bokför, deep-linking to /transactions?source=skatteverket. - Sidebar badge hook: the same third head-count query, summed into the /transactions badge. - DashboardNav subscribes to skattekonto_transactions realtime changes; migration adds the table to the supabase_realtime publication so a booked or ignored row drops the badge without a manual refresh. Closes #2180 Claude-Session: https://claude.ai/code/session_01QPQLwHNEiQfiCNLSMzXMiQ 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
Jakob Wennberg
Claude Fable 5.1
parent
aeff998b90
commit
1e91c126ff
@@ -3,6 +3,7 @@ import type { SupabaseClient } from '@supabase/supabase-js'
|
||||
|
||||
vi.mock('../categories', () => ({
|
||||
countUnbookedTransactions: vi.fn().mockResolvedValue(4),
|
||||
countUnbookedSkattekontoRows: vi.fn().mockResolvedValue(7),
|
||||
countInboxDocuments: vi.fn().mockResolvedValue(6),
|
||||
countSuggestedMatches: vi.fn().mockResolvedValue(2),
|
||||
countSupplierInvoicesAwaitingApproval: vi.fn().mockResolvedValue(1),
|
||||
@@ -26,6 +27,7 @@ describe('getWorklistCounts', () => {
|
||||
const { counts } = await getWorklistCounts(supabase, 'company-1')
|
||||
expect(counts).toEqual({
|
||||
book_transaction: 4,
|
||||
book_skattekonto: 7,
|
||||
inbox_document: 6,
|
||||
suggested_match: 2,
|
||||
supplier_invoice_approval: 1,
|
||||
@@ -49,7 +51,7 @@ describe('getWorklistCounts', () => {
|
||||
|
||||
it('excludes suggested_match from the total (subset of book_transaction)', async () => {
|
||||
const { total } = await getWorklistCounts(supabase, 'company-1')
|
||||
// 4 + 6 + 1 + 3 + 5 + 1 + 2 + 1, without the 2 suggested matches.
|
||||
expect(total).toBe(23)
|
||||
// 4 + 7 + 6 + 1 + 3 + 5 + 1 + 2 + 1, without the 2 suggested matches.
|
||||
expect(total).toBe(30)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
countReconciliationDue,
|
||||
countSuggestedMatches,
|
||||
countSupplierInvoicesAwaitingApproval,
|
||||
countUnbookedSkattekontoRows,
|
||||
countUnbookedTransactions,
|
||||
countVerifikatMissingDocument,
|
||||
listSuggestedMatches,
|
||||
@@ -40,6 +41,25 @@ describe('countUnbookedTransactions', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('countUnbookedSkattekontoRows', () => {
|
||||
it('counts only settled, unbooked, non-ignored skattekonto rows', async () => {
|
||||
enqueue({ count: 3 })
|
||||
await expect(countUnbookedSkattekontoRows(supabase, COMPANY)).resolves.toBe(3)
|
||||
expect(mockSupabase.from).toHaveBeenCalledWith('skattekonto_transactions')
|
||||
// Same predicate as the Transaktioner inbox: Skatteverket status 'booked'
|
||||
// (upcoming charges have nothing to book), no verifikat, not ignored.
|
||||
const eqCalls = findCalls('skattekonto_transactions', 'eq')
|
||||
expect(eqCalls).toContainEqual(['status', 'booked'])
|
||||
expect(eqCalls).toContainEqual(['is_ignored', false])
|
||||
expect(findCall('skattekonto_transactions', 'is')).toEqual(['journal_entry_id', null])
|
||||
})
|
||||
|
||||
it('soft-fails to 0 on query error', async () => {
|
||||
enqueue({ error: { message: 'boom' } })
|
||||
await expect(countUnbookedSkattekontoRows(supabase, COMPANY)).resolves.toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('countInboxDocuments', () => {
|
||||
it('counts only items whose document is still unlinked', async () => {
|
||||
enqueue({
|
||||
|
||||
Reference in New Issue
Block a user