@voyantjs/plugin-smartbill 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Minimal shape for Voyant invoice events. The plugin accepts anything with
3
+ * at least these fields; everything else is passed through to the mapper.
4
+ */
5
+ export interface VoyantInvoiceEvent {
6
+ id: string;
7
+ invoiceNumber?: string;
8
+ [key: string]: unknown;
9
+ }
10
+ /**
11
+ * SmartBill invoice line item (product).
12
+ * @see https://api.smartbill.ro/#!/Factura/createInvoice
13
+ */
14
+ export interface SmartbillProduct {
15
+ name: string;
16
+ code?: string;
17
+ measureUnit: string;
18
+ quantity: number;
19
+ price: number;
20
+ currency: string;
21
+ isTaxIncluded: boolean;
22
+ taxPercentage?: number;
23
+ isService?: boolean;
24
+ saveToDb?: boolean;
25
+ warehouseName?: string;
26
+ }
27
+ /**
28
+ * SmartBill invoice client.
29
+ */
30
+ export interface SmartbillClient {
31
+ name: string;
32
+ vatCode?: string;
33
+ regCom?: string;
34
+ address?: string;
35
+ city?: string;
36
+ county?: string;
37
+ country?: string;
38
+ isTaxPayer?: boolean;
39
+ email?: string;
40
+ phone?: string;
41
+ contact?: string;
42
+ saveToDb?: boolean;
43
+ }
44
+ /**
45
+ * SmartBill invoice body as accepted by the `POST /invoice` endpoint.
46
+ */
47
+ export interface SmartbillInvoiceBody {
48
+ companyVatCode: string;
49
+ client: SmartbillClient;
50
+ seriesName: string;
51
+ isDraft?: boolean;
52
+ currency: string;
53
+ language?: string;
54
+ dueDate?: string;
55
+ issueDate?: string;
56
+ deliveryDate?: string;
57
+ precision?: number;
58
+ useEstimateDetails?: boolean;
59
+ mentions?: string;
60
+ observations?: string;
61
+ products: SmartbillProduct[];
62
+ usePaymentTax?: boolean;
63
+ payment?: {
64
+ type: string;
65
+ value: number;
66
+ isCash: boolean;
67
+ };
68
+ }
69
+ /**
70
+ * SmartBill API response for invoice creation.
71
+ */
72
+ export interface SmartbillInvoiceResponse {
73
+ number?: string;
74
+ series?: string;
75
+ url?: string;
76
+ errorText?: string;
77
+ }
78
+ /**
79
+ * SmartBill API response for PDF download.
80
+ */
81
+ export interface SmartbillPdfResponse {
82
+ url?: string;
83
+ errorText?: string;
84
+ }
85
+ /**
86
+ * SmartBill API response for invoice status.
87
+ */
88
+ export interface SmartbillStatusResponse {
89
+ status?: string;
90
+ paidAmount?: number;
91
+ unpaidAmount?: number;
92
+ errorText?: string;
93
+ }
94
+ /**
95
+ * Minimal `fetch` shape the SmartBill client depends on. Works with the global
96
+ * `fetch` in Node 18+ / Cloudflare Workers / browsers, and is trivially
97
+ * stubbable in tests.
98
+ */
99
+ export type SmartbillFetch = (input: string, init: {
100
+ method: string;
101
+ headers: Record<string, string>;
102
+ body?: string;
103
+ }) => Promise<{
104
+ ok: boolean;
105
+ status: number;
106
+ json: () => Promise<unknown>;
107
+ text: () => Promise<string>;
108
+ }>;
109
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,182 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { createSmartbillClient } from "../../src/client.js";
3
+ function jsonResponse(status, body) {
4
+ const text = JSON.stringify(body);
5
+ return {
6
+ ok: status >= 200 && status < 300,
7
+ status,
8
+ json: async () => JSON.parse(text),
9
+ text: async () => text,
10
+ };
11
+ }
12
+ function textResponse(status, text) {
13
+ return {
14
+ ok: status >= 200 && status < 300,
15
+ status,
16
+ json: async () => {
17
+ throw new Error("not json");
18
+ },
19
+ text: async () => text,
20
+ };
21
+ }
22
+ const baseOptions = {
23
+ username: "user@example.com",
24
+ apiToken: "test-token",
25
+ };
26
+ describe("createSmartbillClient.createInvoice", () => {
27
+ it("sends POST to /invoice with basic auth", async () => {
28
+ const fetchMock = vi.fn(async () => jsonResponse(200, { number: "1", series: "A" }));
29
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
30
+ const result = await client.createInvoice({
31
+ companyVatCode: "RO123",
32
+ client: { name: "Acme" },
33
+ seriesName: "A",
34
+ currency: "RON",
35
+ products: [
36
+ {
37
+ name: "Tour",
38
+ measureUnit: "buc",
39
+ quantity: 1,
40
+ price: 100,
41
+ currency: "RON",
42
+ isTaxIncluded: true,
43
+ },
44
+ ],
45
+ });
46
+ expect(result).toEqual({ number: "1", series: "A" });
47
+ const [url, init] = fetchMock.mock.calls[0];
48
+ expect(url).toBe("https://ws.smartbill.ro/SBORO/api/invoice");
49
+ expect(init.method).toBe("POST");
50
+ expect(init.headers.Authorization).toMatch(/^Basic /);
51
+ expect(init.headers["Content-Type"]).toBe("application/json");
52
+ const body = JSON.parse(init.body ?? "{}");
53
+ expect(body.companyVatCode).toBe("RO123");
54
+ expect(body.products).toHaveLength(1);
55
+ });
56
+ it("throws on non-2xx response", async () => {
57
+ const fetchMock = vi.fn(async () => textResponse(400, "bad request"));
58
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
59
+ await expect(client.createInvoice({
60
+ companyVatCode: "RO123",
61
+ client: { name: "X" },
62
+ seriesName: "A",
63
+ currency: "RON",
64
+ products: [],
65
+ })).rejects.toThrow(/SmartBill createInvoice failed \(400\)/);
66
+ });
67
+ });
68
+ describe("createSmartbillClient.createProforma", () => {
69
+ it("sends POST to /estimate", async () => {
70
+ const fetchMock = vi.fn(async () => jsonResponse(200, { number: "P1", series: "P" }));
71
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
72
+ await client.createProforma({
73
+ companyVatCode: "RO123",
74
+ client: { name: "X" },
75
+ seriesName: "P",
76
+ currency: "RON",
77
+ products: [],
78
+ });
79
+ const [url] = fetchMock.mock.calls[0];
80
+ expect(url).toBe("https://ws.smartbill.ro/SBORO/api/estimate");
81
+ });
82
+ });
83
+ describe("createSmartbillClient.cancelInvoice", () => {
84
+ it("sends PUT to /invoice/cancel", async () => {
85
+ const fetchMock = vi.fn(async () => jsonResponse(200, {}));
86
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
87
+ await client.cancelInvoice("RO123", "A", "42");
88
+ const [url, init] = fetchMock.mock.calls[0];
89
+ expect(url).toBe("https://ws.smartbill.ro/SBORO/api/invoice/cancel");
90
+ expect(init.method).toBe("PUT");
91
+ const body = JSON.parse(init.body ?? "{}");
92
+ expect(body).toEqual({ companyVatCode: "RO123", seriesName: "A", number: "42" });
93
+ });
94
+ it("throws on error", async () => {
95
+ const fetchMock = vi.fn(async () => textResponse(500, "fail"));
96
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
97
+ await expect(client.cancelInvoice("RO123", "A", "1")).rejects.toThrow(/SmartBill cancelInvoice failed \(500\)/);
98
+ });
99
+ });
100
+ describe("createSmartbillClient.deleteInvoice", () => {
101
+ it("sends DELETE to /invoice with query params", async () => {
102
+ const fetchMock = vi.fn(async () => jsonResponse(200, {}));
103
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
104
+ await client.deleteInvoice("RO123", "A", "42");
105
+ const [url, init] = fetchMock.mock.calls[0];
106
+ expect(url).toContain("/invoice?cif=RO123&seriesname=A&number=42");
107
+ expect(init.method).toBe("DELETE");
108
+ });
109
+ });
110
+ describe("createSmartbillClient.reverseInvoice", () => {
111
+ it("sends PUT to /invoice/reverse", async () => {
112
+ const fetchMock = vi.fn(async () => jsonResponse(200, { number: "S1", series: "S" }));
113
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
114
+ const result = await client.reverseInvoice("RO123", "A", "42");
115
+ expect(result).toEqual({ number: "S1", series: "S" });
116
+ const [url, init] = fetchMock.mock.calls[0];
117
+ expect(url).toBe("https://ws.smartbill.ro/SBORO/api/invoice/reverse");
118
+ expect(init.method).toBe("PUT");
119
+ });
120
+ });
121
+ describe("createSmartbillClient.viewPdf", () => {
122
+ it("sends GET to /invoice/pdf with query params", async () => {
123
+ const fetchMock = vi.fn(async () => jsonResponse(200, { url: "https://smartbill.ro/pdf/123" }));
124
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
125
+ const result = await client.viewPdf("RO123", "A", "42");
126
+ expect(result.url).toBe("https://smartbill.ro/pdf/123");
127
+ const [url, init] = fetchMock.mock.calls[0];
128
+ expect(url).toContain("/invoice/pdf?cif=RO123&seriesname=A&number=42");
129
+ expect(init.method).toBe("GET");
130
+ });
131
+ });
132
+ describe("createSmartbillClient.getPaymentStatus", () => {
133
+ it("sends GET to /invoice/paymentstatus", async () => {
134
+ const fetchMock = vi.fn(async () => jsonResponse(200, { status: "paid", paidAmount: 100, unpaidAmount: 0 }));
135
+ const client = createSmartbillClient({ ...baseOptions, fetch: fetchMock });
136
+ const result = await client.getPaymentStatus("RO123", "A", "42");
137
+ expect(result).toEqual({ status: "paid", paidAmount: 100, unpaidAmount: 0 });
138
+ const [url] = fetchMock.mock.calls[0];
139
+ expect(url).toContain("/invoice/paymentstatus?cif=RO123&seriesname=A&number=42");
140
+ });
141
+ });
142
+ describe("createSmartbillClient — custom apiUrl", () => {
143
+ it("respects custom API base URL", async () => {
144
+ const fetchMock = vi.fn(async () => jsonResponse(200, {}));
145
+ const client = createSmartbillClient({
146
+ ...baseOptions,
147
+ apiUrl: "https://custom.example.com/api/",
148
+ fetch: fetchMock,
149
+ });
150
+ await client.cancelInvoice("RO1", "A", "1");
151
+ const [url] = fetchMock.mock.calls[0];
152
+ expect(url).toBe("https://custom.example.com/api/invoice/cancel");
153
+ });
154
+ });
155
+ describe("createSmartbillClient — basic auth encoding", () => {
156
+ it("encodes username:token as base64", async () => {
157
+ const fetchMock = vi.fn(async () => jsonResponse(200, {}));
158
+ const client = createSmartbillClient({
159
+ username: "test@test.com",
160
+ apiToken: "secret123",
161
+ fetch: fetchMock,
162
+ });
163
+ await client.cancelInvoice("X", "A", "1");
164
+ const [, init] = fetchMock.mock.calls[0];
165
+ const expected = `Basic ${btoa("test@test.com:secret123")}`;
166
+ expect(init.headers.Authorization).toBe(expected);
167
+ });
168
+ });
169
+ describe("createSmartbillClient — fetch handling", () => {
170
+ it("throws when no fetch implementation is available", async () => {
171
+ const originalFetch = globalThis.fetch;
172
+ globalThis.fetch = undefined;
173
+ try {
174
+ // biome-ignore lint/suspicious/noExplicitAny: simulating missing fetch
175
+ const client = createSmartbillClient({ ...baseOptions, fetch: undefined });
176
+ await expect(client.cancelInvoice("X", "A", "1")).rejects.toThrow(/requires a fetch implementation/);
177
+ }
178
+ finally {
179
+ globalThis.fetch = originalFetch;
180
+ }
181
+ });
182
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mapping.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mapping.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/mapping.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,149 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { mapClient, mapLineItems, mapVoyantInvoiceToSmartbill } from "../../src/mapping.js";
3
+ const defaultOptions = {
4
+ companyVatCode: "RO12345678",
5
+ seriesName: "A",
6
+ };
7
+ function event(overrides = {}) {
8
+ return { id: "inv_test", ...overrides };
9
+ }
10
+ describe("mapClient", () => {
11
+ it("extracts client fields from event", () => {
12
+ const result = mapClient(event({
13
+ clientName: "Acme SRL",
14
+ clientVatCode: "RO999",
15
+ clientAddress: "Str. Test 1",
16
+ clientCity: "Bucharest",
17
+ clientCounty: "B",
18
+ clientCountry: "RO",
19
+ clientEmail: "acme@test.com",
20
+ clientPhone: "+40700000000",
21
+ }));
22
+ expect(result.name).toBe("Acme SRL");
23
+ expect(result.vatCode).toBe("RO999");
24
+ expect(result.address).toBe("Str. Test 1");
25
+ expect(result.city).toBe("Bucharest");
26
+ expect(result.email).toBe("acme@test.com");
27
+ expect(result.saveToDb).toBe(false);
28
+ });
29
+ it("falls back to customerName if clientName is missing", () => {
30
+ const result = mapClient(event({ customerName: "Fallback Inc" }));
31
+ expect(result.name).toBe("Fallback Inc");
32
+ });
33
+ it("uses 'Client' fallback for missing name", () => {
34
+ const result = mapClient(event());
35
+ expect(result.name).toBe("Client");
36
+ });
37
+ it("returns undefined for missing optional fields", () => {
38
+ const result = mapClient(event());
39
+ expect(result.vatCode).toBeUndefined();
40
+ expect(result.address).toBeUndefined();
41
+ expect(result.email).toBeUndefined();
42
+ });
43
+ });
44
+ describe("mapLineItems", () => {
45
+ it("maps an array of line items", () => {
46
+ const result = mapLineItems(event({
47
+ lineItems: [
48
+ {
49
+ description: "Safari Tour",
50
+ code: "TOUR-1",
51
+ unit: "buc",
52
+ quantity: 2,
53
+ unitPrice: 50000,
54
+ currency: "RON",
55
+ isService: true,
56
+ },
57
+ ],
58
+ }), defaultOptions);
59
+ expect(result).toHaveLength(1);
60
+ expect(result[0].name).toBe("Safari Tour");
61
+ expect(result[0].code).toBe("TOUR-1");
62
+ expect(result[0].quantity).toBe(2);
63
+ expect(result[0].price).toBe(50000);
64
+ expect(result[0].isService).toBe(true);
65
+ expect(result[0].isTaxIncluded).toBe(true);
66
+ });
67
+ it("returns empty array when no lineItems", () => {
68
+ expect(mapLineItems(event(), defaultOptions)).toEqual([]);
69
+ });
70
+ it("uses event.currency as fallback for item currency", () => {
71
+ const result = mapLineItems(event({
72
+ currency: "EUR",
73
+ lineItems: [{ name: "X", quantity: 1, price: 10 }],
74
+ }), defaultOptions);
75
+ expect(result[0].currency).toBe("EUR");
76
+ });
77
+ it("respects isTaxIncluded from options", () => {
78
+ const result = mapLineItems(event({ lineItems: [{ name: "X", quantity: 1, price: 10 }] }), {
79
+ ...defaultOptions,
80
+ isTaxIncluded: false,
81
+ });
82
+ expect(result[0].isTaxIncluded).toBe(false);
83
+ });
84
+ it("passes through taxPercentage when present", () => {
85
+ const result = mapLineItems(event({ lineItems: [{ name: "X", quantity: 1, price: 10, taxPercentage: 19 }] }), defaultOptions);
86
+ expect(result[0].taxPercentage).toBe(19);
87
+ });
88
+ it("omits taxPercentage when not present", () => {
89
+ const result = mapLineItems(event({ lineItems: [{ name: "X", quantity: 1, price: 10 }] }), defaultOptions);
90
+ expect(result[0].taxPercentage).toBeUndefined();
91
+ });
92
+ });
93
+ describe("mapVoyantInvoiceToSmartbill", () => {
94
+ it("produces a complete SmartBill invoice body", () => {
95
+ const result = mapVoyantInvoiceToSmartbill(event({
96
+ clientName: "Test SRL",
97
+ currency: "RON",
98
+ issueDate: "2026-01-15",
99
+ dueDate: "2026-02-15",
100
+ lineItems: [{ name: "Tour Package", quantity: 1, unitPrice: 50000 }],
101
+ }), defaultOptions);
102
+ expect(result.companyVatCode).toBe("RO12345678");
103
+ expect(result.seriesName).toBe("A");
104
+ expect(result.currency).toBe("RON");
105
+ expect(result.language).toBe("RO");
106
+ expect(result.client.name).toBe("Test SRL");
107
+ expect(result.products).toHaveLength(1);
108
+ expect(result.issueDate).toBe("2026-01-15");
109
+ expect(result.dueDate).toBe("2026-02-15");
110
+ });
111
+ it("sets isDraft when event has isDraft=true", () => {
112
+ const result = mapVoyantInvoiceToSmartbill(event({ isDraft: true }), defaultOptions);
113
+ expect(result.isDraft).toBe(true);
114
+ });
115
+ it("does not set isDraft when not present", () => {
116
+ const result = mapVoyantInvoiceToSmartbill(event(), defaultOptions);
117
+ expect(result.isDraft).toBeUndefined();
118
+ });
119
+ it("appends Art. 311 mention when art311SpecialRegime is true", () => {
120
+ const result = mapVoyantInvoiceToSmartbill(event(), {
121
+ ...defaultOptions,
122
+ art311SpecialRegime: true,
123
+ });
124
+ expect(result.mentions).toContain("Art. 311");
125
+ });
126
+ it("appends Art. 311 to existing mentions", () => {
127
+ const result = mapVoyantInvoiceToSmartbill(event({ mentions: "Custom note" }), {
128
+ ...defaultOptions,
129
+ art311SpecialRegime: true,
130
+ });
131
+ expect(result.mentions).toContain("Custom note");
132
+ expect(result.mentions).toContain("Art. 311");
133
+ });
134
+ it("uses custom language", () => {
135
+ const result = mapVoyantInvoiceToSmartbill(event(), {
136
+ ...defaultOptions,
137
+ language: "EN",
138
+ });
139
+ expect(result.language).toBe("EN");
140
+ });
141
+ it("defaults currency to RON", () => {
142
+ const result = mapVoyantInvoiceToSmartbill(event(), defaultOptions);
143
+ expect(result.currency).toBe("RON");
144
+ });
145
+ it("passes through observations", () => {
146
+ const result = mapVoyantInvoiceToSmartbill(event({ observations: "Test obs" }), defaultOptions);
147
+ expect(result.observations).toBe("Test obs");
148
+ });
149
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plugin.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.test.d.ts","sourceRoot":"","sources":["../../../tests/unit/plugin.test.ts"],"names":[],"mappings":""}