@@ -1996,6 +1996,23 @@ describe('CreateAccountSchema', () => {
|
||||
})
|
||||
expect(result.success).toBe(false)
|
||||
})
|
||||
|
||||
it('rejects a VAT treatment that does not apply to the account class', () => {
|
||||
expect(CreateAccountSchema.safeParse({
|
||||
account_number: '5010',
|
||||
account_name: 'Consulting costs',
|
||||
account_type: 'expense',
|
||||
normal_balance: 'debit',
|
||||
default_vat_treatment: 'standard_25',
|
||||
}).success).toBe(false)
|
||||
expect(CreateAccountSchema.safeParse({
|
||||
account_number: '5010',
|
||||
account_name: 'EU services',
|
||||
account_type: 'expense',
|
||||
normal_balance: 'debit',
|
||||
default_vat_treatment: 'reverse_charge_eu_services',
|
||||
}).success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
@@ -2305,6 +2322,14 @@ describe('UpdateAccountSchema', () => {
|
||||
default_vat_rate: 0.5,
|
||||
}).success).toBe(false)
|
||||
})
|
||||
|
||||
it('accepts supported account VAT treatments and rejects unknown values', () => {
|
||||
expect(UpdateAccountSchema.safeParse({
|
||||
default_vat_treatment: 'reverse_charge_eu_goods',
|
||||
}).success).toBe(true)
|
||||
expect(UpdateAccountSchema.safeParse({ default_vat_treatment: null }).success).toBe(true)
|
||||
expect(UpdateAccountSchema.safeParse({ default_vat_treatment: 'eu_purchase' }).success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
// ============================================================
|
||||
|
||||
@@ -16,6 +16,7 @@ import { INVOICE_POSTING_ACCOUNT_REGEX } from '@/lib/invoices/posting-account'
|
||||
import { PERSONAL_NUMBER_INPUT_RE } from '@/lib/customers/mask-personal-number'
|
||||
import type { AuditAction } from '@/types'
|
||||
import type { BankFileFormatId } from '@/lib/import/bank-file/types'
|
||||
import { isVatTreatmentValidForAccountClass } from '@/lib/vat/account-vat-treatment'
|
||||
|
||||
// ============================================================
|
||||
// Shared primitives
|
||||
@@ -2110,6 +2111,15 @@ const defaultVatRate = z
|
||||
.nullable()
|
||||
.optional()
|
||||
|
||||
export const AccountVatTreatmentSchema = z.enum([
|
||||
'standard_25', 'reduced_12', 'reduced_6', 'exempt',
|
||||
'reverse_charge_domestic', 'reverse_charge_eu_goods',
|
||||
'reverse_charge_eu_services', 'export_goods', 'export_services',
|
||||
'vmb', 'rental_voluntary',
|
||||
])
|
||||
|
||||
const defaultVatTreatment = AccountVatTreatmentSchema.nullable().optional()
|
||||
|
||||
export const CreateAccountSchema = z.object({
|
||||
account_number: accountNumber,
|
||||
account_name: z.string().min(1, 'Account name is required'),
|
||||
@@ -2119,7 +2129,22 @@ export const CreateAccountSchema = z.object({
|
||||
description: z.string().nullable().optional(),
|
||||
default_vat_code: z.string().nullable().optional(),
|
||||
default_vat_rate: defaultVatRate,
|
||||
default_vat_treatment: defaultVatTreatment,
|
||||
sru_code: z.string().nullable().optional(),
|
||||
}).superRefine((value, ctx) => {
|
||||
if (
|
||||
value.default_vat_treatment &&
|
||||
!isVatTreatmentValidForAccountClass(
|
||||
value.default_vat_treatment,
|
||||
Number(value.account_number.charAt(0)),
|
||||
)
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
path: ['default_vat_treatment'],
|
||||
message: 'VAT treatment is not valid for the account class',
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
export const UpdateAccountSchema = z.object({
|
||||
@@ -2128,6 +2153,7 @@ export const UpdateAccountSchema = z.object({
|
||||
description: z.string().nullable().optional(),
|
||||
default_vat_code: z.string().nullable().optional(),
|
||||
default_vat_rate: defaultVatRate,
|
||||
default_vat_treatment: defaultVatTreatment,
|
||||
sru_code: z.string().nullable().optional(),
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user