@voyantjs/plugin-netopia 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.
- package/LICENSE +109 -0
- package/README.md +56 -0
- package/dist/src/client.d.ts +10 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +71 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +4 -0
- package/dist/src/plugin.d.ts +709 -0
- package/dist/src/plugin.d.ts.map +1 -0
- package/dist/src/plugin.js +127 -0
- package/dist/src/service.d.ts +36 -0
- package/dist/src/service.d.ts.map +1 -0
- package/dist/src/service.js +313 -0
- package/dist/src/types.d.ts +160 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +1 -0
- package/dist/src/validation.d.ts +448 -0
- package/dist/src/validation.d.ts.map +1 -0
- package/dist/src/validation.js +102 -0
- package/dist/tests/unit/client.test.d.ts +2 -0
- package/dist/tests/unit/client.test.d.ts.map +1 -0
- package/dist/tests/unit/client.test.js +254 -0
- package/dist/tests/unit/plugin.test.d.ts +2 -0
- package/dist/tests/unit/plugin.test.d.ts.map +1 -0
- package/dist/tests/unit/plugin.test.js +346 -0
- package/package.json +61 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../../src/plugin.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAKjE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AASvD,KAAK,GAAG,GAAG;IACT,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACjC,SAAS,EAAE;QACT,EAAE,EAAE,kBAAkB,CAAA;QACtB,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAA;CACF,CAAA;AAED,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,qBAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qCAsI7E;AAOD,wBAAgB,6BAA6B,CAAC,OAAO,GAAE,qBAA0B,GAAG,aAAa,CAKhG;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,qBAA0B,GAAG,UAAU,CAMjF;AAED,eAAO,MAAM,uBAAuB,eAAkC,CAAA"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { defineHonoPlugin } from "@voyantjs/hono";
|
|
2
|
+
import { Hono } from "hono";
|
|
3
|
+
import { resolveNetopiaRuntimeOptions } from "./client.js";
|
|
4
|
+
import { netopiaService } from "./service.js";
|
|
5
|
+
import { netopiaCollectBookingGuaranteeSchema, netopiaCollectBookingScheduleSchema, netopiaCollectInvoiceSchema, netopiaStartPaymentSessionSchema, netopiaWebhookPayloadSchema, } from "./validation.js";
|
|
6
|
+
export function createNetopiaFinanceRoutes(options = {}) {
|
|
7
|
+
const handleNetopiaError = (message) => {
|
|
8
|
+
if (message.includes("not found") ||
|
|
9
|
+
message.includes("Payment schedule not found") ||
|
|
10
|
+
message.includes("Booking guarantee not found") ||
|
|
11
|
+
message.includes("Invoice not found")) {
|
|
12
|
+
return { status: 404, message };
|
|
13
|
+
}
|
|
14
|
+
if (message.includes("not startable") || message.includes("already assigned")) {
|
|
15
|
+
return { status: 409, message };
|
|
16
|
+
}
|
|
17
|
+
if (message.includes("Cannot create payment session") ||
|
|
18
|
+
message.includes("outstanding balance") ||
|
|
19
|
+
message.includes("No recipient available")) {
|
|
20
|
+
return { status: 409, message };
|
|
21
|
+
}
|
|
22
|
+
if (message.includes("Missing Netopia config")) {
|
|
23
|
+
return { status: 500, message };
|
|
24
|
+
}
|
|
25
|
+
return { status: 502, message };
|
|
26
|
+
};
|
|
27
|
+
return new Hono()
|
|
28
|
+
.post("/providers/netopia/payment-sessions/:sessionId/start", async (c) => {
|
|
29
|
+
try {
|
|
30
|
+
const data = netopiaStartPaymentSessionSchema.parse(await c.req.json());
|
|
31
|
+
const result = await netopiaService.startPaymentSession(c.get("db"), c.req.param("sessionId"), data, options, undefined, c.env);
|
|
32
|
+
return c.json({ data: result }, 201);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const message = error instanceof Error ? error.message : "Failed to start Netopia payment";
|
|
36
|
+
if (message.includes("Payment session not found")) {
|
|
37
|
+
return c.json({ error: message }, 404);
|
|
38
|
+
}
|
|
39
|
+
if (message.includes("not startable") || message.includes("already assigned")) {
|
|
40
|
+
return c.json({ error: message }, 409);
|
|
41
|
+
}
|
|
42
|
+
if (message.includes("Missing Netopia config")) {
|
|
43
|
+
return c.json({ error: message }, 500);
|
|
44
|
+
}
|
|
45
|
+
return c.json({ error: message }, 502);
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
.post("/providers/netopia/bookings/:bookingId/payment-schedules/:scheduleId/collect", async (c) => {
|
|
49
|
+
try {
|
|
50
|
+
const data = netopiaCollectBookingScheduleSchema.parse(await c.req.json());
|
|
51
|
+
const result = await netopiaService.collectBookingSchedule(c.get("db"), c.req.param("scheduleId"), data, options, undefined, undefined, c.env);
|
|
52
|
+
return c.json({ data: result }, 201);
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : "Failed to collect schedule payment";
|
|
56
|
+
const response = handleNetopiaError(message);
|
|
57
|
+
return c.json({ error: response.message }, response.status);
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
.post("/providers/netopia/bookings/:bookingId/guarantees/:guaranteeId/collect", async (c) => {
|
|
61
|
+
try {
|
|
62
|
+
const data = netopiaCollectBookingGuaranteeSchema.parse(await c.req.json());
|
|
63
|
+
const result = await netopiaService.collectBookingGuarantee(c.get("db"), c.req.param("guaranteeId"), data, options, undefined, undefined, c.env);
|
|
64
|
+
return c.json({ data: result }, 201);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
const message = error instanceof Error ? error.message : "Failed to collect guarantee payment";
|
|
68
|
+
const response = handleNetopiaError(message);
|
|
69
|
+
return c.json({ error: response.message }, response.status);
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
.post("/providers/netopia/invoices/:invoiceId/collect", async (c) => {
|
|
73
|
+
try {
|
|
74
|
+
const data = netopiaCollectInvoiceSchema.parse(await c.req.json());
|
|
75
|
+
const result = await netopiaService.collectInvoice(c.get("db"), c.req.param("invoiceId"), data, options, undefined, undefined, c.env);
|
|
76
|
+
return c.json({ data: result }, 201);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
const message = error instanceof Error ? error.message : "Failed to collect invoice payment";
|
|
80
|
+
const response = handleNetopiaError(message);
|
|
81
|
+
return c.json({ error: response.message }, response.status);
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.post("/providers/netopia/callback", async (c) => {
|
|
85
|
+
const payload = netopiaWebhookPayloadSchema.parse(await c.req.json());
|
|
86
|
+
const result = await netopiaService.handleCallback(c.get("db"), payload, options, c.env);
|
|
87
|
+
return c.json({ data: result });
|
|
88
|
+
})
|
|
89
|
+
.get("/providers/netopia/config", async (c) => {
|
|
90
|
+
try {
|
|
91
|
+
const runtime = resolveNetopiaRuntimeOptions(c.env, options);
|
|
92
|
+
return c.json({
|
|
93
|
+
data: {
|
|
94
|
+
apiUrl: runtime.apiUrl,
|
|
95
|
+
notifyUrl: runtime.notifyUrl,
|
|
96
|
+
redirectUrl: runtime.redirectUrl,
|
|
97
|
+
emailTemplate: runtime.emailTemplate,
|
|
98
|
+
language: runtime.language,
|
|
99
|
+
successStatuses: runtime.successStatuses,
|
|
100
|
+
processingStatuses: runtime.processingStatuses,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const message = error instanceof Error ? error.message : "Missing Netopia config";
|
|
106
|
+
return c.json({ error: message }, 500);
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
const netopiaFinanceExtensionDef = {
|
|
111
|
+
name: "netopia-finance",
|
|
112
|
+
module: "finance",
|
|
113
|
+
};
|
|
114
|
+
export function createNetopiaFinanceExtension(options = {}) {
|
|
115
|
+
return {
|
|
116
|
+
extension: netopiaFinanceExtensionDef,
|
|
117
|
+
routes: createNetopiaFinanceRoutes(options),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export function netopiaHonoPlugin(options = {}) {
|
|
121
|
+
return defineHonoPlugin({
|
|
122
|
+
name: "netopia",
|
|
123
|
+
version: "0.1.0",
|
|
124
|
+
extensions: [createNetopiaFinanceExtension(options)],
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
export const netopiaFinanceExtension = createNetopiaFinanceExtension();
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type PaymentSession } from "@voyantjs/finance";
|
|
2
|
+
import { type NotificationDelivery, type NotificationService } from "@voyantjs/notifications";
|
|
3
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
4
|
+
import type { z } from "zod";
|
|
5
|
+
import { type NetopiaClientApi } from "./client.js";
|
|
6
|
+
import type { NetopiaRuntimeOptions, NetopiaStartPaymentInput, NetopiaStartPaymentResponse, NetopiaWebhookPayload, ResolvedNetopiaRuntimeOptions } from "./types.js";
|
|
7
|
+
import type { netopiaCollectBookingGuaranteeSchema, netopiaCollectBookingScheduleSchema, netopiaCollectInvoiceSchema } from "./validation.js";
|
|
8
|
+
export interface NetopiaStartPaymentResult {
|
|
9
|
+
session: PaymentSession;
|
|
10
|
+
providerResponse: NetopiaStartPaymentResponse;
|
|
11
|
+
orderId: string;
|
|
12
|
+
}
|
|
13
|
+
export interface NetopiaCallbackResult {
|
|
14
|
+
action: "processing" | "completed" | "failed" | "ignored";
|
|
15
|
+
reason?: string;
|
|
16
|
+
session: PaymentSession | null;
|
|
17
|
+
orderId: string;
|
|
18
|
+
}
|
|
19
|
+
export interface NetopiaCollectPaymentResult extends NetopiaStartPaymentResult {
|
|
20
|
+
paymentSessionNotification: NotificationDelivery | null;
|
|
21
|
+
invoiceNotification: NotificationDelivery | null;
|
|
22
|
+
}
|
|
23
|
+
type NetopiaCollectBookingScheduleInput = z.infer<typeof netopiaCollectBookingScheduleSchema>;
|
|
24
|
+
type NetopiaCollectBookingGuaranteeInput = z.infer<typeof netopiaCollectBookingGuaranteeSchema>;
|
|
25
|
+
type NetopiaCollectInvoiceInput = z.infer<typeof netopiaCollectInvoiceSchema>;
|
|
26
|
+
export declare function deriveNetopiaOrderId(session: PaymentSession): string;
|
|
27
|
+
export declare function mapNetopiaPaymentStatus(status: number, options: Pick<ResolvedNetopiaRuntimeOptions, "successStatuses" | "processingStatuses">): "completed" | "processing" | "failed";
|
|
28
|
+
export declare const netopiaService: {
|
|
29
|
+
startPaymentSession(db: PostgresJsDatabase, sessionId: string, input: NetopiaStartPaymentInput, runtimeOptions?: NetopiaRuntimeOptions, clientOverride?: NetopiaClientApi, bindings?: Record<string, unknown>): Promise<NetopiaStartPaymentResult>;
|
|
30
|
+
collectBookingSchedule(db: PostgresJsDatabase, scheduleId: string, input: NetopiaCollectBookingScheduleInput, runtimeOptions?: NetopiaRuntimeOptions, clientOverride?: NetopiaClientApi, dispatcherOverride?: NotificationService, bindings?: Record<string, unknown>): Promise<NetopiaCollectPaymentResult>;
|
|
31
|
+
collectBookingGuarantee(db: PostgresJsDatabase, guaranteeId: string, input: NetopiaCollectBookingGuaranteeInput, runtimeOptions?: NetopiaRuntimeOptions, clientOverride?: NetopiaClientApi, dispatcherOverride?: NotificationService, bindings?: Record<string, unknown>): Promise<NetopiaCollectPaymentResult>;
|
|
32
|
+
collectInvoice(db: PostgresJsDatabase, invoiceId: string, input: NetopiaCollectInvoiceInput, runtimeOptions?: NetopiaRuntimeOptions, clientOverride?: NetopiaClientApi, dispatcherOverride?: NotificationService, bindings?: Record<string, unknown>): Promise<NetopiaCollectPaymentResult>;
|
|
33
|
+
handleCallback(db: PostgresJsDatabase, payload: NetopiaWebhookPayload, runtimeOptions?: NetopiaRuntimeOptions, bindings?: Record<string, unknown>): Promise<NetopiaCallbackResult>;
|
|
34
|
+
};
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAA;AACvE,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACzB,MAAM,yBAAyB,CAAA;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,OAAO,EAAqD,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACtG,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EAExB,2BAA2B,EAC3B,qBAAqB,EAErB,6BAA6B,EAC9B,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EACV,oCAAoC,EACpC,mCAAmC,EACnC,2BAA2B,EAC5B,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,cAAc,CAAA;IACvB,gBAAgB,EAAE,2BAA2B,CAAA;IAC7C,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;IACzD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,cAAc,GAAG,IAAI,CAAA;IAC9B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,2BAA4B,SAAQ,yBAAyB;IAC5E,0BAA0B,EAAE,oBAAoB,GAAG,IAAI,CAAA;IACvD,mBAAmB,EAAE,oBAAoB,GAAG,IAAI,CAAA;CACjD;AAED,KAAK,kCAAkC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mCAAmC,CAAC,CAAA;AAC7F,KAAK,mCAAmC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oCAAoC,CAAC,CAAA;AAC/F,KAAK,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAA;AAkC7E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,cAAc,UAE3D;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,IAAI,CAAC,6BAA6B,EAAE,iBAAiB,GAAG,oBAAoB,CAAC,GACrF,WAAW,GAAG,YAAY,GAAG,QAAQ,CAIvC;AAiBD,eAAO,MAAM,cAAc;4BAEnB,kBAAkB,aACX,MAAM,SACV,wBAAwB,mBACf,qBAAqB,mBACpB,gBAAgB,aACtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,yBAAyB,CAAC;+BA2F/B,kBAAkB,cACV,MAAM,SACX,kCAAkC,mBACzB,qBAAqB,mBACpB,gBAAgB,uBACZ,mBAAmB,aAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,2BAA2B,CAAC;gCAyCjC,kBAAkB,eACT,MAAM,SACZ,mCAAmC,mBAC1B,qBAAqB,mBACpB,gBAAgB,uBACZ,mBAAmB,aAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,2BAA2B,CAAC;uBAyCjC,kBAAkB,aACX,MAAM,SACV,0BAA0B,mBACjB,qBAAqB,mBACpB,gBAAgB,uBACZ,mBAAmB,aAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,2BAA2B,CAAC;uBAoDjC,kBAAkB,WACb,qBAAqB,mBACd,qBAAqB,aAC1B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,OAAO,CAAC,qBAAqB,CAAC;CA8IlC,CAAA"}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { financeService } from "@voyantjs/finance";
|
|
2
|
+
import { createDefaultNotificationProviders, createNotificationService, notificationsService, } from "@voyantjs/notifications";
|
|
3
|
+
import { createNetopiaClient, resolveNetopiaRuntimeOptions } from "./client.js";
|
|
4
|
+
function centsToAmount(cents) {
|
|
5
|
+
return Number((cents / 100).toFixed(2));
|
|
6
|
+
}
|
|
7
|
+
function amountToCents(amount) {
|
|
8
|
+
return Math.round(amount * 100);
|
|
9
|
+
}
|
|
10
|
+
function normalizeCurrency(currency) {
|
|
11
|
+
return currency.trim().toUpperCase();
|
|
12
|
+
}
|
|
13
|
+
function mergeRecord(base, extra) {
|
|
14
|
+
return {
|
|
15
|
+
...(base ?? {}),
|
|
16
|
+
...extra,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function buildDefaultProducts(session, description) {
|
|
20
|
+
return [
|
|
21
|
+
{
|
|
22
|
+
name: description,
|
|
23
|
+
price: centsToAmount(session.amountCents),
|
|
24
|
+
vat: 0,
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
export function deriveNetopiaOrderId(session) {
|
|
29
|
+
return session.externalReference ?? session.clientReference ?? session.id;
|
|
30
|
+
}
|
|
31
|
+
export function mapNetopiaPaymentStatus(status, options) {
|
|
32
|
+
if (options.successStatuses.includes(status))
|
|
33
|
+
return "completed";
|
|
34
|
+
if (options.processingStatuses.includes(status))
|
|
35
|
+
return "processing";
|
|
36
|
+
return "failed";
|
|
37
|
+
}
|
|
38
|
+
function resolveNotificationDispatcher(bindings, runtimeOptions, dispatcherOverride) {
|
|
39
|
+
if (dispatcherOverride) {
|
|
40
|
+
return dispatcherOverride;
|
|
41
|
+
}
|
|
42
|
+
return createNotificationService(runtimeOptions.resolveNotificationProviders?.(bindings ?? {}) ??
|
|
43
|
+
createDefaultNotificationProviders(bindings ?? {}));
|
|
44
|
+
}
|
|
45
|
+
export const netopiaService = {
|
|
46
|
+
async startPaymentSession(db, sessionId, input, runtimeOptions = {}, clientOverride, bindings) {
|
|
47
|
+
const session = await financeService.getPaymentSessionById(db, sessionId);
|
|
48
|
+
if (!session) {
|
|
49
|
+
throw new Error("Payment session not found");
|
|
50
|
+
}
|
|
51
|
+
if (session.provider && session.provider !== "netopia") {
|
|
52
|
+
throw new Error(`Payment session ${sessionId} is already assigned to provider "${session.provider}"`);
|
|
53
|
+
}
|
|
54
|
+
if (["paid", "authorized", "cancelled", "expired"].includes(session.status)) {
|
|
55
|
+
throw new Error(`Payment session ${sessionId} is not startable from status "${session.status}"`);
|
|
56
|
+
}
|
|
57
|
+
const runtime = resolveNetopiaRuntimeOptions(bindings, runtimeOptions);
|
|
58
|
+
const client = clientOverride ??
|
|
59
|
+
createNetopiaClient({
|
|
60
|
+
apiUrl: runtime.apiUrl,
|
|
61
|
+
apiKey: runtime.apiKey,
|
|
62
|
+
fetch: runtime.fetch,
|
|
63
|
+
});
|
|
64
|
+
const description = input.description ?? session.notes ?? `Payment ${session.id}`;
|
|
65
|
+
const orderId = deriveNetopiaOrderId(session);
|
|
66
|
+
const request = {
|
|
67
|
+
config: {
|
|
68
|
+
emailTemplate: input.emailTemplate ?? runtime.emailTemplate,
|
|
69
|
+
notifyUrl: input.notifyUrl ?? runtime.notifyUrl,
|
|
70
|
+
redirectUrl: input.returnUrl ?? runtime.redirectUrl,
|
|
71
|
+
language: input.language ?? runtime.language,
|
|
72
|
+
},
|
|
73
|
+
payment: {
|
|
74
|
+
options: input.options ?? { installments: 1 },
|
|
75
|
+
instrument: input.instrument,
|
|
76
|
+
data: input.browserData,
|
|
77
|
+
},
|
|
78
|
+
order: {
|
|
79
|
+
ntpID: "",
|
|
80
|
+
posSignature: runtime.posSignature,
|
|
81
|
+
dateTime: new Date().toISOString(),
|
|
82
|
+
description,
|
|
83
|
+
orderID: orderId,
|
|
84
|
+
amount: centsToAmount(session.amountCents),
|
|
85
|
+
currency: normalizeCurrency(session.currency),
|
|
86
|
+
billing: input.billing,
|
|
87
|
+
shipping: input.shipping ?? input.billing,
|
|
88
|
+
products: input.products && input.products.length > 0
|
|
89
|
+
? input.products
|
|
90
|
+
: buildDefaultProducts(session, description),
|
|
91
|
+
installments: input.installments ?? { selected: 1, available: [0] },
|
|
92
|
+
data: input.orderData,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
const providerResponse = await client.startCardPayment(request);
|
|
96
|
+
const payment = providerResponse.payment;
|
|
97
|
+
if (!payment?.paymentURL) {
|
|
98
|
+
throw new Error("Netopia start payment succeeded without paymentURL");
|
|
99
|
+
}
|
|
100
|
+
const updated = await financeService.markPaymentSessionRequiresRedirect(db, session.id, {
|
|
101
|
+
provider: "netopia",
|
|
102
|
+
providerSessionId: payment.ntpID ?? null,
|
|
103
|
+
providerPaymentId: payment.ntpID ?? null,
|
|
104
|
+
externalReference: orderId,
|
|
105
|
+
redirectUrl: payment.paymentURL,
|
|
106
|
+
returnUrl: input.returnUrl ?? runtime.redirectUrl,
|
|
107
|
+
cancelUrl: input.cancelUrl ?? null,
|
|
108
|
+
callbackUrl: input.callbackUrl ?? input.notifyUrl ?? runtime.notifyUrl,
|
|
109
|
+
providerPayload: mergeRecord(session.providerPayload, {
|
|
110
|
+
netopiaStartRequest: request,
|
|
111
|
+
netopiaStartResponse: providerResponse,
|
|
112
|
+
}),
|
|
113
|
+
metadata: input.metadata ?? undefined,
|
|
114
|
+
notes: input.notes ?? session.notes ?? undefined,
|
|
115
|
+
});
|
|
116
|
+
if (!updated) {
|
|
117
|
+
throw new Error("Payment session disappeared while saving Netopia redirect state");
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
session: updated,
|
|
121
|
+
providerResponse,
|
|
122
|
+
orderId,
|
|
123
|
+
};
|
|
124
|
+
},
|
|
125
|
+
async collectBookingSchedule(db, scheduleId, input, runtimeOptions = {}, clientOverride, dispatcherOverride, bindings) {
|
|
126
|
+
const session = await financeService.createPaymentSessionFromBookingSchedule(db, scheduleId, {
|
|
127
|
+
...(input.paymentSession ?? {}),
|
|
128
|
+
provider: "netopia",
|
|
129
|
+
});
|
|
130
|
+
if (!session) {
|
|
131
|
+
throw new Error("Payment schedule not found");
|
|
132
|
+
}
|
|
133
|
+
const started = await this.startPaymentSession(db, session.id, input.netopia, runtimeOptions, clientOverride, bindings);
|
|
134
|
+
const dispatcher = input.notification
|
|
135
|
+
? resolveNotificationDispatcher(bindings, runtimeOptions, dispatcherOverride)
|
|
136
|
+
: null;
|
|
137
|
+
const paymentSessionNotification = input.notification && dispatcher
|
|
138
|
+
? await notificationsService.sendPaymentSessionNotification(db, dispatcher, started.session.id, input.notification)
|
|
139
|
+
: null;
|
|
140
|
+
return {
|
|
141
|
+
...started,
|
|
142
|
+
paymentSessionNotification,
|
|
143
|
+
invoiceNotification: null,
|
|
144
|
+
};
|
|
145
|
+
},
|
|
146
|
+
async collectBookingGuarantee(db, guaranteeId, input, runtimeOptions = {}, clientOverride, dispatcherOverride, bindings) {
|
|
147
|
+
const session = await financeService.createPaymentSessionFromBookingGuarantee(db, guaranteeId, {
|
|
148
|
+
...(input.paymentSession ?? {}),
|
|
149
|
+
provider: "netopia",
|
|
150
|
+
});
|
|
151
|
+
if (!session) {
|
|
152
|
+
throw new Error("Booking guarantee not found");
|
|
153
|
+
}
|
|
154
|
+
const started = await this.startPaymentSession(db, session.id, input.netopia, runtimeOptions, clientOverride, bindings);
|
|
155
|
+
const dispatcher = input.notification
|
|
156
|
+
? resolveNotificationDispatcher(bindings, runtimeOptions, dispatcherOverride)
|
|
157
|
+
: null;
|
|
158
|
+
const paymentSessionNotification = input.notification && dispatcher
|
|
159
|
+
? await notificationsService.sendPaymentSessionNotification(db, dispatcher, started.session.id, input.notification)
|
|
160
|
+
: null;
|
|
161
|
+
return {
|
|
162
|
+
...started,
|
|
163
|
+
paymentSessionNotification,
|
|
164
|
+
invoiceNotification: null,
|
|
165
|
+
};
|
|
166
|
+
},
|
|
167
|
+
async collectInvoice(db, invoiceId, input, runtimeOptions = {}, clientOverride, dispatcherOverride, bindings) {
|
|
168
|
+
const session = await financeService.createPaymentSessionFromInvoice(db, invoiceId, {
|
|
169
|
+
...(input.paymentSession ?? {}),
|
|
170
|
+
provider: "netopia",
|
|
171
|
+
});
|
|
172
|
+
if (!session) {
|
|
173
|
+
throw new Error("Invoice not found");
|
|
174
|
+
}
|
|
175
|
+
const started = await this.startPaymentSession(db, session.id, input.netopia, runtimeOptions, clientOverride, bindings);
|
|
176
|
+
const shouldNotify = Boolean(input.paymentSessionNotification || input.invoiceNotification);
|
|
177
|
+
const dispatcher = shouldNotify
|
|
178
|
+
? resolveNotificationDispatcher(bindings, runtimeOptions, dispatcherOverride)
|
|
179
|
+
: null;
|
|
180
|
+
const paymentSessionNotification = input.paymentSessionNotification && dispatcher
|
|
181
|
+
? await notificationsService.sendPaymentSessionNotification(db, dispatcher, started.session.id, input.paymentSessionNotification)
|
|
182
|
+
: null;
|
|
183
|
+
const invoiceNotification = input.invoiceNotification && dispatcher
|
|
184
|
+
? await notificationsService.sendInvoiceNotification(db, dispatcher, invoiceId, input.invoiceNotification)
|
|
185
|
+
: null;
|
|
186
|
+
return {
|
|
187
|
+
...started,
|
|
188
|
+
paymentSessionNotification,
|
|
189
|
+
invoiceNotification,
|
|
190
|
+
};
|
|
191
|
+
},
|
|
192
|
+
async handleCallback(db, payload, runtimeOptions = {}, bindings) {
|
|
193
|
+
const runtime = resolveNetopiaRuntimeOptions(bindings, runtimeOptions);
|
|
194
|
+
const orderId = payload.order.orderID;
|
|
195
|
+
const lookup = await financeService.listPaymentSessions(db, {
|
|
196
|
+
provider: "netopia",
|
|
197
|
+
externalReference: orderId,
|
|
198
|
+
limit: 1,
|
|
199
|
+
offset: 0,
|
|
200
|
+
});
|
|
201
|
+
let session = lookup.data[0] ?? null;
|
|
202
|
+
if (!session) {
|
|
203
|
+
session = await financeService.getPaymentSessionById(db, orderId);
|
|
204
|
+
}
|
|
205
|
+
if (!session) {
|
|
206
|
+
return {
|
|
207
|
+
action: "ignored",
|
|
208
|
+
reason: "payment_session_not_found",
|
|
209
|
+
session: null,
|
|
210
|
+
orderId,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
const callbackState = mapNetopiaPaymentStatus(payload.payment.status, runtime);
|
|
214
|
+
const providerPayload = mergeRecord(session.providerPayload, {
|
|
215
|
+
netopiaCallback: payload,
|
|
216
|
+
});
|
|
217
|
+
const normalizedCurrency = normalizeCurrency(payload.payment.currency);
|
|
218
|
+
const amountCents = amountToCents(payload.payment.amount);
|
|
219
|
+
if (callbackState === "completed" &&
|
|
220
|
+
(normalizedCurrency !== normalizeCurrency(session.currency) || amountCents !== session.amountCents)) {
|
|
221
|
+
const failed = await financeService.failPaymentSession(db, session.id, {
|
|
222
|
+
providerSessionId: payload.payment.ntpID,
|
|
223
|
+
providerPaymentId: payload.payment.ntpID,
|
|
224
|
+
externalReference: orderId,
|
|
225
|
+
failureCode: "amount_or_currency_mismatch",
|
|
226
|
+
failureMessage: `Expected ${session.amountCents} ${normalizeCurrency(session.currency)}, received ${amountCents} ${normalizedCurrency}`,
|
|
227
|
+
providerPayload,
|
|
228
|
+
});
|
|
229
|
+
return {
|
|
230
|
+
action: "failed",
|
|
231
|
+
reason: "amount_or_currency_mismatch",
|
|
232
|
+
session: failed,
|
|
233
|
+
orderId,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (callbackState === "processing") {
|
|
237
|
+
const updated = await financeService.updatePaymentSession(db, session.id, {
|
|
238
|
+
status: "processing",
|
|
239
|
+
provider: "netopia",
|
|
240
|
+
providerSessionId: payload.payment.ntpID,
|
|
241
|
+
providerPaymentId: payload.payment.ntpID,
|
|
242
|
+
externalReference: orderId,
|
|
243
|
+
providerPayload,
|
|
244
|
+
});
|
|
245
|
+
return {
|
|
246
|
+
action: "processing",
|
|
247
|
+
session: updated,
|
|
248
|
+
orderId,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
if (callbackState === "completed") {
|
|
252
|
+
if (session.status === "paid" || session.status === "authorized") {
|
|
253
|
+
const current = await financeService.updatePaymentSession(db, session.id, {
|
|
254
|
+
provider: "netopia",
|
|
255
|
+
providerSessionId: payload.payment.ntpID,
|
|
256
|
+
providerPaymentId: payload.payment.ntpID,
|
|
257
|
+
externalReference: orderId,
|
|
258
|
+
providerPayload,
|
|
259
|
+
});
|
|
260
|
+
return {
|
|
261
|
+
action: "ignored",
|
|
262
|
+
reason: "already_completed",
|
|
263
|
+
session: current,
|
|
264
|
+
orderId,
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const completed = await financeService.completePaymentSession(db, session.id, {
|
|
268
|
+
status: "paid",
|
|
269
|
+
captureMode: "manual",
|
|
270
|
+
paymentMethod: "credit_card",
|
|
271
|
+
providerSessionId: payload.payment.ntpID,
|
|
272
|
+
providerPaymentId: payload.payment.ntpID,
|
|
273
|
+
externalReference: orderId,
|
|
274
|
+
externalAuthorizationId: typeof payload.payment.data?.AuthCode === "string"
|
|
275
|
+
? payload.payment.data.AuthCode
|
|
276
|
+
: payload.payment.ntpID,
|
|
277
|
+
externalCaptureId: typeof payload.payment.data?.RRN === "string"
|
|
278
|
+
? payload.payment.data.RRN
|
|
279
|
+
: payload.payment.ntpID,
|
|
280
|
+
approvalCode: typeof payload.payment.data?.AuthCode === "string"
|
|
281
|
+
? payload.payment.data.AuthCode
|
|
282
|
+
: undefined,
|
|
283
|
+
referenceNumber: typeof payload.payment.data?.RRN === "string" ? payload.payment.data.RRN : undefined,
|
|
284
|
+
authorizedAt: new Date().toISOString(),
|
|
285
|
+
capturedAt: new Date().toISOString(),
|
|
286
|
+
paymentDate: new Date().toISOString(),
|
|
287
|
+
providerPayload,
|
|
288
|
+
});
|
|
289
|
+
return {
|
|
290
|
+
action: "completed",
|
|
291
|
+
session: completed,
|
|
292
|
+
orderId,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const failed = await financeService.failPaymentSession(db, session.id, {
|
|
296
|
+
providerSessionId: payload.payment.ntpID,
|
|
297
|
+
providerPaymentId: payload.payment.ntpID,
|
|
298
|
+
externalReference: orderId,
|
|
299
|
+
failureCode: typeof payload.payment.code === "string" && payload.payment.code.length > 0
|
|
300
|
+
? payload.payment.code
|
|
301
|
+
: `netopia_status_${payload.payment.status}`,
|
|
302
|
+
failureMessage: typeof payload.payment.message === "string" && payload.payment.message.length > 0
|
|
303
|
+
? payload.payment.message
|
|
304
|
+
: "Netopia payment was not approved",
|
|
305
|
+
providerPayload,
|
|
306
|
+
});
|
|
307
|
+
return {
|
|
308
|
+
action: "failed",
|
|
309
|
+
session: failed,
|
|
310
|
+
orderId,
|
|
311
|
+
};
|
|
312
|
+
},
|
|
313
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { NotificationProvider } from "@voyantjs/notifications";
|
|
2
|
+
export type NetopiaFetch = (input: string, init: {
|
|
3
|
+
method: string;
|
|
4
|
+
headers: Record<string, string>;
|
|
5
|
+
body?: string;
|
|
6
|
+
}) => Promise<{
|
|
7
|
+
ok: boolean;
|
|
8
|
+
status: number;
|
|
9
|
+
json: () => Promise<unknown>;
|
|
10
|
+
text: () => Promise<string>;
|
|
11
|
+
}>;
|
|
12
|
+
export interface NetopiaBillingAddress {
|
|
13
|
+
email: string;
|
|
14
|
+
phone: string;
|
|
15
|
+
firstName: string;
|
|
16
|
+
lastName: string;
|
|
17
|
+
city: string;
|
|
18
|
+
country: number;
|
|
19
|
+
state: string;
|
|
20
|
+
postalCode: string;
|
|
21
|
+
details: string;
|
|
22
|
+
}
|
|
23
|
+
export interface NetopiaProductLine {
|
|
24
|
+
name?: string;
|
|
25
|
+
code?: string;
|
|
26
|
+
category?: string;
|
|
27
|
+
price?: number;
|
|
28
|
+
vat?: number;
|
|
29
|
+
}
|
|
30
|
+
export interface NetopiaInstallments {
|
|
31
|
+
selected: number;
|
|
32
|
+
available: number[];
|
|
33
|
+
}
|
|
34
|
+
export interface NetopiaPaymentOptions {
|
|
35
|
+
installments: number;
|
|
36
|
+
bonus?: number;
|
|
37
|
+
}
|
|
38
|
+
export interface NetopiaPaymentInstrument {
|
|
39
|
+
type: string;
|
|
40
|
+
account: string;
|
|
41
|
+
expMonth: number;
|
|
42
|
+
expYear: number;
|
|
43
|
+
secretCode: string;
|
|
44
|
+
token?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface NetopiaBrowserData {
|
|
47
|
+
[key: string]: string | undefined;
|
|
48
|
+
}
|
|
49
|
+
export interface NetopiaStartPaymentRequest {
|
|
50
|
+
config: {
|
|
51
|
+
emailTemplate: string;
|
|
52
|
+
notifyUrl: string;
|
|
53
|
+
redirectUrl: string;
|
|
54
|
+
language: string;
|
|
55
|
+
};
|
|
56
|
+
payment: {
|
|
57
|
+
options: NetopiaPaymentOptions;
|
|
58
|
+
instrument?: NetopiaPaymentInstrument;
|
|
59
|
+
data?: NetopiaBrowserData;
|
|
60
|
+
};
|
|
61
|
+
order: {
|
|
62
|
+
ntpID?: string;
|
|
63
|
+
posSignature: string;
|
|
64
|
+
dateTime: string;
|
|
65
|
+
description: string;
|
|
66
|
+
orderID: string;
|
|
67
|
+
amount: number;
|
|
68
|
+
currency: string;
|
|
69
|
+
billing: NetopiaBillingAddress;
|
|
70
|
+
shipping: NetopiaBillingAddress;
|
|
71
|
+
products: NetopiaProductLine[];
|
|
72
|
+
installments: NetopiaInstallments;
|
|
73
|
+
data?: Record<string, string>;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
export interface NetopiaStartPaymentResponse {
|
|
77
|
+
code?: string;
|
|
78
|
+
message?: string;
|
|
79
|
+
error?: {
|
|
80
|
+
code?: string | number;
|
|
81
|
+
message?: string;
|
|
82
|
+
};
|
|
83
|
+
payment?: {
|
|
84
|
+
paymentURL?: string;
|
|
85
|
+
ntpID?: string;
|
|
86
|
+
status?: number;
|
|
87
|
+
amount?: number;
|
|
88
|
+
currency?: string;
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export interface NetopiaWebhookPayload {
|
|
92
|
+
order: {
|
|
93
|
+
orderID: string;
|
|
94
|
+
};
|
|
95
|
+
payment: {
|
|
96
|
+
amount: number;
|
|
97
|
+
currency: string;
|
|
98
|
+
ntpID: string;
|
|
99
|
+
status: number;
|
|
100
|
+
code?: string;
|
|
101
|
+
message?: string;
|
|
102
|
+
data?: {
|
|
103
|
+
AuthCode?: string;
|
|
104
|
+
RRN?: string;
|
|
105
|
+
[key: string]: unknown;
|
|
106
|
+
};
|
|
107
|
+
instrument?: {
|
|
108
|
+
country?: number;
|
|
109
|
+
panMasked?: string;
|
|
110
|
+
[key: string]: unknown;
|
|
111
|
+
};
|
|
112
|
+
[key: string]: unknown;
|
|
113
|
+
};
|
|
114
|
+
[key: string]: unknown;
|
|
115
|
+
}
|
|
116
|
+
export interface NetopiaStartPaymentInput {
|
|
117
|
+
description?: string;
|
|
118
|
+
notifyUrl?: string;
|
|
119
|
+
returnUrl?: string;
|
|
120
|
+
cancelUrl?: string;
|
|
121
|
+
callbackUrl?: string;
|
|
122
|
+
emailTemplate?: string;
|
|
123
|
+
language?: string;
|
|
124
|
+
options?: NetopiaPaymentOptions;
|
|
125
|
+
instrument?: NetopiaPaymentInstrument;
|
|
126
|
+
browserData?: NetopiaBrowserData;
|
|
127
|
+
billing: NetopiaBillingAddress;
|
|
128
|
+
shipping?: NetopiaBillingAddress;
|
|
129
|
+
products?: NetopiaProductLine[];
|
|
130
|
+
installments?: NetopiaInstallments;
|
|
131
|
+
orderData?: Record<string, string>;
|
|
132
|
+
metadata?: Record<string, unknown>;
|
|
133
|
+
notes?: string | null;
|
|
134
|
+
}
|
|
135
|
+
export interface NetopiaRuntimeOptions {
|
|
136
|
+
apiUrl?: string;
|
|
137
|
+
apiKey?: string;
|
|
138
|
+
posSignature?: string;
|
|
139
|
+
notifyUrl?: string;
|
|
140
|
+
redirectUrl?: string;
|
|
141
|
+
emailTemplate?: string;
|
|
142
|
+
language?: string;
|
|
143
|
+
successStatuses?: number[];
|
|
144
|
+
processingStatuses?: number[];
|
|
145
|
+
fetch?: NetopiaFetch;
|
|
146
|
+
resolveNotificationProviders?: (bindings: Record<string, unknown>) => ReadonlyArray<NotificationProvider>;
|
|
147
|
+
}
|
|
148
|
+
export interface ResolvedNetopiaRuntimeOptions {
|
|
149
|
+
apiUrl: string;
|
|
150
|
+
apiKey: string;
|
|
151
|
+
posSignature: string;
|
|
152
|
+
notifyUrl: string;
|
|
153
|
+
redirectUrl: string;
|
|
154
|
+
emailTemplate: string;
|
|
155
|
+
language: string;
|
|
156
|
+
successStatuses: number[];
|
|
157
|
+
processingStatuses: number[];
|
|
158
|
+
fetch?: NetopiaFetch;
|
|
159
|
+
}
|
|
160
|
+
//# 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 {};
|