Fix/supp ag fb (#1023)

* fix: prevent credit notes from entering payment flow

* fix: persist and display customer personal numbers

* feat: configure automatic invoice reminder days

* fix: issue credit notes through send flow

* chore: add repository agent guidance

* feat(mcp): route tools across user companies

* fix(articles): delete unused register entries

* feat(invoices): improve issued invoice actions

* feat(supplier-invoices): retain uploaded source documents

* docs: record implementation decisions

* feat: enhance customer personal number handling and validation

- Updated CustomerForm to allow personal numbers in the format of "********-1234" for individual customers.
- Added validation to ensure personal numbers are only accepted for individual customers in CreateCustomerSchema.
- Implemented masking and encryption for personal numbers to enhance data protection.
- Introduced new utility functions for masking and encrypting personal numbers.
- Added database migration to enforce unique constraints on credit note relationships and prevent duplicate entries.
- Enhanced error handling and logging for credit note issuance and invoice processing.
- Updated tests to cover new credit note creation guards and personal number handling.

* test: enhance list companies test with supabase query mocks
This commit is contained in:
Mattsson
2026-07-15 15:53:15 +02:00
committed by GitHub
parent a558c75678
commit 072aedeaf9
116 changed files with 5708 additions and 669 deletions
+6 -3
View File
@@ -7,6 +7,7 @@ import { validateVatNumber } from '@/lib/vat/vies-client'
import { withRouteContext } from '@/lib/api/with-route-context'
import { errorResponse, errorResponseFromCode } from '@/lib/errors/get-structured-error'
import type { Customer } from '@/types'
import { encryptCustomerPersonalNumber, maskCustomerRow } from '@/lib/customers/protect-personal-number'
ensureInitialized()
@@ -26,7 +27,7 @@ export const GET = withRouteContext(
return errorResponse(error, log, { requestId })
}
return NextResponse.json({ data })
return NextResponse.json({ data: (data ?? []).map(maskCustomerRow) })
},
)
@@ -59,6 +60,7 @@ export const POST = withRouteContext(
country: body.country || 'Sweden',
org_number: body.org_number,
vat_number: body.vat_number,
personal_number: encryptCustomerPersonalNumber(body.personal_number),
language: body.language || 'sv',
default_payment_terms: body.default_payment_terms || 30,
notes: body.notes,
@@ -104,12 +106,13 @@ export const POST = withRouteContext(
}
}
const safeCustomer = maskCustomerRow(data)
await eventBus.emit({
type: 'customer.created',
payload: { customer: data as Customer, companyId: companyId!, userId: user.id },
payload: { customer: safeCustomer as Customer, companyId: companyId!, userId: user.id },
})
return NextResponse.json({ data })
return NextResponse.json({ data: safeCustomer })
},
{ requireWrite: true },
)