@voyantjs/plugin-smartbill 0.24.1 → 0.24.3
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.
- package/dist/client.d.ts +38 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +105 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/mapping.d.ts +32 -0
- package/dist/mapping.d.ts.map +1 -0
- package/dist/mapping.js +91 -0
- package/dist/plugin.d.ts +22 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +127 -0
- package/dist/runtime.d.ts +16 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +27 -0
- package/dist/settlement.d.ts +30 -0
- package/dist/settlement.d.ts.map +1 -0
- package/dist/settlement.js +63 -0
- package/dist/types.d.ts +110 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/validation.d.ts +18 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +33 -0
- package/package.json +3 -3
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { SmartbillFetch, SmartbillInvoiceBody, SmartbillInvoiceResponse, SmartbillPdfResponse, SmartbillStatusResponse } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options for {@link createSmartbillClient}.
|
|
4
|
+
*/
|
|
5
|
+
export interface SmartbillClientOptions {
|
|
6
|
+
/** SmartBill account username (email). */
|
|
7
|
+
username: string;
|
|
8
|
+
/** SmartBill API token. */
|
|
9
|
+
apiToken: string;
|
|
10
|
+
/**
|
|
11
|
+
* SmartBill API base URL. Defaults to `"https://ws.smartbill.ro/SBORO/api"`.
|
|
12
|
+
*/
|
|
13
|
+
apiUrl?: string;
|
|
14
|
+
/** Override `fetch` (e.g. in tests). Defaults to global `fetch`. */
|
|
15
|
+
fetch?: SmartbillFetch;
|
|
16
|
+
}
|
|
17
|
+
export interface SmartbillClientApi {
|
|
18
|
+
/** Create an invoice. Returns the series + number + URL. */
|
|
19
|
+
createInvoice(body: SmartbillInvoiceBody): Promise<SmartbillInvoiceResponse>;
|
|
20
|
+
/** Create a proforma invoice. */
|
|
21
|
+
createProforma(body: SmartbillInvoiceBody): Promise<SmartbillInvoiceResponse>;
|
|
22
|
+
/** Cancel an invoice by series + number. */
|
|
23
|
+
cancelInvoice(companyVatCode: string, seriesName: string, number: string): Promise<{
|
|
24
|
+
errorText?: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** Delete an invoice by series + number. */
|
|
27
|
+
deleteInvoice(companyVatCode: string, seriesName: string, number: string): Promise<{
|
|
28
|
+
errorText?: string;
|
|
29
|
+
}>;
|
|
30
|
+
/** Reverse an invoice by series + number. */
|
|
31
|
+
reverseInvoice(companyVatCode: string, seriesName: string, number: string): Promise<SmartbillInvoiceResponse>;
|
|
32
|
+
/** Get PDF URL for an invoice. */
|
|
33
|
+
viewPdf(companyVatCode: string, seriesName: string, number: string): Promise<SmartbillPdfResponse>;
|
|
34
|
+
/** Get payment status for an invoice. */
|
|
35
|
+
getPaymentStatus(companyVatCode: string, seriesName: string, number: string): Promise<SmartbillStatusResponse>;
|
|
36
|
+
}
|
|
37
|
+
export declare function createSmartbillClient(options: SmartbillClientOptions): SmartbillClientApi;
|
|
38
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAEnB;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC5E,iCAAiC;IACjC,cAAc,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAA;IAC7E,4CAA4C;IAC5C,aAAa,CACX,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClC,4CAA4C;IAC5C,aAAa,CACX,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAClC,6CAA6C;IAC7C,cAAc,CACZ,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,wBAAwB,CAAC,CAAA;IACpC,kCAAkC;IAClC,OAAO,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAA;IAClG,yCAAyC;IACzC,gBAAgB,CACd,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,uBAAuB,CAAC,CAAA;CACpC;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,kBAAkB,CAyIzF"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export function createSmartbillClient(options) {
|
|
2
|
+
const apiUrl = (options.apiUrl ?? "https://ws.smartbill.ro/SBORO/api").replace(/\/$/, "");
|
|
3
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
4
|
+
function authHeader() {
|
|
5
|
+
return `Basic ${btoa(`${options.username}:${options.apiToken}`)}`;
|
|
6
|
+
}
|
|
7
|
+
function headers() {
|
|
8
|
+
return {
|
|
9
|
+
Authorization: authHeader(),
|
|
10
|
+
"Content-Type": "application/json",
|
|
11
|
+
Accept: "application/json",
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
async function request(method, path, body) {
|
|
15
|
+
if (!fetchImpl) {
|
|
16
|
+
throw new Error("SmartBill client requires a fetch implementation");
|
|
17
|
+
}
|
|
18
|
+
const init = {
|
|
19
|
+
method,
|
|
20
|
+
headers: headers(),
|
|
21
|
+
};
|
|
22
|
+
if (body !== undefined)
|
|
23
|
+
init.body = JSON.stringify(body);
|
|
24
|
+
const response = await fetchImpl(`${apiUrl}${path}`, init);
|
|
25
|
+
let text = "";
|
|
26
|
+
let json = null;
|
|
27
|
+
try {
|
|
28
|
+
text = await response.text();
|
|
29
|
+
json = text ? JSON.parse(text) : null;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// leave json as null, surface text
|
|
33
|
+
}
|
|
34
|
+
return { ok: response.ok, status: response.status, json, text };
|
|
35
|
+
}
|
|
36
|
+
async function createInvoice(body) {
|
|
37
|
+
const res = await request("POST", "/invoice", body);
|
|
38
|
+
if (!res.ok) {
|
|
39
|
+
throw new Error(`SmartBill createInvoice failed (${res.status}): ${res.text}`);
|
|
40
|
+
}
|
|
41
|
+
return (res.json ?? {});
|
|
42
|
+
}
|
|
43
|
+
async function createProforma(body) {
|
|
44
|
+
const res = await request("POST", "/estimate", body);
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
throw new Error(`SmartBill createProforma failed (${res.status}): ${res.text}`);
|
|
47
|
+
}
|
|
48
|
+
return (res.json ?? {});
|
|
49
|
+
}
|
|
50
|
+
async function cancelInvoice(companyVatCode, seriesName, number) {
|
|
51
|
+
const res = await request("PUT", "/invoice/cancel", {
|
|
52
|
+
companyVatCode,
|
|
53
|
+
seriesName,
|
|
54
|
+
number,
|
|
55
|
+
});
|
|
56
|
+
if (!res.ok) {
|
|
57
|
+
throw new Error(`SmartBill cancelInvoice failed (${res.status}): ${res.text}`);
|
|
58
|
+
}
|
|
59
|
+
return (res.json ?? {});
|
|
60
|
+
}
|
|
61
|
+
async function deleteInvoice(companyVatCode, seriesName, number) {
|
|
62
|
+
const query = `cif=${encodeURIComponent(companyVatCode)}&seriesname=${encodeURIComponent(seriesName)}&number=${encodeURIComponent(number)}`;
|
|
63
|
+
const res = await request("DELETE", `/invoice?${query}`);
|
|
64
|
+
if (!res.ok) {
|
|
65
|
+
throw new Error(`SmartBill deleteInvoice failed (${res.status}): ${res.text}`);
|
|
66
|
+
}
|
|
67
|
+
return (res.json ?? {});
|
|
68
|
+
}
|
|
69
|
+
async function reverseInvoice(companyVatCode, seriesName, number) {
|
|
70
|
+
const res = await request("PUT", "/invoice/reverse", {
|
|
71
|
+
companyVatCode,
|
|
72
|
+
seriesName,
|
|
73
|
+
number,
|
|
74
|
+
});
|
|
75
|
+
if (!res.ok) {
|
|
76
|
+
throw new Error(`SmartBill reverseInvoice failed (${res.status}): ${res.text}`);
|
|
77
|
+
}
|
|
78
|
+
return (res.json ?? {});
|
|
79
|
+
}
|
|
80
|
+
async function viewPdf(companyVatCode, seriesName, number) {
|
|
81
|
+
const query = `cif=${encodeURIComponent(companyVatCode)}&seriesname=${encodeURIComponent(seriesName)}&number=${encodeURIComponent(number)}`;
|
|
82
|
+
const res = await request("GET", `/invoice/pdf?${query}`);
|
|
83
|
+
if (!res.ok) {
|
|
84
|
+
throw new Error(`SmartBill viewPdf failed (${res.status}): ${res.text}`);
|
|
85
|
+
}
|
|
86
|
+
return (res.json ?? {});
|
|
87
|
+
}
|
|
88
|
+
async function getPaymentStatus(companyVatCode, seriesName, number) {
|
|
89
|
+
const query = `cif=${encodeURIComponent(companyVatCode)}&seriesname=${encodeURIComponent(seriesName)}&number=${encodeURIComponent(number)}`;
|
|
90
|
+
const res = await request("GET", `/invoice/paymentstatus?${query}`);
|
|
91
|
+
if (!res.ok) {
|
|
92
|
+
throw new Error(`SmartBill getPaymentStatus failed (${res.status}): ${res.text}`);
|
|
93
|
+
}
|
|
94
|
+
return (res.json ?? {});
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
createInvoice,
|
|
98
|
+
createProforma,
|
|
99
|
+
cancelInvoice,
|
|
100
|
+
deleteInvoice,
|
|
101
|
+
reverseInvoice,
|
|
102
|
+
viewPdf,
|
|
103
|
+
getPaymentStatus,
|
|
104
|
+
};
|
|
105
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type { SmartbillClientApi, SmartbillClientOptions } from "./client.js";
|
|
2
|
+
export { createSmartbillClient } from "./client.js";
|
|
3
|
+
export type { SmartbillMappingOptions } from "./mapping.js";
|
|
4
|
+
export { mapClient, mapLineItems, mapVoyantInvoiceToSmartbill } from "./mapping.js";
|
|
5
|
+
export type { SmartbillLogger, SmartbillMapFn, SmartbillPluginOptions, SmartbillSyncEventNames, } from "./plugin.js";
|
|
6
|
+
export { smartbillPlugin } from "./plugin.js";
|
|
7
|
+
export type { ResolvedSmartbillSyncEventNames, SmartbillSyncRuntime } from "./runtime.js";
|
|
8
|
+
export { createSmartbillSyncRuntime } from "./runtime.js";
|
|
9
|
+
export type { SmartbillInvoiceSettlementPoller, SmartbillInvoiceSettlementPollerOptions, SmartbillSettlementExternalRef, SmartbillSettlementInvoice, SmartbillSettlementPollerContext, SmartbillSettlementPollerResult, } from "./settlement.js";
|
|
10
|
+
export { createSmartbillInvoiceSettlementPoller } from "./settlement.js";
|
|
11
|
+
export type { SmartbillClient, SmartbillFetch, SmartbillInvoiceBody, SmartbillInvoiceResponse, SmartbillPdfResponse, SmartbillProduct, SmartbillStatusResponse, VoyantInvoiceEvent, } from "./types.js";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAC7E,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACnD,YAAY,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAC3D,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,2BAA2B,EAAE,MAAM,cAAc,CAAA;AACnF,YAAY,EACV,eAAe,EACf,cAAc,EACd,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EAAE,+BAA+B,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,cAAc,CAAA;AACzD,YAAY,EACV,gCAAgC,EAChC,uCAAuC,EACvC,8BAA8B,EAC9B,0BAA0B,EAC1B,gCAAgC,EAChC,+BAA+B,GAChC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,sCAAsC,EAAE,MAAM,iBAAiB,CAAA;AACxE,YAAY,EACV,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { createSmartbillClient } from "./client.js";
|
|
2
|
+
export { mapClient, mapLineItems, mapVoyantInvoiceToSmartbill } from "./mapping.js";
|
|
3
|
+
export { smartbillPlugin } from "./plugin.js";
|
|
4
|
+
export { createSmartbillSyncRuntime } from "./runtime.js";
|
|
5
|
+
export { createSmartbillInvoiceSettlementPoller } from "./settlement.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { SmartbillClient, SmartbillInvoiceBody, SmartbillProduct, VoyantInvoiceEvent } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options for the default invoice mapper.
|
|
4
|
+
*/
|
|
5
|
+
export interface SmartbillMappingOptions {
|
|
6
|
+
/** Romanian company VAT code (e.g. `"RO12345678"`). */
|
|
7
|
+
companyVatCode: string;
|
|
8
|
+
/** SmartBill invoice series name (e.g. `"A"`). */
|
|
9
|
+
seriesName: string;
|
|
10
|
+
/** Invoice language. Defaults to `"RO"`. */
|
|
11
|
+
language?: string;
|
|
12
|
+
/** Whether VAT is included in line item prices. Defaults to `true`. */
|
|
13
|
+
isTaxIncluded?: boolean;
|
|
14
|
+
/** Whether to use Art. 311 special regime (margin scheme for travel). */
|
|
15
|
+
art311SpecialRegime?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract the SmartBill client block from a Voyant invoice event.
|
|
19
|
+
* Falls back to empty strings for missing fields.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mapClient(event: VoyantInvoiceEvent): SmartbillClient;
|
|
22
|
+
/**
|
|
23
|
+
* Extract SmartBill product lines from a Voyant invoice event.
|
|
24
|
+
* Expects `event.lineItems` to be an array of objects with at minimum
|
|
25
|
+
* `description`/`name`, `quantity`, `unitPrice`, `currency`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function mapLineItems(event: VoyantInvoiceEvent, options: SmartbillMappingOptions): SmartbillProduct[];
|
|
28
|
+
/**
|
|
29
|
+
* Map a full Voyant invoice event to a SmartBill invoice body.
|
|
30
|
+
*/
|
|
31
|
+
export declare function mapVoyantInvoiceToSmartbill(event: VoyantInvoiceEvent, options: SmartbillMappingOptions): SmartbillInvoiceBody;
|
|
32
|
+
//# sourceMappingURL=mapping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapping.d.ts","sourceRoot":"","sources":["../src/mapping.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,YAAY,CAAA;AAEnB;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAA;IACtB,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAA;IAClB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,yEAAyE;IACzE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,kBAAkB,GAAG,eAAe,CAapE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,uBAAuB,GAC/B,gBAAgB,EAAE,CAiBpB;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,kBAAkB,EACzB,OAAO,EAAE,uBAAuB,GAC/B,oBAAoB,CA2BtB"}
|
package/dist/mapping.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract the SmartBill client block from a Voyant invoice event.
|
|
3
|
+
* Falls back to empty strings for missing fields.
|
|
4
|
+
*/
|
|
5
|
+
export function mapClient(event) {
|
|
6
|
+
return {
|
|
7
|
+
name: asString(event.clientName ?? event.customerName, "Client"),
|
|
8
|
+
vatCode: asStringOrUndefined(event.clientVatCode ?? event.customerVatCode),
|
|
9
|
+
regCom: asStringOrUndefined(event.clientRegCom),
|
|
10
|
+
address: asStringOrUndefined(event.clientAddress ?? event.customerAddress),
|
|
11
|
+
city: asStringOrUndefined(event.clientCity ?? event.customerCity),
|
|
12
|
+
county: asStringOrUndefined(event.clientCounty ?? event.customerCounty),
|
|
13
|
+
country: asStringOrUndefined(event.clientCountry ?? event.customerCountry),
|
|
14
|
+
email: asStringOrUndefined(event.clientEmail ?? event.customerEmail),
|
|
15
|
+
phone: asStringOrUndefined(event.clientPhone ?? event.customerPhone),
|
|
16
|
+
saveToDb: false,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Extract SmartBill product lines from a Voyant invoice event.
|
|
21
|
+
* Expects `event.lineItems` to be an array of objects with at minimum
|
|
22
|
+
* `description`/`name`, `quantity`, `unitPrice`, `currency`.
|
|
23
|
+
*/
|
|
24
|
+
export function mapLineItems(event, options) {
|
|
25
|
+
const items = event.lineItems;
|
|
26
|
+
if (!Array.isArray(items))
|
|
27
|
+
return [];
|
|
28
|
+
return items.map((item) => ({
|
|
29
|
+
name: asString(item.description ?? item.name, "Item"),
|
|
30
|
+
code: asStringOrUndefined(item.code ?? item.sku),
|
|
31
|
+
measureUnit: asString(item.measureUnit ?? item.unit, "buc"),
|
|
32
|
+
quantity: asNumber(item.quantity, 1),
|
|
33
|
+
price: asNumber(item.unitPrice ?? item.price, 0),
|
|
34
|
+
currency: asString(item.currency ?? event.currency, "RON"),
|
|
35
|
+
isTaxIncluded: options.isTaxIncluded ?? true,
|
|
36
|
+
taxName: asStringOrUndefined(item.taxName),
|
|
37
|
+
taxPercentage: item.taxPercentage != null ? asNumber(item.taxPercentage, 0) : undefined,
|
|
38
|
+
isService: item.isService === true,
|
|
39
|
+
saveToDb: false,
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Map a full Voyant invoice event to a SmartBill invoice body.
|
|
44
|
+
*/
|
|
45
|
+
export function mapVoyantInvoiceToSmartbill(event, options) {
|
|
46
|
+
const body = {
|
|
47
|
+
companyVatCode: options.companyVatCode,
|
|
48
|
+
client: mapClient(event),
|
|
49
|
+
seriesName: options.seriesName,
|
|
50
|
+
currency: asString(event.currency, "RON"),
|
|
51
|
+
language: options.language ?? "RO",
|
|
52
|
+
products: mapLineItems(event, options),
|
|
53
|
+
};
|
|
54
|
+
if (event.isDraft === true)
|
|
55
|
+
body.isDraft = true;
|
|
56
|
+
if (typeof event.dueDate === "string")
|
|
57
|
+
body.dueDate = event.dueDate;
|
|
58
|
+
if (typeof event.issueDate === "string")
|
|
59
|
+
body.issueDate = event.issueDate;
|
|
60
|
+
if (typeof event.deliveryDate === "string")
|
|
61
|
+
body.deliveryDate = event.deliveryDate;
|
|
62
|
+
if (typeof event.mentions === "string")
|
|
63
|
+
body.mentions = event.mentions;
|
|
64
|
+
if (typeof event.observations === "string")
|
|
65
|
+
body.observations = event.observations;
|
|
66
|
+
if (options.art311SpecialRegime) {
|
|
67
|
+
body.mentions = [
|
|
68
|
+
body.mentions,
|
|
69
|
+
"Regimul special de taxare - agentie de turism (Art. 311 Cod Fiscal)",
|
|
70
|
+
]
|
|
71
|
+
.filter(Boolean)
|
|
72
|
+
.join("\n");
|
|
73
|
+
}
|
|
74
|
+
return body;
|
|
75
|
+
}
|
|
76
|
+
// --- helpers ---
|
|
77
|
+
function asString(value, fallback) {
|
|
78
|
+
if (typeof value === "string" && value.length > 0)
|
|
79
|
+
return value;
|
|
80
|
+
return fallback;
|
|
81
|
+
}
|
|
82
|
+
function asStringOrUndefined(value) {
|
|
83
|
+
if (typeof value === "string" && value.length > 0)
|
|
84
|
+
return value;
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
function asNumber(value, fallback) {
|
|
88
|
+
if (typeof value === "number" && !Number.isNaN(value))
|
|
89
|
+
return value;
|
|
90
|
+
return fallback;
|
|
91
|
+
}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Plugin } from "@voyantjs/core";
|
|
2
|
+
import type { SmartbillClientOptions } from "./client.js";
|
|
3
|
+
import type { mapVoyantInvoiceToSmartbill, SmartbillMappingOptions } from "./mapping.js";
|
|
4
|
+
import type { VoyantInvoiceEvent } from "./types.js";
|
|
5
|
+
export interface SmartbillSyncEventNames {
|
|
6
|
+
issued?: string;
|
|
7
|
+
proformaIssued?: string;
|
|
8
|
+
voided?: string;
|
|
9
|
+
syncRequested?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SmartbillLogger {
|
|
12
|
+
error: (message: string, meta?: unknown) => void;
|
|
13
|
+
info?: (message: string, meta?: unknown) => void;
|
|
14
|
+
}
|
|
15
|
+
export type SmartbillMapFn = (event: VoyantInvoiceEvent) => ReturnType<typeof mapVoyantInvoiceToSmartbill>;
|
|
16
|
+
export interface SmartbillPluginOptions extends SmartbillClientOptions, SmartbillMappingOptions {
|
|
17
|
+
events?: SmartbillSyncEventNames;
|
|
18
|
+
mapEvent?: SmartbillMapFn;
|
|
19
|
+
logger?: SmartbillLogger;
|
|
20
|
+
}
|
|
21
|
+
export declare function smartbillPlugin(options: SmartbillPluginOptions): Plugin;
|
|
22
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAc,MAAM,gBAAgB,CAAA;AAGxD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,KAAK,EAAE,2BAA2B,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAExF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAGpD,MAAM,WAAW,uBAAuB;IACtC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;IAChD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAA;CACjD;AAED,MAAM,MAAM,cAAc,GAAG,CAC3B,KAAK,EAAE,kBAAkB,KACtB,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAEnD,MAAM,WAAW,sBAAuB,SAAQ,sBAAsB,EAAE,uBAAuB;IAC7F,MAAM,CAAC,EAAE,uBAAuB,CAAA;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAA;IACzB,MAAM,CAAC,EAAE,eAAe,CAAA;CACzB;AASD,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAyHvE"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { ZodError } from "zod";
|
|
2
|
+
import { createSmartbillSyncRuntime } from "./runtime.js";
|
|
3
|
+
import { smartbillPluginOptionsSchema } from "./validation.js";
|
|
4
|
+
function coerceEvent(data) {
|
|
5
|
+
if (data == null || typeof data !== "object")
|
|
6
|
+
return null;
|
|
7
|
+
const maybe = data;
|
|
8
|
+
if (typeof maybe.id !== "string")
|
|
9
|
+
return null;
|
|
10
|
+
return maybe;
|
|
11
|
+
}
|
|
12
|
+
export function smartbillPlugin(options) {
|
|
13
|
+
const validatedOptions = parseSmartbillPluginOptions(options);
|
|
14
|
+
const { client, logger, mapEvent, eventNames } = createSmartbillSyncRuntime(validatedOptions);
|
|
15
|
+
const subscribers = [
|
|
16
|
+
{
|
|
17
|
+
event: eventNames.issued,
|
|
18
|
+
handler: async (envelope) => {
|
|
19
|
+
const event = coerceEvent(envelope.data);
|
|
20
|
+
if (!event)
|
|
21
|
+
return;
|
|
22
|
+
try {
|
|
23
|
+
const body = mapEvent(event);
|
|
24
|
+
const result = await client.createInvoice(body);
|
|
25
|
+
logger.info?.(`[smartbill] invoice created: ${result.series}-${result.number} for ${event.id}`, result);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
logger.error(`[smartbill] createInvoice on "${eventNames.issued}" failed for ${event.id}`, err);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
event: eventNames.proformaIssued,
|
|
34
|
+
handler: async (envelope) => {
|
|
35
|
+
const event = coerceEvent(envelope.data);
|
|
36
|
+
if (!event)
|
|
37
|
+
return;
|
|
38
|
+
try {
|
|
39
|
+
// Same shape as createInvoice — SmartBill's `/proforma`
|
|
40
|
+
// endpoint accepts the same body as `/invoice`.
|
|
41
|
+
const body = mapEvent(event);
|
|
42
|
+
const result = await client.createProforma(body);
|
|
43
|
+
logger.info?.(`[smartbill] proforma created: ${result.series}-${result.number} for ${event.id}`, result);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
logger.error(`[smartbill] createProforma on "${eventNames.proformaIssued}" failed for ${event.id}`, err);
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
event: eventNames.voided,
|
|
52
|
+
handler: async (envelope) => {
|
|
53
|
+
const event = coerceEvent(envelope.data);
|
|
54
|
+
if (!event)
|
|
55
|
+
return;
|
|
56
|
+
try {
|
|
57
|
+
const seriesName = typeof event.externalSeriesName === "string"
|
|
58
|
+
? event.externalSeriesName
|
|
59
|
+
: validatedOptions.seriesName;
|
|
60
|
+
const number = typeof event.externalNumber === "string"
|
|
61
|
+
? event.externalNumber
|
|
62
|
+
: typeof event.invoiceNumber === "string"
|
|
63
|
+
? event.invoiceNumber
|
|
64
|
+
: undefined;
|
|
65
|
+
if (!number) {
|
|
66
|
+
logger.error(`[smartbill] cannot cancel invoice ${event.id}: missing external number`);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
await client.cancelInvoice(validatedOptions.companyVatCode, seriesName, number);
|
|
70
|
+
logger.info?.(`[smartbill] invoice cancelled: ${seriesName}-${number} for ${event.id}`);
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
logger.error(`[smartbill] cancelInvoice on "${eventNames.voided}" failed for ${event.id}`, err);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
event: eventNames.syncRequested,
|
|
79
|
+
handler: async (envelope) => {
|
|
80
|
+
const event = coerceEvent(envelope.data);
|
|
81
|
+
if (!event)
|
|
82
|
+
return;
|
|
83
|
+
try {
|
|
84
|
+
const seriesName = typeof event.externalSeriesName === "string"
|
|
85
|
+
? event.externalSeriesName
|
|
86
|
+
: validatedOptions.seriesName;
|
|
87
|
+
const number = typeof event.externalNumber === "string"
|
|
88
|
+
? event.externalNumber
|
|
89
|
+
: typeof event.invoiceNumber === "string"
|
|
90
|
+
? event.invoiceNumber
|
|
91
|
+
: undefined;
|
|
92
|
+
if (!number) {
|
|
93
|
+
logger.error(`[smartbill] cannot sync invoice ${event.id}: missing external number`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const status = await client.getPaymentStatus(validatedOptions.companyVatCode, seriesName, number);
|
|
97
|
+
logger.info?.(`[smartbill] payment status for ${seriesName}-${number}: ${status.status}`, status);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
logger.error(`[smartbill] getPaymentStatus on "${eventNames.syncRequested}" failed for ${event.id}`, err);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
];
|
|
105
|
+
return {
|
|
106
|
+
name: "smartbill",
|
|
107
|
+
version: "0.1.0",
|
|
108
|
+
subscribers,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function parseSmartbillPluginOptions(options) {
|
|
112
|
+
try {
|
|
113
|
+
return smartbillPluginOptionsSchema.parse(options);
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof ZodError) {
|
|
117
|
+
const detail = error.issues
|
|
118
|
+
.map((issue) => {
|
|
119
|
+
const path = issue.path.join(".") || "options";
|
|
120
|
+
return `${path}: ${issue.message}`;
|
|
121
|
+
})
|
|
122
|
+
.join("; ");
|
|
123
|
+
throw new Error(`Invalid SmartBill plugin options: ${detail}`);
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createSmartbillClient } from "./client.js";
|
|
2
|
+
import type { SmartbillLogger, SmartbillMapFn, SmartbillPluginOptions } from "./plugin.js";
|
|
3
|
+
export interface ResolvedSmartbillSyncEventNames {
|
|
4
|
+
issued: string;
|
|
5
|
+
proformaIssued: string;
|
|
6
|
+
voided: string;
|
|
7
|
+
syncRequested: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SmartbillSyncRuntime {
|
|
10
|
+
client: ReturnType<typeof createSmartbillClient>;
|
|
11
|
+
logger: SmartbillLogger;
|
|
12
|
+
mapEvent: SmartbillMapFn;
|
|
13
|
+
eventNames: ResolvedSmartbillSyncEventNames;
|
|
14
|
+
}
|
|
15
|
+
export declare function createSmartbillSyncRuntime(options: SmartbillPluginOptions): SmartbillSyncRuntime;
|
|
16
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAEnD,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAG1F,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAA;IAChD,MAAM,EAAE,eAAe,CAAA;IACvB,QAAQ,EAAE,cAAc,CAAA;IACxB,UAAU,EAAE,+BAA+B,CAAA;CAC5C;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,sBAAsB,GAAG,oBAAoB,CA0BhG"}
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createSmartbillClient } from "./client.js";
|
|
2
|
+
import { mapVoyantInvoiceToSmartbill } from "./mapping.js";
|
|
3
|
+
export function createSmartbillSyncRuntime(options) {
|
|
4
|
+
const client = createSmartbillClient(options);
|
|
5
|
+
const logger = options.logger ?? console;
|
|
6
|
+
const mappingOptions = {
|
|
7
|
+
companyVatCode: options.companyVatCode,
|
|
8
|
+
seriesName: options.seriesName,
|
|
9
|
+
language: options.language,
|
|
10
|
+
isTaxIncluded: options.isTaxIncluded,
|
|
11
|
+
art311SpecialRegime: options.art311SpecialRegime,
|
|
12
|
+
};
|
|
13
|
+
const mapEvent = options.mapEvent ??
|
|
14
|
+
((event) => mapVoyantInvoiceToSmartbill(event, mappingOptions));
|
|
15
|
+
const eventNames = {
|
|
16
|
+
issued: options.events?.issued ?? "invoice.issued",
|
|
17
|
+
proformaIssued: options.events?.proformaIssued ?? "invoice.proforma.issued",
|
|
18
|
+
voided: options.events?.voided ?? "invoice.voided",
|
|
19
|
+
syncRequested: options.events?.syncRequested ?? "invoice.external.sync.requested",
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
client,
|
|
23
|
+
logger,
|
|
24
|
+
mapEvent,
|
|
25
|
+
eventNames,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { SmartbillClientOptions } from "./client.js";
|
|
2
|
+
export interface SmartbillInvoiceSettlementPollerOptions extends SmartbillClientOptions {
|
|
3
|
+
companyVatCode?: string;
|
|
4
|
+
seriesName?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface SmartbillSettlementInvoice {
|
|
7
|
+
invoiceNumber: string;
|
|
8
|
+
}
|
|
9
|
+
export interface SmartbillSettlementExternalRef {
|
|
10
|
+
externalId: string | null;
|
|
11
|
+
externalNumber: string | null;
|
|
12
|
+
metadata?: unknown;
|
|
13
|
+
}
|
|
14
|
+
export interface SmartbillSettlementPollerContext {
|
|
15
|
+
invoice: SmartbillSettlementInvoice;
|
|
16
|
+
externalRef: SmartbillSettlementExternalRef;
|
|
17
|
+
}
|
|
18
|
+
export interface SmartbillSettlementPollerResult {
|
|
19
|
+
externalId?: string | null;
|
|
20
|
+
externalNumber?: string | null;
|
|
21
|
+
status?: string | null;
|
|
22
|
+
paidAmountCents?: number | null;
|
|
23
|
+
unpaidAmountCents?: number | null;
|
|
24
|
+
settledAt?: string | null;
|
|
25
|
+
syncError?: string | null;
|
|
26
|
+
metadata?: Record<string, unknown> | null;
|
|
27
|
+
}
|
|
28
|
+
export type SmartbillInvoiceSettlementPoller = (context: SmartbillSettlementPollerContext) => Promise<SmartbillSettlementPollerResult>;
|
|
29
|
+
export declare function createSmartbillInvoiceSettlementPoller(options: SmartbillInvoiceSettlementPollerOptions): SmartbillInvoiceSettlementPoller;
|
|
30
|
+
//# sourceMappingURL=settlement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"settlement.d.ts","sourceRoot":"","sources":["../src/settlement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAGzD,MAAM,WAAW,uCAAwC,SAAQ,sBAAsB;IACrF,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,0BAA0B;IACzC,aAAa,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,8BAA8B;IAC7C,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,0BAA0B,CAAA;IACnC,WAAW,EAAE,8BAA8B,CAAA;CAC5C;AAED,MAAM,WAAW,+BAA+B;IAC9C,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;CAC1C;AAED,MAAM,MAAM,gCAAgC,GAAG,CAC7C,OAAO,EAAE,gCAAgC,KACtC,OAAO,CAAC,+BAA+B,CAAC,CAAA;AAuD7C,wBAAgB,sCAAsC,CACpD,OAAO,EAAE,uCAAuC,GAC/C,gCAAgC,CA0ClC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { createSmartbillClient } from "./client.js";
|
|
2
|
+
function coerceString(value) {
|
|
3
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
4
|
+
}
|
|
5
|
+
function coerceMetadata(value) {
|
|
6
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
7
|
+
? value
|
|
8
|
+
: null;
|
|
9
|
+
}
|
|
10
|
+
function resolveCompanyVatCode(metadata, options) {
|
|
11
|
+
return (coerceString(metadata?.companyVatCode) ??
|
|
12
|
+
coerceString(metadata?.vatCode) ??
|
|
13
|
+
options.companyVatCode ??
|
|
14
|
+
null);
|
|
15
|
+
}
|
|
16
|
+
function resolveSeriesName(metadata, options) {
|
|
17
|
+
return (coerceString(metadata?.seriesName) ??
|
|
18
|
+
coerceString(metadata?.series) ??
|
|
19
|
+
options.seriesName ??
|
|
20
|
+
null);
|
|
21
|
+
}
|
|
22
|
+
function resolveInvoiceNumber(metadata, externalNumber, externalId, invoiceNumber) {
|
|
23
|
+
return (coerceString(metadata?.number) ??
|
|
24
|
+
coerceString(metadata?.invoiceNumber) ??
|
|
25
|
+
externalNumber ??
|
|
26
|
+
externalId ??
|
|
27
|
+
invoiceNumber);
|
|
28
|
+
}
|
|
29
|
+
function toCents(value) {
|
|
30
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.round(value * 100) : null;
|
|
31
|
+
}
|
|
32
|
+
export function createSmartbillInvoiceSettlementPoller(options) {
|
|
33
|
+
const client = createSmartbillClient(options);
|
|
34
|
+
return async ({ invoice, externalRef }) => {
|
|
35
|
+
const metadata = coerceMetadata(externalRef.metadata);
|
|
36
|
+
const companyVatCode = resolveCompanyVatCode(metadata, options);
|
|
37
|
+
const seriesName = resolveSeriesName(metadata, options);
|
|
38
|
+
const number = resolveInvoiceNumber(metadata, externalRef.externalNumber, externalRef.externalId, invoice.invoiceNumber);
|
|
39
|
+
if (!companyVatCode) {
|
|
40
|
+
return { syncError: "SmartBill settlement polling requires companyVatCode" };
|
|
41
|
+
}
|
|
42
|
+
if (!seriesName) {
|
|
43
|
+
return { syncError: "SmartBill settlement polling requires seriesName" };
|
|
44
|
+
}
|
|
45
|
+
const status = await client.getPaymentStatus(companyVatCode, seriesName, number);
|
|
46
|
+
return {
|
|
47
|
+
externalId: externalRef.externalId ?? null,
|
|
48
|
+
externalNumber: number,
|
|
49
|
+
status: status.status ?? null,
|
|
50
|
+
paidAmountCents: toCents(status.paidAmount),
|
|
51
|
+
unpaidAmountCents: toCents(status.unpaidAmount),
|
|
52
|
+
settledAt: status.status === "paid" && typeof status.paidAmount === "number" && status.paidAmount > 0
|
|
53
|
+
? new Date().toISOString()
|
|
54
|
+
: null,
|
|
55
|
+
syncError: status.errorText ?? null,
|
|
56
|
+
metadata: {
|
|
57
|
+
...(metadata ?? {}),
|
|
58
|
+
companyVatCode,
|
|
59
|
+
seriesName,
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
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
|
+
taxName?: string;
|
|
23
|
+
taxPercentage?: number;
|
|
24
|
+
isService?: boolean;
|
|
25
|
+
saveToDb?: boolean;
|
|
26
|
+
warehouseName?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* SmartBill invoice client.
|
|
30
|
+
*/
|
|
31
|
+
export interface SmartbillClient {
|
|
32
|
+
name: string;
|
|
33
|
+
vatCode?: string;
|
|
34
|
+
regCom?: string;
|
|
35
|
+
address?: string;
|
|
36
|
+
city?: string;
|
|
37
|
+
county?: string;
|
|
38
|
+
country?: string;
|
|
39
|
+
isTaxPayer?: boolean;
|
|
40
|
+
email?: string;
|
|
41
|
+
phone?: string;
|
|
42
|
+
contact?: string;
|
|
43
|
+
saveToDb?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* SmartBill invoice body as accepted by the `POST /invoice` endpoint.
|
|
47
|
+
*/
|
|
48
|
+
export interface SmartbillInvoiceBody {
|
|
49
|
+
companyVatCode: string;
|
|
50
|
+
client: SmartbillClient;
|
|
51
|
+
seriesName: string;
|
|
52
|
+
isDraft?: boolean;
|
|
53
|
+
currency: string;
|
|
54
|
+
language?: string;
|
|
55
|
+
dueDate?: string;
|
|
56
|
+
issueDate?: string;
|
|
57
|
+
deliveryDate?: string;
|
|
58
|
+
precision?: number;
|
|
59
|
+
useEstimateDetails?: boolean;
|
|
60
|
+
mentions?: string;
|
|
61
|
+
observations?: string;
|
|
62
|
+
products: SmartbillProduct[];
|
|
63
|
+
usePaymentTax?: boolean;
|
|
64
|
+
payment?: {
|
|
65
|
+
type: string;
|
|
66
|
+
value: number;
|
|
67
|
+
isCash: boolean;
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* SmartBill API response for invoice creation.
|
|
72
|
+
*/
|
|
73
|
+
export interface SmartbillInvoiceResponse {
|
|
74
|
+
number?: string;
|
|
75
|
+
series?: string;
|
|
76
|
+
url?: string;
|
|
77
|
+
errorText?: string;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* SmartBill API response for PDF download.
|
|
81
|
+
*/
|
|
82
|
+
export interface SmartbillPdfResponse {
|
|
83
|
+
url?: string;
|
|
84
|
+
errorText?: string;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* SmartBill API response for invoice status.
|
|
88
|
+
*/
|
|
89
|
+
export interface SmartbillStatusResponse {
|
|
90
|
+
status?: string;
|
|
91
|
+
paidAmount?: number;
|
|
92
|
+
unpaidAmount?: number;
|
|
93
|
+
errorText?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Minimal `fetch` shape the SmartBill client depends on. Works with the global
|
|
97
|
+
* `fetch` in Node 18+ / Cloudflare Workers / browsers, and is trivially
|
|
98
|
+
* stubbable in tests.
|
|
99
|
+
*/
|
|
100
|
+
export type SmartbillFetch = (input: string, init: {
|
|
101
|
+
method: string;
|
|
102
|
+
headers: Record<string, string>;
|
|
103
|
+
body?: string;
|
|
104
|
+
}) => Promise<{
|
|
105
|
+
ok: boolean;
|
|
106
|
+
status: number;
|
|
107
|
+
json: () => Promise<unknown>;
|
|
108
|
+
text: () => Promise<string>;
|
|
109
|
+
}>;
|
|
110
|
+
//# 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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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { SmartbillLogger, SmartbillMapFn, SmartbillSyncEventNames } from "./plugin.js";
|
|
3
|
+
import type { SmartbillFetch } from "./types.js";
|
|
4
|
+
export declare const smartbillPluginOptionsSchema: z.ZodObject<{
|
|
5
|
+
username: z.ZodString;
|
|
6
|
+
apiToken: z.ZodString;
|
|
7
|
+
companyVatCode: z.ZodString;
|
|
8
|
+
seriesName: z.ZodString;
|
|
9
|
+
apiUrl: z.ZodOptional<z.ZodString>;
|
|
10
|
+
fetch: z.ZodOptional<z.ZodCustom<SmartbillFetch | undefined, SmartbillFetch | undefined>>;
|
|
11
|
+
language: z.ZodOptional<z.ZodString>;
|
|
12
|
+
isTaxIncluded: z.ZodOptional<z.ZodBoolean>;
|
|
13
|
+
art311SpecialRegime: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
events: z.ZodOptional<z.ZodCustom<SmartbillSyncEventNames | undefined, SmartbillSyncEventNames | undefined>>;
|
|
15
|
+
mapEvent: z.ZodOptional<z.ZodCustom<SmartbillMapFn | undefined, SmartbillMapFn | undefined>>;
|
|
16
|
+
logger: z.ZodOptional<z.ZodCustom<SmartbillLogger | undefined, SmartbillLogger | undefined>>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAEd,uBAAuB,EACxB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAmChD,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;iBAaK,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const optionalString = z.string().trim().min(1).optional();
|
|
3
|
+
const optionalUrl = z.string().trim().url().optional();
|
|
4
|
+
const optionalFetch = z.custom((value) => value === undefined || typeof value === "function", "Expected a fetch implementation function");
|
|
5
|
+
const optionalLogger = z.custom((value) => value === undefined ||
|
|
6
|
+
(typeof value === "object" &&
|
|
7
|
+
value !== null &&
|
|
8
|
+
typeof value.error === "function" &&
|
|
9
|
+
((value.info ?? undefined) === undefined ||
|
|
10
|
+
typeof value.info === "function")), "Expected a logger with an error function");
|
|
11
|
+
const optionalMapEvent = z.custom((value) => value === undefined || typeof value === "function", "Expected a mapEvent function");
|
|
12
|
+
const optionalEvents = z.custom((value) => {
|
|
13
|
+
if (value === undefined)
|
|
14
|
+
return true;
|
|
15
|
+
if (typeof value !== "object" || value === null)
|
|
16
|
+
return false;
|
|
17
|
+
const events = value;
|
|
18
|
+
return [events.issued, events.voided, events.syncRequested].every((entry) => entry === undefined || (typeof entry === "string" && entry.trim().length > 0));
|
|
19
|
+
}, "Expected event names to be non-empty strings");
|
|
20
|
+
export const smartbillPluginOptionsSchema = z.object({
|
|
21
|
+
username: z.string().trim().min(1),
|
|
22
|
+
apiToken: z.string().trim().min(1),
|
|
23
|
+
companyVatCode: z.string().trim().min(1),
|
|
24
|
+
seriesName: z.string().trim().min(1),
|
|
25
|
+
apiUrl: optionalUrl,
|
|
26
|
+
fetch: optionalFetch.optional(),
|
|
27
|
+
language: optionalString,
|
|
28
|
+
isTaxIncluded: z.boolean().optional(),
|
|
29
|
+
art311SpecialRegime: z.boolean().optional(),
|
|
30
|
+
events: optionalEvents.optional(),
|
|
31
|
+
mapEvent: optionalMapEvent.optional(),
|
|
32
|
+
logger: optionalLogger.optional(),
|
|
33
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/plugin-smartbill",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"zod": "^4.3.6",
|
|
35
|
-
"@voyantjs/core": "0.24.
|
|
35
|
+
"@voyantjs/core": "0.24.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
38
|
"typescript": "^6.0.2",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"lint": "biome check src/",
|
|
56
56
|
"test": "vitest run",
|
|
57
57
|
"build": "pnpm run clean && tsc -p tsconfig.json",
|
|
58
|
-
"clean": "rm -rf dist"
|
|
58
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo"
|
|
59
59
|
},
|
|
60
60
|
"main": "./dist/index.js",
|
|
61
61
|
"types": "./dist/index.d.ts"
|