import { describe, it, expect } from "vitest"; import { Decimal } from "@prisma/client"; describe("Buchungen - Double-Entry Bookkeeping Logic", () => { describe("TransactionAccount Enum", () => { it("should have KASSE and BANK accounts", () => { // These are the two main accounts for German bookkeeping const accounts = ["KASSE", "BANK"]; expect(accounts).toContain("KASSE"); expect(accounts).toContain("BANK"); }); }); describe("TransactionType Enum", () => { it("should have EINLAGE and ENTNAHME types", () => { // EINLAGE = Owner investment, ENTNAHME = Owner withdrawal const types = ["EINLAGE", "ENTNAHME"]; expect(types).toContain("EINLAGE"); expect(types).toContain("ENTNAHME"); }); }); describe("Zahlungsart Enum", () => { it("should have KASSE and BANK payment methods", () => { const paymentMethods = ["KASSE", "BANK"]; expect(paymentMethods).toContain("KASSE"); expect(paymentMethods).toContain("BANK"); }); }); describe("Buchung Business Logic", () => { it("should calculate correct sign for EINLAGE (positive)", () => { // EINLAGE increases the company's assets const amount = 1000; const type = "EINLAGE"; // In German bookkeeping: EINLAGE is recorded as positive (credit to equity) const signedAmount = type === "EINLAGE" ? amount : -amount; expect(signedAmount).toBe(1000); }); it("should calculate correct sign for ENTNAHME (negative)", () => { // ENTNAHME decreases the company's assets const amount = 500; const type = "ENTNAHME"; // In German bookkeeping: ENTNAHME is recorded as negative (debit to equity) const signedAmount = type === "EINLAGE" ? amount : -amount; expect(signedAmount).toBe(-500); }); it("should identify business records correctly", () => { // Business records (isBusinessRecord = true) come from Einnahmen/Ausgaben const isBusinessRecord = true; const hasKategorie = true; expect(isBusinessRecord).toBe(true); expect(hasKategorie).toBe(true); }); it("should handle non-business records (private)", () => { // Non-business records might not have a kategorie const isBusinessRecord = false; const kategorie = null; expect(isBusinessRecord).toBe(false); expect(kategorie).toBeNull(); }); it("should validate Decimal precision for amounts", () => { // Prisma Decimal(10,2) - max 10 digits, 2 decimal places const amount = 12345678.90; // 8 digits before decimal, 2 after const maxAmount = 99999999.99; // Max for DECIMAL(10,2) expect(amount).toBeLessThanOrEqual(maxAmount); expect(Number(amount.toFixed(2))).toBe(12345678.9); }); }); describe("Buchung Link Logic (Linked Transactions)", () => { it("should allow linking related transactions", () => { // Example: An invoice payment might be linked to the invoice const buchungId = "buchung-123"; const linkedBuchungId = "buchung-456"; // A Buchung can be linked to another (e.g., invoice payment -> invoice) const link = { source: buchungId, target: linkedBuchungId }; expect(link.source).toBe("buchung-123"); expect(link.target).toBe("buchung-456"); }); }); describe("Kategorie Logic", () => { it("should have unique category names per company", () => { // BuchungKategorie has @@unique([companyId, name, typ]) const companyId = "company-123"; const categories = [ { companyId, name: "Fußpflege", typ: "EINNAHME" }, { companyId, name: "Miete", typ: "AUSGABE" }, ]; const uniqueCheck = new Set(categories.map(c => `${c.companyId}-${c.name}-${c.typ}`)); expect(uniqueCheck.size).toBe(categories.length); }); it("should distinguish between EINNAHME and AUSGABE", () => { const einnahme: "EINNAHME" = "EINNAHME"; const ausgabe: "AUSGABE" = "AUSGABE"; expect(einnahme).toBe("EINNAHME"); expect(ausgabe).toBe("AUSGABE"); expect(einnahme).not.toBe(ausgabe); }); }); describe("Date-Based Queries", () => { it("should filter Buchungen by date range", () => { const buchungen = [ { date: new Date("2026-01-15"), amount: 100 }, { date: new Date("2026-02-20"), amount: 200 }, { date: new Date("2026-03-10"), amount: 300 }, ]; const startDate = new Date("2026-02-01"); const endDate = new Date("2026-03-31"); const filtered = buchungen.filter(b => b.date >= startDate && b.date <= endDate ); expect(filtered).toHaveLength(2); expect(filtered[0].amount).toBe(200); expect(filtered[1].amount).toBe(300); }); it("should group Buchungen by month for reports", () => { const buchungen = [ { date: new Date("2026-01-10"), amount: 100 }, { date: new Date("2026-01-20"), amount: 150 }, { date: new Date("2026-02-05"), amount: 200 }, ]; const grouped = buchungen.reduce((acc, b) => { const month = b.date.getMonth(); // 0-indexed acc[month] = (acc[month] || 0) + b.amount; return acc; }, {} as Record); expect(grouped[0]).toBe(250); // January (month 0) expect(grouped[1]).toBe(200); // February (month 1) }); }); });