183 lines
5.9 KiB
TypeScript
183 lines
5.9 KiB
TypeScript
import { TaxService } from "../src/tax/tax.service";
|
|
import { createPrismaMock } from "./utils/mock-prisma";
|
|
|
|
describe("TaxService", () => {
|
|
it("saves and submits complete intake as ready", async () => {
|
|
const prisma = createPrismaMock();
|
|
const createdAt = new Date("2026-07-16T00:00:00.000Z");
|
|
prisma.taxReturn.findFirst.mockResolvedValue({
|
|
id: "return_1",
|
|
userId: "user_1",
|
|
taxYear: 2026,
|
|
filingType: "individual",
|
|
jurisdictions: ["CA"],
|
|
status: "draft",
|
|
summary: {},
|
|
createdAt,
|
|
updatedAt: createdAt,
|
|
});
|
|
prisma.taxReturn.update.mockResolvedValue({
|
|
id: "return_1",
|
|
status: "ready",
|
|
summary: {},
|
|
});
|
|
prisma.auditLog.create.mockResolvedValue({});
|
|
const service = new TaxService(prisma as any);
|
|
|
|
const result = await service.saveIntake("user_1", "return_1", {
|
|
taxpayer: { name: "Jane Doe", filingStatus: "Single", address: "1 Main St" },
|
|
income: { total: 120000 },
|
|
deductions: { standard: true },
|
|
credits: {},
|
|
}, true);
|
|
|
|
expect(result.readiness.complete).toBe(true);
|
|
expect(prisma.taxReturn.update).toHaveBeenCalledWith({
|
|
where: { id: "return_1" },
|
|
data: expect.objectContaining({
|
|
status: "ready",
|
|
summary: expect.objectContaining({
|
|
intake: expect.any(Object),
|
|
intakeReadiness: expect.objectContaining({ complete: true }),
|
|
}),
|
|
}),
|
|
});
|
|
expect(prisma.auditLog.create).toHaveBeenCalledWith({
|
|
data: expect.objectContaining({
|
|
action: "tax.intake_submit",
|
|
}),
|
|
});
|
|
});
|
|
|
|
it("exports a versioned package with hash, manifest, and audit log", async () => {
|
|
const prisma = createPrismaMock();
|
|
const createdAt = new Date("2026-07-16T00:00:00.000Z");
|
|
prisma.taxReturn.findFirst.mockResolvedValue({
|
|
id: "return_1",
|
|
userId: "user_1",
|
|
taxYear: 2026,
|
|
filingType: "individual",
|
|
jurisdictions: ["CA"],
|
|
status: "draft",
|
|
summary: { grossIncome: 1000 },
|
|
createdAt,
|
|
updatedAt: createdAt,
|
|
documents: [
|
|
{
|
|
id: "doc_1",
|
|
taxReturnId: "return_1",
|
|
docType: "w2_or_1099",
|
|
metadata: { source: "upload" },
|
|
createdAt,
|
|
},
|
|
],
|
|
});
|
|
prisma.taxReturn.update.mockResolvedValue({});
|
|
prisma.auditLog.create.mockResolvedValue({});
|
|
const service = new TaxService(prisma as any);
|
|
|
|
const result = await service.exportReturn("user_1", "return_1");
|
|
|
|
expect(result.packageId).toMatch(/^taxpkg_/);
|
|
expect(result.packageVersion).toBe("2026.1");
|
|
expect(result.packageHash).toMatch(/^[a-f0-9]{64}$/);
|
|
expect(result.manifest).toEqual(expect.objectContaining({
|
|
taxReturnId: "return_1",
|
|
taxYear: 2026,
|
|
filingType: "individual",
|
|
documentCount: 1,
|
|
readiness: "needs_documents",
|
|
}));
|
|
expect(result.return.status).toBe("exported");
|
|
expect(result.documents).toHaveLength(1);
|
|
expect(prisma.auditLog.create).toHaveBeenCalledWith({
|
|
data: expect.objectContaining({
|
|
userId: "user_1",
|
|
action: "tax.export_package",
|
|
metadata: expect.objectContaining({
|
|
taxReturnId: "return_1",
|
|
packageHash: result.packageHash,
|
|
}),
|
|
}),
|
|
});
|
|
});
|
|
|
|
it("submits a ready return to the sandbox e-file provider", async () => {
|
|
const prisma = createPrismaMock();
|
|
const createdAt = new Date("2026-07-16T00:00:00.000Z");
|
|
prisma.taxReturn.findFirst.mockResolvedValue({
|
|
id: "return_1",
|
|
userId: "user_1",
|
|
taxYear: 2026,
|
|
filingType: "individual",
|
|
jurisdictions: ["CA"],
|
|
status: "ready",
|
|
summary: {
|
|
intake: {
|
|
taxpayer: { name: "Jane Doe", filingStatus: "Single", address: "1 Main St" },
|
|
income: { total: 120000 },
|
|
},
|
|
},
|
|
createdAt,
|
|
updatedAt: createdAt,
|
|
documents: [
|
|
{ id: "doc_1", docType: "w2_or_1099", metadata: {}, createdAt },
|
|
{ id: "doc_2", docType: "interest_and_dividend_forms", metadata: {}, createdAt },
|
|
{ id: "doc_3", docType: "deduction_support", metadata: {}, createdAt },
|
|
{ id: "doc_4", docType: "identity_information", metadata: {}, createdAt },
|
|
],
|
|
});
|
|
prisma.taxReturn.update.mockResolvedValue({
|
|
id: "return_1",
|
|
status: "efile_submitted",
|
|
summary: {},
|
|
});
|
|
prisma.auditLog.create.mockResolvedValue({});
|
|
const service = new TaxService(prisma as any);
|
|
|
|
const result = await service.submitEFile("user_1", "return_1", true);
|
|
|
|
expect(result.eFile.provider).toBe("sandbox");
|
|
expect(result.eFile.status).toBe("submitted");
|
|
expect(result.eFile.submissionId).toMatch(/^efile_/);
|
|
expect(result.eFile.packageHash).toMatch(/^[a-f0-9]{64}$/);
|
|
expect(prisma.taxReturn.update).toHaveBeenCalledWith({
|
|
where: { id: "return_1" },
|
|
data: expect.objectContaining({
|
|
status: "efile_submitted",
|
|
summary: expect.objectContaining({
|
|
eFile: expect.objectContaining({
|
|
provider: "sandbox",
|
|
status: "submitted",
|
|
}),
|
|
}),
|
|
}),
|
|
});
|
|
expect(prisma.auditLog.create).toHaveBeenCalledWith({
|
|
data: expect.objectContaining({
|
|
action: "tax.efile_submit",
|
|
}),
|
|
});
|
|
});
|
|
|
|
it("blocks e-file submission when intake or documents are incomplete", async () => {
|
|
const prisma = createPrismaMock();
|
|
prisma.taxReturn.findFirst.mockResolvedValue({
|
|
id: "return_1",
|
|
userId: "user_1",
|
|
taxYear: 2026,
|
|
filingType: "individual",
|
|
jurisdictions: ["CA"],
|
|
status: "draft",
|
|
summary: { intake: { taxpayer: { name: "Jane Doe" }, income: {} } },
|
|
documents: [],
|
|
});
|
|
const service = new TaxService(prisma as any);
|
|
|
|
await expect(service.submitEFile("user_1", "return_1", true)).rejects.toThrow(
|
|
"Tax return is not ready for e-file submission.",
|
|
);
|
|
expect(prisma.taxReturn.update).not.toHaveBeenCalled();
|
|
});
|
|
});
|