Add comprehensive tests for client validation, revenue and expense categories, invoice generation, and schemas
- Implement tests for client validation functions including tax ID, VAT ID, IBAN, BIC, website, and company form validation. - Create tests for revenue and expense categories ensuring all expected categories and labels are present. - Add tests for invoice number generation with various scenarios including prefix handling and sequence padding. - Introduce tests for default categories and their integration, ensuring no overlaps and consistent naming conventions. - Implement Zod schema validation tests for currency, tax rates, IBAN, tax ID, VAT ID, invoices, companies, and customers. - Add utility tests for tax calculations, including item amounts and invoice totals, ensuring correct handling of tax rates and formatting. - Set up Vitest configuration and global test setup for consistent testing environment.
This commit is contained in:
@@ -0,0 +1,159 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
jahresAfa,
|
||||
erwerbsjahrAfa,
|
||||
afaFuerJahr,
|
||||
kumulierteAfa,
|
||||
buchwert,
|
||||
assetStatus,
|
||||
AnlagegutRaw,
|
||||
} from "@/lib/afa";
|
||||
|
||||
describe("afa.ts - Asset Depreciation (§7 EStG)", () => {
|
||||
const sampleAsset: AnlagegutRaw = {
|
||||
anschaffungskosten: 12000,
|
||||
nutzungsdauerJahre: 3,
|
||||
restwert: 0,
|
||||
anschaffungsdatum: "2024-03-15", // March 15, 2024
|
||||
aktiv: true,
|
||||
};
|
||||
|
||||
describe("jahresAfa", () => {
|
||||
it("should calculate full annual depreciation", () => {
|
||||
// 12000 over 3 years = 4000 per year
|
||||
expect(jahresAfa(12000, 0, 3)).toBe(4000);
|
||||
});
|
||||
|
||||
it("should handle residual value (restwert)", () => {
|
||||
// 12000 - 2000 restwert = 10000 over 3 years
|
||||
expect(jahresAfa(12000, 2000, 3)).toBe(3333.33);
|
||||
});
|
||||
|
||||
it("should handle different depreciation periods", () => {
|
||||
// 24000 over 8 years = 3000 per year
|
||||
expect(jahresAfa(24000, 0, 8)).toBe(3000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("erwerbsjahrAfa", () => {
|
||||
it("should calculate pro-rata depreciation in acquisition year", () => {
|
||||
// Acquired March 15 = 10 months remaining (Mar-Dec, inclusive) = 10/12
|
||||
// 4000 * (10/12) = 3333.33
|
||||
const acqDate = new Date("2024-03-15");
|
||||
const result = erwerbsjahrAfa(12000, 0, 3, acqDate);
|
||||
expect(result).toBe(3333.33);
|
||||
});
|
||||
|
||||
it("should calculate full year if acquired in January", () => {
|
||||
const acqDate = new Date("2024-01-01");
|
||||
const result = erwerbsjahrAfa(12000, 0, 3, acqDate);
|
||||
expect(result).toBe(4000);
|
||||
});
|
||||
|
||||
it("should calculate 1/12 if acquired in December", () => {
|
||||
const acqDate = new Date("2024-12-01");
|
||||
const result = erwerbsjahrAfa(12000, 0, 3, acqDate);
|
||||
expect(result).toBe(333.33);
|
||||
});
|
||||
});
|
||||
|
||||
describe("afaFuerJahr", () => {
|
||||
it("should return 0 for years before acquisition", () => {
|
||||
expect(afaFuerJahr(sampleAsset, 2023)).toBe(0);
|
||||
});
|
||||
|
||||
it("should return pro-rata for acquisition year", () => {
|
||||
// 2024 acquisition, 10 months = 3333.33
|
||||
const result = afaFuerJahr(sampleAsset, 2024);
|
||||
expect(result).toBe(3333.33);
|
||||
});
|
||||
|
||||
it("should return full annual amount for middle years", () => {
|
||||
expect(afaFuerJahr(sampleAsset, 2025)).toBe(4000);
|
||||
expect(afaFuerJahr(sampleAsset, 2026)).toBe(4000);
|
||||
});
|
||||
|
||||
it("should return 0 after full depreciation period", () => {
|
||||
// 3 years: 2024, 2025, 2026 -> after 2026 = 0
|
||||
expect(afaFuerJahr(sampleAsset, 2027)).toBe(0);
|
||||
});
|
||||
|
||||
it("should handle asset with residual value", () => {
|
||||
const assetWithRestwert: AnlagegutRaw = {
|
||||
anschaffungskosten: 5000,
|
||||
nutzungsdauerJahre: 5,
|
||||
restwert: 500,
|
||||
anschaffungsdatum: "2024-01-01",
|
||||
aktiv: true,
|
||||
};
|
||||
// (5000-500) / 5 = 900 per year
|
||||
expect(afaFuerJahr(assetWithRestwert, 2024)).toBe(900);
|
||||
expect(afaFuerJahr(assetWithRestwert, 2028)).toBe(900);
|
||||
expect(afaFuerJahr(assetWithRestwert, 2029)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("kumulierteAfa", () => {
|
||||
it("should calculate cumulative depreciation correctly", () => {
|
||||
// 2024: 3333.33, 2025: 4000, 2026: 4000 = 11333.33
|
||||
expect(kumulierteAfa(sampleAsset, 2026)).toBe(11333.33);
|
||||
});
|
||||
|
||||
it("should return 0 for year before acquisition", () => {
|
||||
expect(kumulierteAfa(sampleAsset, 2023)).toBe(0);
|
||||
});
|
||||
|
||||
it("should return full depreciation after end of period", () => {
|
||||
// After 3 years: 3333.33 + 4000 + 4000 = 11333.33
|
||||
// But asset cost is 12000, so 12000 - 11333.33 = 666.67 remaining
|
||||
const result = kumulierteAfa(sampleAsset, 2027);
|
||||
expect(result).toBe(11333.33);
|
||||
});
|
||||
});
|
||||
|
||||
describe("buchwert", () => {
|
||||
it("should calculate book value correctly", () => {
|
||||
// 2024: 3333.33 depreciation -> 12000 - 3333.33 = 8666.67
|
||||
expect(buchwert(sampleAsset, 2024)).toBe(8666.67);
|
||||
// 2025: another 4000 -> 8666.67 - 4000 = 4666.67
|
||||
expect(buchwert(sampleAsset, 2025)).toBe(4666.67);
|
||||
// 2026: another 4000 -> 4666.67 - 4000 = 666.67
|
||||
expect(buchwert(sampleAsset, 2026)).toBe(666.67);
|
||||
});
|
||||
|
||||
it("should not go below residual value", () => {
|
||||
const assetWithRestwert: AnlagegutRaw = {
|
||||
anschaffungskosten: 5000,
|
||||
nutzungsdauerJahre: 5,
|
||||
restwert: 500,
|
||||
anschaffungsdatum: "2024-01-01",
|
||||
aktiv: true,
|
||||
};
|
||||
// After full depreciation: 5000 - (900 * 5) = 500
|
||||
expect(buchwert(assetWithRestwert, 2028)).toBe(500);
|
||||
expect(buchwert(assetWithRestwert, 2030)).toBe(500);
|
||||
});
|
||||
|
||||
it("should return acquisition cost for year before acquisition", () => {
|
||||
expect(buchwert(sampleAsset, 2023)).toBe(12000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("assetStatus", () => {
|
||||
it("should return 'inaktiv' for inactive assets", () => {
|
||||
const inactive: AnlagegutRaw = { ...sampleAsset, aktiv: false };
|
||||
expect(assetStatus(inactive, 2025)).toBe("inaktiv");
|
||||
});
|
||||
|
||||
it("should return 'aktiv' for active assets within depreciation period", () => {
|
||||
expect(assetStatus(sampleAsset, 2024)).toBe("aktiv");
|
||||
expect(assetStatus(sampleAsset, 2025)).toBe("aktiv");
|
||||
expect(assetStatus(sampleAsset, 2026)).toBe("aktiv");
|
||||
});
|
||||
|
||||
it("should return 'vollständig abgeschrieben' after depreciation period", () => {
|
||||
expect(assetStatus(sampleAsset, 2027)).toBe("vollständig abgeschrieben");
|
||||
expect(assetStatus(sampleAsset, 2030)).toBe("vollständig abgeschrieben");
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user