@voyantjs/plugin-smartbill 0.31.2 → 0.31.4
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/README.md +16 -1
- package/dist/artifacts.d.ts +101 -0
- package/dist/artifacts.d.ts.map +1 -0
- package/dist/artifacts.js +114 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/plugin.d.ts +14 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +28 -4
- package/dist/runtime.d.ts +2 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +5 -0
- package/dist/validation.d.ts +5 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +31 -1
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -29,6 +29,10 @@ const smartbillSync = smartbillPlugin({
|
|
|
29
29
|
companyVatCode: "RO12345678",
|
|
30
30
|
seriesName: "A",
|
|
31
31
|
// optional: language, art311SpecialRegime, events, mapEvent, logger
|
|
32
|
+
artifacts: {
|
|
33
|
+
db: appDb,
|
|
34
|
+
documentStorage,
|
|
35
|
+
},
|
|
32
36
|
})
|
|
33
37
|
|
|
34
38
|
const app = createApp({
|
|
@@ -38,11 +42,22 @@ const app = createApp({
|
|
|
38
42
|
|
|
39
43
|
`smartbillPlugin(...)` is the packaged distribution helper. At runtime, the
|
|
40
44
|
package behaves primarily as a subscriber-driven SmartBill sync adapter. By
|
|
41
|
-
default it wires up
|
|
45
|
+
default it wires up 4 subscribers (`invoice.issued`,
|
|
46
|
+
`invoice.proforma.issued`, `invoice.voided`,
|
|
42
47
|
`invoice.external.sync.requested`) that create, cancel, and check payment
|
|
43
48
|
status on SmartBill. All error handling is fire-and-forget per the EventBus
|
|
44
49
|
contract.
|
|
45
50
|
|
|
51
|
+
When `artifacts.db` is configured, successful invoice/proforma creation also
|
|
52
|
+
registers the SmartBill external reference through `@voyantjs/finance`. When
|
|
53
|
+
`artifacts.documentStorage` is configured, the plugin downloads the generated
|
|
54
|
+
SmartBill PDF, uploads it to document storage, and records both a ready
|
|
55
|
+
`invoice_renditions` row and a `smartbill_pdf` `invoice_attachments` row. The
|
|
56
|
+
upload path defaults to `invoices/<invoiceId>/smartbill/...`; pass
|
|
57
|
+
`artifacts.documentStorageKeyPrefix` to customize it. Existing
|
|
58
|
+
`smartbill_pdf` attachments are reused so repeat event delivery does not upload
|
|
59
|
+
the same PDF again.
|
|
60
|
+
|
|
46
61
|
## Exports
|
|
47
62
|
|
|
48
63
|
| Entry | Description |
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { StorageProvider } from "@voyantjs/storage";
|
|
2
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
|
+
import type { SmartbillClientApi } from "./client.js";
|
|
4
|
+
import type { SmartbillInvoiceBody, SmartbillInvoiceResponse, VoyantInvoiceEvent } from "./types.js";
|
|
5
|
+
export type SmartbillDocumentType = "invoice" | "proforma";
|
|
6
|
+
export interface SmartbillArtifactStorageContext {
|
|
7
|
+
event: VoyantInvoiceEvent;
|
|
8
|
+
documentType: SmartbillDocumentType;
|
|
9
|
+
body: SmartbillInvoiceBody;
|
|
10
|
+
result: SmartbillInvoiceResponse;
|
|
11
|
+
}
|
|
12
|
+
export type SmartbillDbResolver = PostgresJsDatabase | ((context: SmartbillArtifactStorageContext) => PostgresJsDatabase | null | Promise<PostgresJsDatabase | null>);
|
|
13
|
+
export type SmartbillDocumentStorageResolver = StorageProvider | null | ((context: SmartbillArtifactStorageContext) => StorageProvider | null | Promise<StorageProvider | null>);
|
|
14
|
+
export type SmartbillStorageKeyPrefixResolver = string | ((context: SmartbillArtifactStorageContext) => string | Promise<string>);
|
|
15
|
+
export interface SmartbillArtifactPersistenceOptions {
|
|
16
|
+
db?: SmartbillDbResolver;
|
|
17
|
+
documentStorage?: SmartbillDocumentStorageResolver;
|
|
18
|
+
documentStorageKeyPrefix?: SmartbillStorageKeyPrefixResolver;
|
|
19
|
+
}
|
|
20
|
+
export interface SmartbillArtifactPersistenceRuntime {
|
|
21
|
+
db?: SmartbillDbResolver;
|
|
22
|
+
documentStorage?: SmartbillDocumentStorageResolver;
|
|
23
|
+
documentStorageKeyPrefix?: SmartbillStorageKeyPrefixResolver;
|
|
24
|
+
}
|
|
25
|
+
export interface PersistSmartbillInvoiceArtifactInput {
|
|
26
|
+
runtime: SmartbillArtifactPersistenceRuntime;
|
|
27
|
+
client: SmartbillClientApi;
|
|
28
|
+
event: VoyantInvoiceEvent;
|
|
29
|
+
documentType: SmartbillDocumentType;
|
|
30
|
+
body: SmartbillInvoiceBody;
|
|
31
|
+
result: SmartbillInvoiceResponse;
|
|
32
|
+
}
|
|
33
|
+
export declare function persistSmartbillInvoiceArtifact({ runtime, client, event, documentType, body, result, }: PersistSmartbillInvoiceArtifactInput): Promise<{
|
|
34
|
+
status: "skipped";
|
|
35
|
+
reason: "missing_db";
|
|
36
|
+
attachment?: undefined;
|
|
37
|
+
rendition?: undefined;
|
|
38
|
+
} | {
|
|
39
|
+
status: "skipped";
|
|
40
|
+
reason: "missing_invoice";
|
|
41
|
+
attachment?: undefined;
|
|
42
|
+
rendition?: undefined;
|
|
43
|
+
} | {
|
|
44
|
+
status: "registered_ref";
|
|
45
|
+
reason?: undefined;
|
|
46
|
+
attachment?: undefined;
|
|
47
|
+
rendition?: undefined;
|
|
48
|
+
} | {
|
|
49
|
+
status: "registered_ref";
|
|
50
|
+
reason: "missing_number";
|
|
51
|
+
attachment?: undefined;
|
|
52
|
+
rendition?: undefined;
|
|
53
|
+
} | {
|
|
54
|
+
status: "already_exists";
|
|
55
|
+
attachment: {
|
|
56
|
+
id: string;
|
|
57
|
+
invoiceId: string;
|
|
58
|
+
kind: string;
|
|
59
|
+
name: string;
|
|
60
|
+
mimeType: string | null;
|
|
61
|
+
fileSize: number | null;
|
|
62
|
+
storageKey: string | null;
|
|
63
|
+
checksum: string | null;
|
|
64
|
+
metadata: unknown;
|
|
65
|
+
createdAt: Date;
|
|
66
|
+
};
|
|
67
|
+
reason?: undefined;
|
|
68
|
+
rendition?: undefined;
|
|
69
|
+
} | {
|
|
70
|
+
status: "persisted";
|
|
71
|
+
rendition: {
|
|
72
|
+
metadata: unknown;
|
|
73
|
+
id: string;
|
|
74
|
+
createdAt: Date;
|
|
75
|
+
updatedAt: Date;
|
|
76
|
+
status: "pending" | "failed" | "ready" | "stale";
|
|
77
|
+
format: "json" | "pdf" | "html" | "xml";
|
|
78
|
+
errorMessage: string | null;
|
|
79
|
+
templateId: string | null;
|
|
80
|
+
language: string | null;
|
|
81
|
+
invoiceId: string;
|
|
82
|
+
storageKey: string | null;
|
|
83
|
+
fileSize: number | null;
|
|
84
|
+
checksum: string | null;
|
|
85
|
+
generatedAt: Date | null;
|
|
86
|
+
} | null;
|
|
87
|
+
attachment: {
|
|
88
|
+
metadata: unknown;
|
|
89
|
+
name: string;
|
|
90
|
+
id: string;
|
|
91
|
+
createdAt: Date;
|
|
92
|
+
kind: string;
|
|
93
|
+
invoiceId: string;
|
|
94
|
+
storageKey: string | null;
|
|
95
|
+
fileSize: number | null;
|
|
96
|
+
checksum: string | null;
|
|
97
|
+
mimeType: string | null;
|
|
98
|
+
} | null;
|
|
99
|
+
reason?: undefined;
|
|
100
|
+
}>;
|
|
101
|
+
//# sourceMappingURL=artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../src/artifacts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAEjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAEpG,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,UAAU,CAAA;AAE1D,MAAM,WAAW,+BAA+B;IAC9C,KAAK,EAAE,kBAAkB,CAAA;IACzB,YAAY,EAAE,qBAAqB,CAAA;IACnC,IAAI,EAAE,oBAAoB,CAAA;IAC1B,MAAM,EAAE,wBAAwB,CAAA;CACjC;AAED,MAAM,MAAM,mBAAmB,GAC3B,kBAAkB,GAClB,CAAC,CACC,OAAO,EAAE,+BAA+B,KACrC,kBAAkB,GAAG,IAAI,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,CAAA;AAExE,MAAM,MAAM,gCAAgC,GACxC,eAAe,GACf,IAAI,GACJ,CAAC,CACC,OAAO,EAAE,+BAA+B,KACrC,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC,CAAA;AAElE,MAAM,MAAM,iCAAiC,GACzC,MAAM,GACN,CAAC,CAAC,OAAO,EAAE,+BAA+B,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAA;AAE5E,MAAM,WAAW,mCAAmC;IAClD,EAAE,CAAC,EAAE,mBAAmB,CAAA;IACxB,eAAe,CAAC,EAAE,gCAAgC,CAAA;IAClD,wBAAwB,CAAC,EAAE,iCAAiC,CAAA;CAC7D;AAED,MAAM,WAAW,mCAAmC;IAClD,EAAE,CAAC,EAAE,mBAAmB,CAAA;IACxB,eAAe,CAAC,EAAE,gCAAgC,CAAA;IAClD,wBAAwB,CAAC,EAAE,iCAAiC,CAAA;CAC7D;AAED,MAAM,WAAW,oCAAoC;IACnD,OAAO,EAAE,mCAAmC,CAAA;IAC5C,MAAM,EAAE,kBAAkB,CAAA;IAC1B,KAAK,EAAE,kBAAkB,CAAA;IACzB,YAAY,EAAE,qBAAqB,CAAA;IACnC,IAAI,EAAE,oBAAoB,CAAA;IAC1B,MAAM,EAAE,wBAAwB,CAAA;CACjC;AAwCD,wBAAsB,+BAA+B,CAAC,EACpD,OAAO,EACP,MAAM,EACN,KAAK,EACL,YAAY,EACZ,IAAI,EACJ,MAAM,GACP,EAAE,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiGtC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { financeService } from "@voyantjs/finance";
|
|
2
|
+
const SMARTBILL_ATTACHMENT_KIND = "smartbill_pdf";
|
|
3
|
+
function isResolver(value) {
|
|
4
|
+
return typeof value === "function";
|
|
5
|
+
}
|
|
6
|
+
async function resolveMaybe(value, context) {
|
|
7
|
+
return isResolver(value) ? await value(context) : value;
|
|
8
|
+
}
|
|
9
|
+
function sanitizeKeyPart(value) {
|
|
10
|
+
return value.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "document";
|
|
11
|
+
}
|
|
12
|
+
async function sha256(bytes) {
|
|
13
|
+
const crypto = globalThis.crypto;
|
|
14
|
+
if (!crypto?.subtle)
|
|
15
|
+
return null;
|
|
16
|
+
const buffer = new ArrayBuffer(bytes.byteLength);
|
|
17
|
+
new Uint8Array(buffer).set(bytes);
|
|
18
|
+
const digest = await crypto.subtle.digest("SHA-256", buffer);
|
|
19
|
+
return `sha256:${Array.from(new Uint8Array(digest))
|
|
20
|
+
.map((byte) => byte.toString(16).padStart(2, "0"))
|
|
21
|
+
.join("")}`;
|
|
22
|
+
}
|
|
23
|
+
function smartbillAttachmentName(documentType, seriesName, number) {
|
|
24
|
+
return `SmartBill ${documentType} ${seriesName}-${number}.pdf`;
|
|
25
|
+
}
|
|
26
|
+
export async function persistSmartbillInvoiceArtifact({ runtime, client, event, documentType, body, result, }) {
|
|
27
|
+
if (!runtime.db)
|
|
28
|
+
return { status: "skipped", reason: "missing_db" };
|
|
29
|
+
const context = { event, documentType, body, result };
|
|
30
|
+
const db = await resolveMaybe(runtime.db, context);
|
|
31
|
+
if (!db)
|
|
32
|
+
return { status: "skipped", reason: "missing_db" };
|
|
33
|
+
const seriesName = result.series ?? body.seriesName;
|
|
34
|
+
const number = result.number;
|
|
35
|
+
const externalRef = await financeService.registerInvoiceExternalRef(db, event.id, {
|
|
36
|
+
provider: "smartbill",
|
|
37
|
+
externalId: number ?? null,
|
|
38
|
+
externalNumber: number ?? null,
|
|
39
|
+
externalUrl: result.url ?? null,
|
|
40
|
+
status: result.errorText ? "error" : "issued",
|
|
41
|
+
syncedAt: new Date().toISOString(),
|
|
42
|
+
syncError: result.errorText ?? null,
|
|
43
|
+
metadata: {
|
|
44
|
+
companyVatCode: body.companyVatCode,
|
|
45
|
+
seriesName: body.seriesName,
|
|
46
|
+
series: seriesName,
|
|
47
|
+
number: number ?? null,
|
|
48
|
+
documentType,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (!externalRef)
|
|
52
|
+
return { status: "skipped", reason: "missing_invoice" };
|
|
53
|
+
const storage = await resolveMaybe(runtime.documentStorage, context);
|
|
54
|
+
if (!storage)
|
|
55
|
+
return { status: "registered_ref" };
|
|
56
|
+
if (!number)
|
|
57
|
+
return { status: "registered_ref", reason: "missing_number" };
|
|
58
|
+
const existingAttachments = await financeService.listInvoiceAttachments(db, event.id);
|
|
59
|
+
const existingSmartbillAttachment = existingAttachments.find((attachment) => attachment.kind === SMARTBILL_ATTACHMENT_KIND);
|
|
60
|
+
if (existingSmartbillAttachment) {
|
|
61
|
+
return { status: "already_exists", attachment: existingSmartbillAttachment };
|
|
62
|
+
}
|
|
63
|
+
const pdf = documentType === "proforma"
|
|
64
|
+
? await client.viewEstimatePdf(body.companyVatCode, seriesName, number)
|
|
65
|
+
: await client.viewInvoicePdf(body.companyVatCode, seriesName, number);
|
|
66
|
+
const defaultPrefix = `invoices/${event.id}/smartbill`;
|
|
67
|
+
const keyPrefix = (await resolveMaybe(runtime.documentStorageKeyPrefix, context)) ?? defaultPrefix;
|
|
68
|
+
const key = `${keyPrefix.replace(/\/$/, "")}/${documentType}-${sanitizeKeyPart(seriesName)}-${sanitizeKeyPart(number)}.pdf`;
|
|
69
|
+
const contentType = pdf.contentType || "application/pdf";
|
|
70
|
+
const checksum = await sha256(pdf.bytes);
|
|
71
|
+
const uploaded = await storage.upload(pdf.bytes, {
|
|
72
|
+
key,
|
|
73
|
+
contentType,
|
|
74
|
+
metadata: {
|
|
75
|
+
provider: "smartbill",
|
|
76
|
+
documentType,
|
|
77
|
+
invoiceId: event.id,
|
|
78
|
+
seriesName,
|
|
79
|
+
number,
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
const commonMetadata = {
|
|
83
|
+
provider: "smartbill",
|
|
84
|
+
documentType,
|
|
85
|
+
companyVatCode: body.companyVatCode,
|
|
86
|
+
seriesName,
|
|
87
|
+
number,
|
|
88
|
+
storageProvider: storage.name,
|
|
89
|
+
...(uploaded.url ? { url: uploaded.url } : {}),
|
|
90
|
+
};
|
|
91
|
+
const rendition = await financeService.createInvoiceRendition(db, event.id, {
|
|
92
|
+
format: "pdf",
|
|
93
|
+
status: "ready",
|
|
94
|
+
storageKey: uploaded.key,
|
|
95
|
+
fileSize: pdf.bytes.byteLength,
|
|
96
|
+
checksum,
|
|
97
|
+
language: body.language ?? null,
|
|
98
|
+
generatedAt: new Date().toISOString(),
|
|
99
|
+
metadata: commonMetadata,
|
|
100
|
+
});
|
|
101
|
+
const attachment = await financeService.createInvoiceAttachment(db, event.id, {
|
|
102
|
+
kind: SMARTBILL_ATTACHMENT_KIND,
|
|
103
|
+
name: smartbillAttachmentName(documentType, seriesName, number),
|
|
104
|
+
mimeType: contentType,
|
|
105
|
+
fileSize: pdf.bytes.byteLength,
|
|
106
|
+
storageKey: uploaded.key,
|
|
107
|
+
checksum,
|
|
108
|
+
metadata: {
|
|
109
|
+
...commonMetadata,
|
|
110
|
+
renditionId: rendition?.id ?? null,
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
return { status: "persisted", rendition, attachment };
|
|
114
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type { SmartbillArtifactPersistenceOptions, SmartbillArtifactStorageContext, SmartbillDbResolver, SmartbillDocumentStorageResolver, SmartbillDocumentType, SmartbillStorageKeyPrefixResolver, } from "./artifacts.js";
|
|
1
2
|
export type { SmartbillClientApi, SmartbillClientOptions } from "./client.js";
|
|
2
3
|
export { createSmartbillClient } from "./client.js";
|
|
3
4
|
export type { SmartbillMappingOptions } from "./mapping.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +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,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrD,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,iBAAiB,EACjB,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,mCAAmC,EACnC,+BAA+B,EAC/B,mBAAmB,EACnB,gCAAgC,EAChC,qBAAqB,EACrB,iCAAiC,GAClC,MAAM,gBAAgB,CAAA;AACvB,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,qBAAqB,EACrB,yBAAyB,EACzB,2BAA2B,EAC3B,0BAA0B,EAC1B,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,yBAAyB,EACzB,0BAA0B,EAC1B,gBAAgB,GACjB,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AACrD,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,iBAAiB,EACjB,iCAAiC,EACjC,cAAc,EACd,oBAAoB,EACpB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,YAAY,CAAA"}
|
package/dist/plugin.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from "@voyantjs/core";
|
|
2
|
+
import { type SmartbillArtifactPersistenceOptions } from "./artifacts.js";
|
|
2
3
|
import type { SmartbillClientOptions } from "./client.js";
|
|
3
4
|
import type { mapVoyantInvoiceToSmartbill, SmartbillMappingOptions } from "./mapping.js";
|
|
4
5
|
import type { VoyantInvoiceEvent } from "./types.js";
|
|
@@ -17,6 +18,19 @@ export interface SmartbillPluginOptions extends SmartbillClientOptions, Smartbil
|
|
|
17
18
|
events?: SmartbillSyncEventNames;
|
|
18
19
|
mapEvent?: SmartbillMapFn;
|
|
19
20
|
logger?: SmartbillLogger;
|
|
21
|
+
/**
|
|
22
|
+
* Optional finance artifact persistence. When `db` is supplied, the plugin
|
|
23
|
+
* registers the SmartBill external ref after creation. When
|
|
24
|
+
* `documentStorage` is also supplied, it downloads and stores the generated
|
|
25
|
+
* SmartBill PDF as both an invoice rendition and attachment.
|
|
26
|
+
*/
|
|
27
|
+
artifacts?: SmartbillArtifactPersistenceOptions;
|
|
28
|
+
/** @deprecated Use `artifacts.db`. */
|
|
29
|
+
db?: SmartbillArtifactPersistenceOptions["db"];
|
|
30
|
+
/** @deprecated Use `artifacts.documentStorage`. */
|
|
31
|
+
documentStorage?: SmartbillArtifactPersistenceOptions["documentStorage"];
|
|
32
|
+
/** @deprecated Use `artifacts.documentStorageKeyPrefix`. */
|
|
33
|
+
documentStorageKeyPrefix?: SmartbillArtifactPersistenceOptions["documentStorageKeyPrefix"];
|
|
20
34
|
}
|
|
21
35
|
export declare function smartbillPlugin(options: SmartbillPluginOptions): Plugin;
|
|
22
36
|
//# sourceMappingURL=plugin.d.ts.map
|
package/dist/plugin.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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,EAEL,KAAK,mCAAmC,EAEzC,MAAM,gBAAgB,CAAA;AACvB,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;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,mCAAmC,CAAA;IAC/C,sCAAsC;IACtC,EAAE,CAAC,EAAE,mCAAmC,CAAC,IAAI,CAAC,CAAA;IAC9C,mDAAmD;IACnD,eAAe,CAAC,EAAE,mCAAmC,CAAC,iBAAiB,CAAC,CAAA;IACxE,4DAA4D;IAC5D,wBAAwB,CAAC,EAAE,mCAAmC,CAAC,0BAA0B,CAAC,CAAA;CAC3F;AAYD,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,MAAM,CAwJvE"}
|
package/dist/plugin.js
CHANGED
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
import { ZodError } from "zod";
|
|
2
|
+
import { persistSmartbillInvoiceArtifact, } from "./artifacts.js";
|
|
2
3
|
import { createSmartbillSyncRuntime } from "./runtime.js";
|
|
3
4
|
import { smartbillPluginOptionsSchema } from "./validation.js";
|
|
4
5
|
function coerceEvent(data) {
|
|
5
6
|
if (data == null || typeof data !== "object")
|
|
6
7
|
return null;
|
|
7
8
|
const maybe = data;
|
|
8
|
-
if (typeof maybe.id
|
|
9
|
-
return
|
|
10
|
-
|
|
9
|
+
if (typeof maybe.id === "string")
|
|
10
|
+
return maybe;
|
|
11
|
+
if (typeof maybe.invoiceId === "string") {
|
|
12
|
+
return { ...maybe, id: maybe.invoiceId };
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
11
15
|
}
|
|
12
16
|
export function smartbillPlugin(options) {
|
|
13
17
|
const validatedOptions = parseSmartbillPluginOptions(options);
|
|
14
|
-
const { client, logger, mapEvent, eventNames } = createSmartbillSyncRuntime(validatedOptions);
|
|
18
|
+
const { client, logger, mapEvent, eventNames, artifacts } = createSmartbillSyncRuntime(validatedOptions);
|
|
19
|
+
async function persistArtifact(event, documentType, body, result) {
|
|
20
|
+
try {
|
|
21
|
+
const persisted = await persistSmartbillInvoiceArtifact({
|
|
22
|
+
runtime: artifacts,
|
|
23
|
+
client,
|
|
24
|
+
event,
|
|
25
|
+
documentType,
|
|
26
|
+
body,
|
|
27
|
+
result,
|
|
28
|
+
});
|
|
29
|
+
if (persisted.status === "persisted") {
|
|
30
|
+
logger.info?.(`[smartbill] ${documentType} PDF persisted for ${event.id}`, persisted);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
logger.error(`[smartbill] artifact persistence failed for ${event.id}`, err);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
15
37
|
const subscribers = [
|
|
16
38
|
{
|
|
17
39
|
event: eventNames.issued,
|
|
@@ -23,6 +45,7 @@ export function smartbillPlugin(options) {
|
|
|
23
45
|
const body = mapEvent(event);
|
|
24
46
|
const result = await client.createInvoice(body);
|
|
25
47
|
logger.info?.(`[smartbill] invoice created: ${result.series}-${result.number} for ${event.id}`, result);
|
|
48
|
+
await persistArtifact(event, "invoice", body, result);
|
|
26
49
|
}
|
|
27
50
|
catch (err) {
|
|
28
51
|
logger.error(`[smartbill] createInvoice on "${eventNames.issued}" failed for ${event.id}`, err);
|
|
@@ -41,6 +64,7 @@ export function smartbillPlugin(options) {
|
|
|
41
64
|
const body = mapEvent(event);
|
|
42
65
|
const result = await client.createProforma(body);
|
|
43
66
|
logger.info?.(`[smartbill] proforma created: ${result.series}-${result.number} for ${event.id}`, result);
|
|
67
|
+
await persistArtifact(event, "proforma", body, result);
|
|
44
68
|
}
|
|
45
69
|
catch (err) {
|
|
46
70
|
logger.error(`[smartbill] createProforma on "${eventNames.proformaIssued}" failed for ${event.id}`, err);
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { SmartbillArtifactPersistenceOptions } from "./artifacts.js";
|
|
1
2
|
import { createSmartbillClient } from "./client.js";
|
|
2
3
|
import type { SmartbillLogger, SmartbillMapFn, SmartbillPluginOptions } from "./plugin.js";
|
|
3
4
|
export interface ResolvedSmartbillSyncEventNames {
|
|
@@ -11,6 +12,7 @@ export interface SmartbillSyncRuntime {
|
|
|
11
12
|
logger: SmartbillLogger;
|
|
12
13
|
mapEvent: SmartbillMapFn;
|
|
13
14
|
eventNames: ResolvedSmartbillSyncEventNames;
|
|
15
|
+
artifacts: SmartbillArtifactPersistenceOptions;
|
|
14
16
|
}
|
|
15
17
|
export declare function createSmartbillSyncRuntime(options: SmartbillPluginOptions): SmartbillSyncRuntime;
|
|
16
18
|
//# sourceMappingURL=runtime.d.ts.map
|
package/dist/runtime.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,gBAAgB,CAAA;AACzE,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;IAC3C,SAAS,EAAE,mCAAmC,CAAA;CAC/C;AAED,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,sBAAsB,GAAG,oBAAoB,CAgChG"}
|
package/dist/runtime.js
CHANGED
|
@@ -23,5 +23,10 @@ export function createSmartbillSyncRuntime(options) {
|
|
|
23
23
|
logger,
|
|
24
24
|
mapEvent,
|
|
25
25
|
eventNames,
|
|
26
|
+
artifacts: {
|
|
27
|
+
db: options.artifacts?.db ?? options.db,
|
|
28
|
+
documentStorage: options.artifacts?.documentStorage ?? options.documentStorage,
|
|
29
|
+
documentStorageKeyPrefix: options.artifacts?.documentStorageKeyPrefix ?? options.documentStorageKeyPrefix,
|
|
30
|
+
},
|
|
26
31
|
};
|
|
27
32
|
}
|
package/dist/validation.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { SmartbillArtifactPersistenceOptions, SmartbillDbResolver, SmartbillDocumentStorageResolver, SmartbillStorageKeyPrefixResolver } from "./artifacts.js";
|
|
2
3
|
import type { SmartbillLogger, SmartbillMapFn, SmartbillSyncEventNames } from "./plugin.js";
|
|
3
4
|
import type { SmartbillFetch } from "./types.js";
|
|
4
5
|
export declare const smartbillPluginOptionsSchema: z.ZodObject<{
|
|
@@ -14,5 +15,9 @@ export declare const smartbillPluginOptionsSchema: z.ZodObject<{
|
|
|
14
15
|
events: z.ZodOptional<z.ZodCustom<SmartbillSyncEventNames | undefined, SmartbillSyncEventNames | undefined>>;
|
|
15
16
|
mapEvent: z.ZodOptional<z.ZodCustom<SmartbillMapFn | undefined, SmartbillMapFn | undefined>>;
|
|
16
17
|
logger: z.ZodOptional<z.ZodCustom<SmartbillLogger | undefined, SmartbillLogger | undefined>>;
|
|
18
|
+
artifacts: z.ZodOptional<z.ZodCustom<SmartbillArtifactPersistenceOptions | undefined, SmartbillArtifactPersistenceOptions | undefined>>;
|
|
19
|
+
db: z.ZodOptional<z.ZodCustom<SmartbillDbResolver | undefined, SmartbillDbResolver | undefined>>;
|
|
20
|
+
documentStorage: z.ZodOptional<z.ZodCustom<SmartbillDocumentStorageResolver | undefined, SmartbillDocumentStorageResolver | undefined>>;
|
|
21
|
+
documentStorageKeyPrefix: z.ZodOptional<z.ZodCustom<SmartbillStorageKeyPrefixResolver | undefined, SmartbillStorageKeyPrefixResolver | undefined>>;
|
|
17
22
|
}, z.core.$strip>;
|
|
18
23
|
//# sourceMappingURL=validation.d.ts.map
|
package/dist/validation.d.ts.map
CHANGED
|
@@ -1 +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;
|
|
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,mCAAmC,EACnC,mBAAmB,EACnB,gCAAgC,EAChC,iCAAiC,EAClC,MAAM,gBAAgB,CAAA;AACvB,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAEd,uBAAuB,EACxB,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AA+EhD,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;iBAiBK,CAAA"}
|
package/dist/validation.js
CHANGED
|
@@ -9,13 +9,39 @@ const optionalLogger = z.custom((value) => value === undefined ||
|
|
|
9
9
|
((value.info ?? undefined) === undefined ||
|
|
10
10
|
typeof value.info === "function")), "Expected a logger with an error function");
|
|
11
11
|
const optionalMapEvent = z.custom((value) => value === undefined || typeof value === "function", "Expected a mapEvent function");
|
|
12
|
+
const optionalDb = z.custom((value) => value === undefined ||
|
|
13
|
+
typeof value === "function" ||
|
|
14
|
+
(typeof value === "object" && value !== null), "Expected a database handle or resolver function");
|
|
15
|
+
function isStorageProvider(value) {
|
|
16
|
+
return (typeof value === "object" &&
|
|
17
|
+
value !== null &&
|
|
18
|
+
typeof value.upload === "function" &&
|
|
19
|
+
typeof value.delete === "function" &&
|
|
20
|
+
typeof value.signedUrl === "function" &&
|
|
21
|
+
typeof value.get === "function");
|
|
22
|
+
}
|
|
23
|
+
const optionalDocumentStorage = z.custom((value) => value === undefined ||
|
|
24
|
+
value === null ||
|
|
25
|
+
typeof value === "function" ||
|
|
26
|
+
isStorageProvider(value), "Expected a storage provider or resolver function");
|
|
27
|
+
const optionalDocumentStorageKeyPrefix = z.custom((value) => value === undefined || typeof value === "string" || typeof value === "function", "Expected a storage key prefix string or resolver function");
|
|
28
|
+
const optionalArtifacts = z.custom((value) => {
|
|
29
|
+
if (value === undefined)
|
|
30
|
+
return true;
|
|
31
|
+
if (typeof value !== "object" || value === null)
|
|
32
|
+
return false;
|
|
33
|
+
const artifacts = value;
|
|
34
|
+
return (optionalDb.safeParse(artifacts.db).success &&
|
|
35
|
+
optionalDocumentStorage.safeParse(artifacts.documentStorage).success &&
|
|
36
|
+
optionalDocumentStorageKeyPrefix.safeParse(artifacts.documentStorageKeyPrefix).success);
|
|
37
|
+
}, "Expected valid SmartBill artifact persistence options");
|
|
12
38
|
const optionalEvents = z.custom((value) => {
|
|
13
39
|
if (value === undefined)
|
|
14
40
|
return true;
|
|
15
41
|
if (typeof value !== "object" || value === null)
|
|
16
42
|
return false;
|
|
17
43
|
const events = value;
|
|
18
|
-
return [events.issued, events.voided, events.syncRequested].every((entry) => entry === undefined || (typeof entry === "string" && entry.trim().length > 0));
|
|
44
|
+
return [events.issued, events.proformaIssued, events.voided, events.syncRequested].every((entry) => entry === undefined || (typeof entry === "string" && entry.trim().length > 0));
|
|
19
45
|
}, "Expected event names to be non-empty strings");
|
|
20
46
|
export const smartbillPluginOptionsSchema = z.object({
|
|
21
47
|
username: z.string().trim().min(1),
|
|
@@ -30,4 +56,8 @@ export const smartbillPluginOptionsSchema = z.object({
|
|
|
30
56
|
events: optionalEvents.optional(),
|
|
31
57
|
mapEvent: optionalMapEvent.optional(),
|
|
32
58
|
logger: optionalLogger.optional(),
|
|
59
|
+
artifacts: optionalArtifacts.optional(),
|
|
60
|
+
db: optionalDb.optional(),
|
|
61
|
+
documentStorage: optionalDocumentStorage.optional(),
|
|
62
|
+
documentStorageKeyPrefix: optionalDocumentStorageKeyPrefix.optional(),
|
|
33
63
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/plugin-smartbill",
|
|
3
|
-
"version": "0.31.
|
|
3
|
+
"version": "0.31.4",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -36,8 +36,11 @@
|
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
+
"drizzle-orm": "^0.45.2",
|
|
39
40
|
"zod": "^4.3.6",
|
|
40
|
-
"@voyantjs/core": "0.31.
|
|
41
|
+
"@voyantjs/core": "0.31.4",
|
|
42
|
+
"@voyantjs/finance": "0.31.4",
|
|
43
|
+
"@voyantjs/storage": "0.31.4"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
43
46
|
"typescript": "^6.0.2",
|