@open-mercato/core 0.4.7-develop-0a657b411f → 0.4.7-develop-e249d3e7d0
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/generated/entities/carrier_shipment/index.js +37 -0
- package/dist/generated/entities/carrier_shipment/index.js.map +7 -0
- package/dist/generated/entities/gateway_transaction/index.js +47 -0
- package/dist/generated/entities/gateway_transaction/index.js.map +7 -0
- package/dist/generated/entities/webhook_processed_event/index.js +17 -0
- package/dist/generated/entities/webhook_processed_event/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +10 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +6 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/data_sync/api/runs/[id]/cancel.js +14 -5
- package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.meta.js +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.meta.js.map +1 -1
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +37 -12
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/directory/api/get/tenants/lookup.js +1 -0
- package/dist/modules/directory/api/get/tenants/lookup.js.map +2 -2
- package/dist/modules/integrations/api/[id]/route.js +38 -11
- package/dist/modules/integrations/api/[id]/route.js.map +2 -2
- package/dist/modules/integrations/api/logs/route.js +52 -26
- package/dist/modules/integrations/api/logs/route.js.map +2 -2
- package/dist/modules/integrations/api/route.js +37 -7
- package/dist/modules/integrations/api/route.js.map +2 -2
- package/dist/modules/integrations/api/umes-read.js +121 -0
- package/dist/modules/integrations/api/umes-read.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.js +715 -183
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +30 -9
- package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/detail-page-widgets.js +46 -0
- package/dist/modules/integrations/backend/integrations/detail-page-widgets.js.map +7 -0
- package/dist/modules/integrations/backend/integrations/page.js +78 -62
- package/dist/modules/integrations/backend/integrations/page.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/page.meta.js +2 -2
- package/dist/modules/integrations/backend/integrations/page.meta.js.map +1 -1
- package/dist/modules/integrations/setup.js +2 -2
- package/dist/modules/integrations/setup.js.map +2 -2
- package/dist/modules/payment_gateways/acl.js +12 -0
- package/dist/modules/payment_gateways/acl.js.map +7 -0
- package/dist/modules/payment_gateways/api/cancel/route.js +55 -0
- package/dist/modules/payment_gateways/api/cancel/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/capture/route.js +55 -0
- package/dist/modules/payment_gateways/api/capture/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/interceptors.js +24 -0
- package/dist/modules/payment_gateways/api/interceptors.js.map +7 -0
- package/dist/modules/payment_gateways/api/openapi.js +5 -0
- package/dist/modules/payment_gateways/api/openapi.js.map +7 -0
- package/dist/modules/payment_gateways/api/refund/route.js +56 -0
- package/dist/modules/payment_gateways/api/refund/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/sessions/route.js +74 -0
- package/dist/modules/payment_gateways/api/sessions/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/status/route.js +66 -0
- package/dist/modules/payment_gateways/api/status/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/transactions/[id]/route.js +118 -0
- package/dist/modules/payment_gateways/api/transactions/[id]/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/transactions/route.js +113 -0
- package/dist/modules/payment_gateways/api/transactions/route.js.map +7 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +136 -0
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +7 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js +496 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +7 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.meta.js +23 -0
- package/dist/modules/payment_gateways/backend/payment-gateways/page.meta.js.map +7 -0
- package/dist/modules/payment_gateways/data/enrichers.js +5 -0
- package/dist/modules/payment_gateways/data/enrichers.js.map +7 -0
- package/dist/modules/payment_gateways/data/entities.js +131 -0
- package/dist/modules/payment_gateways/data/entities.js.map +7 -0
- package/dist/modules/payment_gateways/data/validators.js +57 -0
- package/dist/modules/payment_gateways/data/validators.js.map +7 -0
- package/dist/modules/payment_gateways/di.js +16 -0
- package/dist/modules/payment_gateways/di.js.map +7 -0
- package/dist/modules/payment_gateways/events.js +21 -0
- package/dist/modules/payment_gateways/events.js.map +7 -0
- package/dist/modules/payment_gateways/i18n/en.js +6 -0
- package/dist/modules/payment_gateways/i18n/en.js.map +7 -0
- package/dist/modules/payment_gateways/i18n/pl.js +6 -0
- package/dist/modules/payment_gateways/i18n/pl.js.map +7 -0
- package/dist/modules/payment_gateways/index.js +9 -0
- package/dist/modules/payment_gateways/index.js.map +7 -0
- package/dist/modules/payment_gateways/lib/gateway-service.js +378 -0
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +7 -0
- package/dist/modules/payment_gateways/lib/queue.js +17 -0
- package/dist/modules/payment_gateways/lib/queue.js.map +7 -0
- package/dist/modules/payment_gateways/lib/status-machine.js +29 -0
- package/dist/modules/payment_gateways/lib/status-machine.js.map +7 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js +88 -0
- package/dist/modules/payment_gateways/lib/webhook-processor.js.map +7 -0
- package/dist/modules/payment_gateways/lib/webhook-utils.js +42 -0
- package/dist/modules/payment_gateways/lib/webhook-utils.js.map +7 -0
- package/dist/modules/payment_gateways/migrations/Migration20260305122155.js +19 -0
- package/dist/modules/payment_gateways/migrations/Migration20260305122155.js.map +7 -0
- package/dist/modules/payment_gateways/setup.js +13 -0
- package/dist/modules/payment_gateways/setup.js.map +7 -0
- package/dist/modules/payment_gateways/widgets/injection-table.js +7 -0
- package/dist/modules/payment_gateways/widgets/injection-table.js.map +7 -0
- package/dist/modules/payment_gateways/workers/status-poller.js +44 -0
- package/dist/modules/payment_gateways/workers/status-poller.js.map +7 -0
- package/dist/modules/payment_gateways/workers/webhook-processor.js +20 -0
- package/dist/modules/payment_gateways/workers/webhook-processor.js.map +7 -0
- package/dist/modules/sales/data/enrichers.js +72 -0
- package/dist/modules/sales/data/enrichers.js.map +7 -0
- package/dist/modules/sales/lib/makeSalesLineRoute.js +3 -0
- package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
- package/dist/modules/sales/widgets/injection/payment-gateway-config-field/widget.js +29 -0
- package/dist/modules/sales/widgets/injection/payment-gateway-config-field/widget.js.map +7 -0
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js +23 -0
- package/dist/modules/sales/widgets/injection/payment-gateway-status-column/widget.js.map +7 -0
- package/dist/modules/sales/widgets/injection-table.js +13 -1
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/dist/modules/shipping_carriers/acl.js +10 -0
- package/dist/modules/shipping_carriers/acl.js.map +7 -0
- package/dist/modules/shipping_carriers/api/cancel/route.js +55 -0
- package/dist/modules/shipping_carriers/api/cancel/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/interceptors.js +21 -0
- package/dist/modules/shipping_carriers/api/interceptors.js.map +7 -0
- package/dist/modules/shipping_carriers/api/openapi.js +5 -0
- package/dist/modules/shipping_carriers/api/openapi.js.map +7 -0
- package/dist/modules/shipping_carriers/api/rates/route.js +55 -0
- package/dist/modules/shipping_carriers/api/rates/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/shipments/route.js +61 -0
- package/dist/modules/shipping_carriers/api/shipments/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/tracking/route.js +58 -0
- package/dist/modules/shipping_carriers/api/tracking/route.js.map +7 -0
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +119 -0
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +7 -0
- package/dist/modules/shipping_carriers/data/enrichers.js +82 -0
- package/dist/modules/shipping_carriers/data/enrichers.js.map +7 -0
- package/dist/modules/shipping_carriers/data/entities.js +80 -0
- package/dist/modules/shipping_carriers/data/entities.js.map +7 -0
- package/dist/modules/shipping_carriers/data/validators.js +49 -0
- package/dist/modules/shipping_carriers/data/validators.js.map +7 -0
- package/dist/modules/shipping_carriers/di.js +15 -0
- package/dist/modules/shipping_carriers/di.js.map +7 -0
- package/dist/modules/shipping_carriers/events.js +19 -0
- package/dist/modules/shipping_carriers/events.js.map +7 -0
- package/dist/modules/shipping_carriers/i18n/en.js +11 -0
- package/dist/modules/shipping_carriers/i18n/en.js.map +7 -0
- package/dist/modules/shipping_carriers/i18n/pl.js +11 -0
- package/dist/modules/shipping_carriers/i18n/pl.js.map +7 -0
- package/dist/modules/shipping_carriers/index.js +9 -0
- package/dist/modules/shipping_carriers/index.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/adapter-registry.js +29 -0
- package/dist/modules/shipping_carriers/lib/adapter-registry.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/adapter.js +1 -0
- package/dist/modules/shipping_carriers/lib/adapter.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/queue.js +17 -0
- package/dist/modules/shipping_carriers/lib/queue.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/shipping-service.js +155 -0
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +7 -0
- package/dist/modules/shipping_carriers/lib/status-sync.js +37 -0
- package/dist/modules/shipping_carriers/lib/status-sync.js.map +7 -0
- package/dist/modules/shipping_carriers/migrations/Migration20260305170000.js +16 -0
- package/dist/modules/shipping_carriers/migrations/Migration20260305170000.js.map +7 -0
- package/dist/modules/shipping_carriers/setup.js +13 -0
- package/dist/modules/shipping_carriers/setup.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.js +25 -0
- package/dist/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-column/widget.js +23 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-column/widget.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +40 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection-table.js +24 -0
- package/dist/modules/shipping_carriers/widgets/injection-table.js.map +7 -0
- package/dist/modules/shipping_carriers/workers/status-poller.js +21 -0
- package/dist/modules/shipping_carriers/workers/status-poller.js.map +7 -0
- package/dist/modules/shipping_carriers/workers/webhook-processor.js +54 -0
- package/dist/modules/shipping_carriers/workers/webhook-processor.js.map +7 -0
- package/dist/modules/translations/api/get/locales.js +1 -0
- package/dist/modules/translations/api/get/locales.js.map +2 -2
- package/dist/modules/translations/api/put/locales.js +1 -0
- package/dist/modules/translations/api/put/locales.js.map +2 -2
- package/generated/entities/carrier_shipment/index.ts +17 -0
- package/generated/entities/gateway_transaction/index.ts +22 -0
- package/generated/entities/webhook_processed_event/index.ts +7 -0
- package/generated/entities.ids.generated.ts +10 -1
- package/generated/entity-fields-registry.ts +6 -0
- package/jest.config.cjs +1 -0
- package/package.json +5 -2
- package/src/modules/auth/i18n/de.json +1 -0
- package/src/modules/auth/i18n/en.json +1 -0
- package/src/modules/auth/i18n/es.json +1 -0
- package/src/modules/auth/i18n/pl.json +1 -0
- package/src/modules/data_sync/api/runs/[id]/cancel.ts +18 -5
- package/src/modules/data_sync/backend/data-sync/page.meta.ts +2 -2
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +50 -12
- package/src/modules/directory/api/get/tenants/lookup.ts +1 -0
- package/src/modules/integrations/AGENTS.md +31 -0
- package/src/modules/integrations/api/[id]/route.ts +38 -11
- package/src/modules/integrations/api/logs/route.ts +53 -27
- package/src/modules/integrations/api/route.ts +31 -1
- package/src/modules/integrations/api/umes-read.ts +177 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +902 -202
- package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +43 -9
- package/src/modules/integrations/backend/integrations/detail-page-widgets.ts +74 -0
- package/src/modules/integrations/backend/integrations/page.meta.ts +2 -2
- package/src/modules/integrations/backend/integrations/page.tsx +65 -54
- package/src/modules/integrations/i18n/de.json +15 -0
- package/src/modules/integrations/i18n/en.json +15 -0
- package/src/modules/integrations/i18n/es.json +15 -0
- package/src/modules/integrations/i18n/pl.json +15 -0
- package/src/modules/integrations/setup.ts +2 -2
- package/src/modules/payment_gateways/acl.ts +8 -0
- package/src/modules/payment_gateways/api/cancel/route.ts +56 -0
- package/src/modules/payment_gateways/api/capture/route.ts +56 -0
- package/src/modules/payment_gateways/api/interceptors.ts +22 -0
- package/src/modules/payment_gateways/api/openapi.ts +1 -0
- package/src/modules/payment_gateways/api/refund/route.ts +57 -0
- package/src/modules/payment_gateways/api/sessions/route.ts +76 -0
- package/src/modules/payment_gateways/api/status/route.ts +69 -0
- package/src/modules/payment_gateways/api/transactions/[id]/route.ts +123 -0
- package/src/modules/payment_gateways/api/transactions/route.ts +120 -0
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +161 -0
- package/src/modules/payment_gateways/backend/payment-gateways/page.meta.ts +19 -0
- package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +660 -0
- package/src/modules/payment_gateways/data/enrichers.ts +8 -0
- package/src/modules/payment_gateways/data/entities.ts +106 -0
- package/src/modules/payment_gateways/data/validators.ts +67 -0
- package/src/modules/payment_gateways/di.ts +26 -0
- package/src/modules/payment_gateways/events.ts +17 -0
- package/src/modules/payment_gateways/i18n/de.json +77 -0
- package/src/modules/payment_gateways/i18n/en.json +77 -0
- package/src/modules/payment_gateways/i18n/en.ts +4 -0
- package/src/modules/payment_gateways/i18n/es.json +77 -0
- package/src/modules/payment_gateways/i18n/pl.json +77 -0
- package/src/modules/payment_gateways/i18n/pl.ts +4 -0
- package/src/modules/payment_gateways/index.ts +5 -0
- package/src/modules/payment_gateways/lib/gateway-service.ts +486 -0
- package/src/modules/payment_gateways/lib/queue.ts +19 -0
- package/src/modules/payment_gateways/lib/status-machine.ts +28 -0
- package/src/modules/payment_gateways/lib/webhook-processor.ts +133 -0
- package/src/modules/payment_gateways/lib/webhook-utils.ts +52 -0
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +373 -0
- package/src/modules/payment_gateways/migrations/Migration20260305122155.ts +20 -0
- package/src/modules/payment_gateways/setup.ts +11 -0
- package/src/modules/payment_gateways/widgets/injection-table.ts +9 -0
- package/src/modules/payment_gateways/workers/status-poller.ts +58 -0
- package/src/modules/payment_gateways/workers/webhook-processor.ts +30 -0
- package/src/modules/sales/data/enrichers.ts +120 -0
- package/src/modules/sales/lib/makeSalesLineRoute.ts +3 -0
- package/src/modules/sales/widgets/injection/payment-gateway-config-field/widget.ts +28 -0
- package/src/modules/sales/widgets/injection/payment-gateway-status-column/widget.ts +22 -0
- package/src/modules/sales/widgets/injection-table.ts +12 -0
- package/src/modules/shipping_carriers/acl.ts +6 -0
- package/src/modules/shipping_carriers/api/cancel/route.ts +53 -0
- package/src/modules/shipping_carriers/api/interceptors.ts +19 -0
- package/src/modules/shipping_carriers/api/openapi.ts +1 -0
- package/src/modules/shipping_carriers/api/rates/route.ts +53 -0
- package/src/modules/shipping_carriers/api/shipments/route.ts +59 -0
- package/src/modules/shipping_carriers/api/tracking/route.ts +56 -0
- package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +134 -0
- package/src/modules/shipping_carriers/data/enrichers.ts +89 -0
- package/src/modules/shipping_carriers/data/entities.ts +60 -0
- package/src/modules/shipping_carriers/data/validators.ts +48 -0
- package/src/modules/shipping_carriers/di.ts +20 -0
- package/src/modules/shipping_carriers/events.ts +16 -0
- package/src/modules/shipping_carriers/i18n/de.json +7 -0
- package/src/modules/shipping_carriers/i18n/en.json +7 -0
- package/src/modules/shipping_carriers/i18n/en.ts +7 -0
- package/src/modules/shipping_carriers/i18n/es.json +7 -0
- package/src/modules/shipping_carriers/i18n/pl.json +7 -0
- package/src/modules/shipping_carriers/i18n/pl.ts +7 -0
- package/src/modules/shipping_carriers/index.ts +5 -0
- package/src/modules/shipping_carriers/lib/adapter-registry.ts +33 -0
- package/src/modules/shipping_carriers/lib/adapter.ts +93 -0
- package/src/modules/shipping_carriers/lib/queue.ts +19 -0
- package/src/modules/shipping_carriers/lib/shipping-service.ts +204 -0
- package/src/modules/shipping_carriers/lib/status-sync.ts +38 -0
- package/src/modules/shipping_carriers/migrations/Migration20260305170000.ts +14 -0
- package/src/modules/shipping_carriers/setup.ts +11 -0
- package/src/modules/shipping_carriers/widgets/injection/create-shipment-button/widget.ts +24 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-column/widget.ts +22 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +44 -0
- package/src/modules/shipping_carriers/widgets/injection-table.ts +22 -0
- package/src/modules/shipping_carriers/workers/status-poller.ts +33 -0
- package/src/modules/shipping_carriers/workers/webhook-processor.ts +79 -0
- package/src/modules/translations/api/get/locales.ts +1 -0
- package/src/modules/translations/api/put/locales.ts +1 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
5
|
+
import { refundSchema } from "../../data/validators.js";
|
|
6
|
+
import { paymentGatewaysTag } from "../openapi.js";
|
|
7
|
+
const metadata = {
|
|
8
|
+
path: "/payment_gateways/refund",
|
|
9
|
+
POST: { requireAuth: true, requireFeatures: ["payment_gateways.refund"] }
|
|
10
|
+
};
|
|
11
|
+
async function POST(req) {
|
|
12
|
+
const auth = await getAuthFromRequest(req);
|
|
13
|
+
if (!auth?.tenantId || !auth.orgId) {
|
|
14
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
15
|
+
}
|
|
16
|
+
const payload = await readJsonSafe(req);
|
|
17
|
+
const parsed = refundSchema.safeParse(payload);
|
|
18
|
+
if (!parsed.success) {
|
|
19
|
+
return NextResponse.json({ error: "Invalid payload", details: parsed.error.flatten() }, { status: 422 });
|
|
20
|
+
}
|
|
21
|
+
const container = await createRequestContainer();
|
|
22
|
+
const service = container.resolve("paymentGatewayService");
|
|
23
|
+
try {
|
|
24
|
+
const result = await service.refundPayment(
|
|
25
|
+
parsed.data.transactionId,
|
|
26
|
+
parsed.data.amount,
|
|
27
|
+
parsed.data.reason,
|
|
28
|
+
{ organizationId: auth.orgId, tenantId: auth.tenantId }
|
|
29
|
+
);
|
|
30
|
+
return NextResponse.json(result);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
const message = err instanceof Error ? err.message : "Refund failed";
|
|
33
|
+
return NextResponse.json({ error: message }, { status: 502 });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const openApi = {
|
|
37
|
+
tags: [paymentGatewaysTag],
|
|
38
|
+
summary: "Refund a captured payment",
|
|
39
|
+
methods: {
|
|
40
|
+
POST: {
|
|
41
|
+
summary: "Refund payment",
|
|
42
|
+
tags: [paymentGatewaysTag],
|
|
43
|
+
responses: [
|
|
44
|
+
{ status: 200, description: "Payment refunded" },
|
|
45
|
+
{ status: 422, description: "Invalid payload" },
|
|
46
|
+
{ status: 502, description: "Gateway provider error" }
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
export {
|
|
52
|
+
POST,
|
|
53
|
+
metadata,
|
|
54
|
+
openApi
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/payment_gateways/api/refund/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { refundSchema } from '../../data/validators'\nimport type { PaymentGatewayService } from '../../lib/gateway-service'\nimport { paymentGatewaysTag } from '../openapi'\n\nexport const metadata = {\n path: '/payment_gateways/refund',\n POST: { requireAuth: true, requireFeatures: ['payment_gateways.refund'] },\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const payload = await readJsonSafe<unknown>(req)\n const parsed = refundSchema.safeParse(payload)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid payload', details: parsed.error.flatten() }, { status: 422 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve('paymentGatewayService') as PaymentGatewayService\n\n try {\n const result = await service.refundPayment(\n parsed.data.transactionId,\n parsed.data.amount,\n parsed.data.reason,\n { organizationId: auth.orgId as string, tenantId: auth.tenantId },\n )\n return NextResponse.json(result)\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Refund failed'\n return NextResponse.json({ error: message }, { status: 502 })\n }\n}\n\nexport const openApi = {\n tags: [paymentGatewaysTag],\n summary: 'Refund a captured payment',\n methods: {\n POST: {\n summary: 'Refund payment',\n tags: [paymentGatewaysTag],\n responses: [\n { status: 200, description: 'Payment refunded' },\n { status: 422, description: 'Invalid payload' },\n { status: 502, description: 'Gateway provider error' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAE7B,SAAS,0BAA0B;AAE5B,MAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAC1E;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,UAAU,MAAM,aAAsB,GAAG;AAC/C,QAAM,SAAS,aAAa,UAAU,OAAO;AAC7C,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,OAAO,mBAAmB,SAAS,OAAO,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACzG;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,UAAU,UAAU,QAAQ,uBAAuB;AAEzD,MAAI;AACF,UAAM,SAAS,MAAM,QAAQ;AAAA,MAC3B,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,MACZ,EAAE,gBAAgB,KAAK,OAAiB,UAAU,KAAK,SAAS;AAAA,IAClE;AACA,WAAO,aAAa,KAAK,MAAM;AAAA,EACjC,SAAS,KAAc;AACrB,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,WAAO,aAAa,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9D;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,kBAAkB;AAAA,EACzB,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,MAAM,CAAC,kBAAkB;AAAA,MACzB,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,mBAAmB;AAAA,QAC/C,EAAE,QAAQ,KAAK,aAAa,kBAAkB;AAAA,QAC9C,EAAE,QAAQ,KAAK,aAAa,yBAAyB;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
5
|
+
import { createSessionSchema } from "../../data/validators.js";
|
|
6
|
+
import { paymentGatewaysTag } from "../openapi.js";
|
|
7
|
+
const metadata = {
|
|
8
|
+
path: "/payment_gateways/sessions",
|
|
9
|
+
POST: { requireAuth: true, requireFeatures: ["payment_gateways.manage"] }
|
|
10
|
+
};
|
|
11
|
+
async function POST(req) {
|
|
12
|
+
const auth = await getAuthFromRequest(req);
|
|
13
|
+
if (!auth?.tenantId || !auth.orgId) {
|
|
14
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
15
|
+
}
|
|
16
|
+
const payload = await readJsonSafe(req);
|
|
17
|
+
const parsed = createSessionSchema.safeParse(payload);
|
|
18
|
+
if (!parsed.success) {
|
|
19
|
+
return NextResponse.json({ error: "Invalid payload", details: parsed.error.flatten() }, { status: 422 });
|
|
20
|
+
}
|
|
21
|
+
const container = await createRequestContainer();
|
|
22
|
+
const service = container.resolve("paymentGatewayService");
|
|
23
|
+
try {
|
|
24
|
+
const { transaction, session } = await service.createPaymentSession({
|
|
25
|
+
providerKey: parsed.data.providerKey,
|
|
26
|
+
paymentId: crypto.randomUUID(),
|
|
27
|
+
orderId: parsed.data.orderId,
|
|
28
|
+
amount: parsed.data.amount,
|
|
29
|
+
currencyCode: parsed.data.currencyCode,
|
|
30
|
+
captureMethod: parsed.data.captureMethod,
|
|
31
|
+
description: parsed.data.description,
|
|
32
|
+
successUrl: parsed.data.successUrl,
|
|
33
|
+
cancelUrl: parsed.data.cancelUrl,
|
|
34
|
+
metadata: parsed.data.metadata,
|
|
35
|
+
organizationId: auth.orgId,
|
|
36
|
+
tenantId: auth.tenantId
|
|
37
|
+
});
|
|
38
|
+
return NextResponse.json({
|
|
39
|
+
transactionId: transaction.id,
|
|
40
|
+
sessionId: session.sessionId,
|
|
41
|
+
providerKey: transaction.providerKey,
|
|
42
|
+
clientSecret: session.clientSecret,
|
|
43
|
+
redirectUrl: session.redirectUrl,
|
|
44
|
+
providerData: session.providerData ?? null,
|
|
45
|
+
status: session.status,
|
|
46
|
+
paymentId: transaction.paymentId
|
|
47
|
+
}, { status: 201 });
|
|
48
|
+
} catch (err) {
|
|
49
|
+
const message = err instanceof Error ? err.message : "Failed to create payment session";
|
|
50
|
+
const status = message.includes("No gateway adapter") ? 422 : 502;
|
|
51
|
+
return NextResponse.json({ error: message }, { status });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const openApi = {
|
|
55
|
+
tags: [paymentGatewaysTag],
|
|
56
|
+
summary: "Create a payment session via a gateway provider",
|
|
57
|
+
methods: {
|
|
58
|
+
POST: {
|
|
59
|
+
summary: "Create payment session",
|
|
60
|
+
tags: [paymentGatewaysTag],
|
|
61
|
+
responses: [
|
|
62
|
+
{ status: 201, description: "Payment session created" },
|
|
63
|
+
{ status: 422, description: "Invalid payload or unknown provider" },
|
|
64
|
+
{ status: 502, description: "Gateway provider error" }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
export {
|
|
70
|
+
POST,
|
|
71
|
+
metadata,
|
|
72
|
+
openApi
|
|
73
|
+
};
|
|
74
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/payment_gateways/api/sessions/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { readJsonSafe } from '@open-mercato/shared/lib/http/readJsonSafe'\nimport { createSessionSchema } from '../../data/validators'\nimport type { PaymentGatewayService } from '../../lib/gateway-service'\nimport { paymentGatewaysTag } from '../openapi'\n\nexport const metadata = {\n path: '/payment_gateways/sessions',\n POST: { requireAuth: true, requireFeatures: ['payment_gateways.manage'] },\n}\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const payload = await readJsonSafe<unknown>(req)\n const parsed = createSessionSchema.safeParse(payload)\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid payload', details: parsed.error.flatten() }, { status: 422 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve('paymentGatewayService') as PaymentGatewayService\n\n try {\n const { transaction, session } = await service.createPaymentSession({\n providerKey: parsed.data.providerKey,\n paymentId: crypto.randomUUID(),\n orderId: parsed.data.orderId,\n amount: parsed.data.amount,\n currencyCode: parsed.data.currencyCode,\n captureMethod: parsed.data.captureMethod,\n description: parsed.data.description,\n successUrl: parsed.data.successUrl,\n cancelUrl: parsed.data.cancelUrl,\n metadata: parsed.data.metadata,\n organizationId: auth.orgId as string,\n tenantId: auth.tenantId,\n })\n\n return NextResponse.json({\n transactionId: transaction.id,\n sessionId: session.sessionId,\n providerKey: transaction.providerKey,\n clientSecret: session.clientSecret,\n redirectUrl: session.redirectUrl,\n providerData: session.providerData ?? null,\n status: session.status,\n paymentId: transaction.paymentId,\n }, { status: 201 })\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to create payment session'\n const status = message.includes('No gateway adapter') ? 422 : 502\n return NextResponse.json({ error: message }, { status })\n }\n}\n\nexport const openApi = {\n tags: [paymentGatewaysTag],\n summary: 'Create a payment session via a gateway provider',\n methods: {\n POST: {\n summary: 'Create payment session',\n tags: [paymentGatewaysTag],\n responses: [\n { status: 201, description: 'Payment session created' },\n { status: 422, description: 'Invalid payload or unknown provider' },\n { status: 502, description: 'Gateway provider error' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,oBAAoB;AAC7B,SAAS,2BAA2B;AAEpC,SAAS,0BAA0B;AAE5B,MAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAC1E;AAEA,eAAsB,KAAK,KAAc;AACvC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,UAAU,MAAM,aAAsB,GAAG;AAC/C,QAAM,SAAS,oBAAoB,UAAU,OAAO;AACpD,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,OAAO,mBAAmB,SAAS,OAAO,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACzG;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,UAAU,UAAU,QAAQ,uBAAuB;AAEzD,MAAI;AACF,UAAM,EAAE,aAAa,QAAQ,IAAI,MAAM,QAAQ,qBAAqB;AAAA,MAClE,aAAa,OAAO,KAAK;AAAA,MACzB,WAAW,OAAO,WAAW;AAAA,MAC7B,SAAS,OAAO,KAAK;AAAA,MACrB,QAAQ,OAAO,KAAK;AAAA,MACpB,cAAc,OAAO,KAAK;AAAA,MAC1B,eAAe,OAAO,KAAK;AAAA,MAC3B,aAAa,OAAO,KAAK;AAAA,MACzB,YAAY,OAAO,KAAK;AAAA,MACxB,WAAW,OAAO,KAAK;AAAA,MACvB,UAAU,OAAO,KAAK;AAAA,MACtB,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,IACjB,CAAC;AAED,WAAO,aAAa,KAAK;AAAA,MACvB,eAAe,YAAY;AAAA,MAC3B,WAAW,QAAQ;AAAA,MACnB,aAAa,YAAY;AAAA,MACzB,cAAc,QAAQ;AAAA,MACtB,aAAa,QAAQ;AAAA,MACrB,cAAc,QAAQ,gBAAgB;AAAA,MACtC,QAAQ,QAAQ;AAAA,MAChB,WAAW,YAAY;AAAA,IACzB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACpB,SAAS,KAAc;AACrB,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,UAAM,SAAS,QAAQ,SAAS,oBAAoB,IAAI,MAAM;AAC9D,WAAO,aAAa,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,OAAO,CAAC;AAAA,EACzD;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,kBAAkB;AAAA,EACzB,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,MAAM,CAAC,kBAAkB;AAAA,MACzB,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,0BAA0B;AAAA,QACtD,EAAE,QAAQ,KAAK,aAAa,sCAAsC;AAAA,QAClE,EAAE,QAAQ,KAAK,aAAa,yBAAyB;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { paymentGatewaysTag } from "../openapi.js";
|
|
5
|
+
const metadata = {
|
|
6
|
+
path: "/payment_gateways/status",
|
|
7
|
+
GET: { requireAuth: true, requireFeatures: ["payment_gateways.view"] }
|
|
8
|
+
};
|
|
9
|
+
async function GET(req) {
|
|
10
|
+
const auth = await getAuthFromRequest(req);
|
|
11
|
+
if (!auth?.tenantId || !auth.orgId) {
|
|
12
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
13
|
+
}
|
|
14
|
+
const url = new URL(req.url);
|
|
15
|
+
const transactionId = url.searchParams.get("transactionId");
|
|
16
|
+
if (!transactionId) {
|
|
17
|
+
return NextResponse.json({ error: "transactionId is required" }, { status: 400 });
|
|
18
|
+
}
|
|
19
|
+
const container = await createRequestContainer();
|
|
20
|
+
const service = container.resolve("paymentGatewayService");
|
|
21
|
+
try {
|
|
22
|
+
const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
|
|
23
|
+
const transaction = await service.findTransaction(transactionId, scope);
|
|
24
|
+
if (!transaction) {
|
|
25
|
+
return NextResponse.json({ error: "Transaction not found" }, { status: 404 });
|
|
26
|
+
}
|
|
27
|
+
const status = await service.getPaymentStatus(transactionId, scope);
|
|
28
|
+
return NextResponse.json({
|
|
29
|
+
transactionId: transaction.id,
|
|
30
|
+
paymentId: transaction.paymentId,
|
|
31
|
+
providerKey: transaction.providerKey,
|
|
32
|
+
sessionId: transaction.providerSessionId,
|
|
33
|
+
status: status.status,
|
|
34
|
+
gatewayStatus: transaction.gatewayStatus,
|
|
35
|
+
amount: status.amount,
|
|
36
|
+
amountReceived: status.amountReceived,
|
|
37
|
+
currencyCode: status.currencyCode,
|
|
38
|
+
redirectUrl: transaction.redirectUrl,
|
|
39
|
+
createdAt: transaction.createdAt.toISOString(),
|
|
40
|
+
updatedAt: transaction.updatedAt.toISOString()
|
|
41
|
+
});
|
|
42
|
+
} catch (err) {
|
|
43
|
+
const message = err instanceof Error ? err.message : "Failed to get status";
|
|
44
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const openApi = {
|
|
48
|
+
tags: [paymentGatewaysTag],
|
|
49
|
+
summary: "Get payment transaction status",
|
|
50
|
+
methods: {
|
|
51
|
+
GET: {
|
|
52
|
+
summary: "Get transaction status",
|
|
53
|
+
tags: [paymentGatewaysTag],
|
|
54
|
+
responses: [
|
|
55
|
+
{ status: 200, description: "Transaction status" },
|
|
56
|
+
{ status: 404, description: "Transaction not found" }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
export {
|
|
62
|
+
GET,
|
|
63
|
+
metadata,
|
|
64
|
+
openApi
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/payment_gateways/api/status/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { PaymentGatewayService } from '../../lib/gateway-service'\nimport { paymentGatewaysTag } from '../openapi'\n\nexport const metadata = {\n path: '/payment_gateways/status',\n GET: { requireAuth: true, requireFeatures: ['payment_gateways.view'] },\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const transactionId = url.searchParams.get('transactionId')\n if (!transactionId) {\n return NextResponse.json({ error: 'transactionId is required' }, { status: 400 })\n }\n\n const container = await createRequestContainer()\n const service = container.resolve('paymentGatewayService') as PaymentGatewayService\n\n try {\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n const transaction = await service.findTransaction(transactionId, scope)\n if (!transaction) {\n return NextResponse.json({ error: 'Transaction not found' }, { status: 404 })\n }\n\n const status = await service.getPaymentStatus(transactionId, scope)\n\n return NextResponse.json({\n transactionId: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n sessionId: transaction.providerSessionId,\n status: status.status,\n gatewayStatus: transaction.gatewayStatus,\n amount: status.amount,\n amountReceived: status.amountReceived,\n currencyCode: status.currencyCode,\n redirectUrl: transaction.redirectUrl,\n createdAt: transaction.createdAt.toISOString(),\n updatedAt: transaction.updatedAt.toISOString(),\n })\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : 'Failed to get status'\n return NextResponse.json({ error: message }, { status: 500 })\n }\n}\n\nexport const openApi = {\n tags: [paymentGatewaysTag],\n summary: 'Get payment transaction status',\n methods: {\n GET: {\n summary: 'Get transaction status',\n tags: [paymentGatewaysTag],\n responses: [\n { status: 200, description: 'Transaction status' },\n { status: 404, description: 'Transaction not found' },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AAEvC,SAAS,0BAA0B;AAE5B,MAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AACvE;AAEA,eAAsB,IAAI,KAAc;AACtC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,gBAAgB,IAAI,aAAa,IAAI,eAAe;AAC1D,MAAI,CAAC,eAAe;AAClB,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AAEA,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,UAAU,UAAU,QAAQ,uBAAuB;AAEzD,MAAI;AACF,UAAM,QAAQ,EAAE,gBAAgB,KAAK,OAAiB,UAAU,KAAK,SAAS;AAC9E,UAAM,cAAc,MAAM,QAAQ,gBAAgB,eAAe,KAAK;AACtE,QAAI,CAAC,aAAa;AAChB,aAAO,aAAa,KAAK,EAAE,OAAO,wBAAwB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC9E;AAEA,UAAM,SAAS,MAAM,QAAQ,iBAAiB,eAAe,KAAK;AAElE,WAAO,aAAa,KAAK;AAAA,MACvB,eAAe,YAAY;AAAA,MAC3B,WAAW,YAAY;AAAA,MACvB,aAAa,YAAY;AAAA,MACzB,WAAW,YAAY;AAAA,MACvB,QAAQ,OAAO;AAAA,MACf,eAAe,YAAY;AAAA,MAC3B,QAAQ,OAAO;AAAA,MACf,gBAAgB,OAAO;AAAA,MACvB,cAAc,OAAO;AAAA,MACrB,aAAa,YAAY;AAAA,MACzB,WAAW,YAAY,UAAU,YAAY;AAAA,MAC7C,WAAW,YAAY,UAAU,YAAY;AAAA,IAC/C,CAAC;AAAA,EACH,SAAS,KAAc;AACrB,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,WAAO,aAAa,KAAK,EAAE,OAAO,QAAQ,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC9D;AACF;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,kBAAkB;AAAA,EACzB,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,MAAM,CAAC,kBAAkB;AAAA,MACzB,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,qBAAqB;AAAA,QACjD,EAAE,QAAQ,KAAK,aAAa,wBAAwB;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
5
|
+
import { GatewayTransaction } from "../../../data/entities.js";
|
|
6
|
+
import { paymentGatewaysTag } from "../../openapi.js";
|
|
7
|
+
const metadata = {
|
|
8
|
+
path: "/payment_gateways/transactions/[id]",
|
|
9
|
+
GET: { requireAuth: true, requireFeatures: ["payment_gateways.view"] }
|
|
10
|
+
};
|
|
11
|
+
function toIsoString(value) {
|
|
12
|
+
if (!value) return null;
|
|
13
|
+
if (value instanceof Date) return value.toISOString();
|
|
14
|
+
if (typeof value === "string") {
|
|
15
|
+
const parsed2 = new Date(value);
|
|
16
|
+
if (!Number.isNaN(parsed2.getTime())) return parsed2.toISOString();
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
const parsed = new Date(value);
|
|
20
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString();
|
|
21
|
+
}
|
|
22
|
+
async function GET(req, { params }) {
|
|
23
|
+
const auth = await getAuthFromRequest(req);
|
|
24
|
+
if (!auth?.tenantId || !auth.orgId) {
|
|
25
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
26
|
+
}
|
|
27
|
+
const resolvedParams = await params;
|
|
28
|
+
const transactionId = resolvedParams?.id;
|
|
29
|
+
if (!transactionId) {
|
|
30
|
+
return NextResponse.json({ error: "Transaction id is required" }, { status: 400 });
|
|
31
|
+
}
|
|
32
|
+
const { resolve } = await createRequestContainer();
|
|
33
|
+
const scope = { organizationId: auth.orgId, tenantId: auth.tenantId };
|
|
34
|
+
const em = resolve("em");
|
|
35
|
+
const integrationLogService = resolve("integrationLogService");
|
|
36
|
+
const transaction = await findOneWithDecryption(
|
|
37
|
+
em,
|
|
38
|
+
GatewayTransaction,
|
|
39
|
+
{
|
|
40
|
+
id: transactionId,
|
|
41
|
+
organizationId: scope.organizationId,
|
|
42
|
+
tenantId: scope.tenantId,
|
|
43
|
+
deletedAt: null
|
|
44
|
+
},
|
|
45
|
+
void 0,
|
|
46
|
+
scope
|
|
47
|
+
);
|
|
48
|
+
if (!transaction) {
|
|
49
|
+
return NextResponse.json({ error: "Transaction not found" }, { status: 404 });
|
|
50
|
+
}
|
|
51
|
+
const integrationId = `gateway_${transaction.providerKey}`;
|
|
52
|
+
const { items: logRows } = await integrationLogService.query(
|
|
53
|
+
{
|
|
54
|
+
integrationId,
|
|
55
|
+
entityType: "payment_transaction",
|
|
56
|
+
entityId: transactionId,
|
|
57
|
+
page: 1,
|
|
58
|
+
pageSize: 100
|
|
59
|
+
},
|
|
60
|
+
scope
|
|
61
|
+
);
|
|
62
|
+
return NextResponse.json({
|
|
63
|
+
transaction: {
|
|
64
|
+
id: transaction.id,
|
|
65
|
+
paymentId: transaction.paymentId,
|
|
66
|
+
providerKey: transaction.providerKey,
|
|
67
|
+
providerSessionId: transaction.providerSessionId ?? null,
|
|
68
|
+
gatewayPaymentId: transaction.gatewayPaymentId ?? null,
|
|
69
|
+
gatewayRefundId: transaction.gatewayRefundId ?? null,
|
|
70
|
+
unifiedStatus: transaction.unifiedStatus,
|
|
71
|
+
gatewayStatus: transaction.gatewayStatus ?? null,
|
|
72
|
+
redirectUrl: transaction.redirectUrl ?? null,
|
|
73
|
+
amount: transaction.amount,
|
|
74
|
+
currencyCode: transaction.currencyCode,
|
|
75
|
+
gatewayMetadata: transaction.gatewayMetadata ?? null,
|
|
76
|
+
webhookLog: Array.isArray(transaction.webhookLog) ? transaction.webhookLog : [],
|
|
77
|
+
lastWebhookAt: toIsoString(transaction.lastWebhookAt),
|
|
78
|
+
lastPolledAt: toIsoString(transaction.lastPolledAt),
|
|
79
|
+
expiresAt: toIsoString(transaction.expiresAt),
|
|
80
|
+
createdAt: toIsoString(transaction.createdAt),
|
|
81
|
+
updatedAt: toIsoString(transaction.updatedAt)
|
|
82
|
+
},
|
|
83
|
+
logs: logRows.map((row) => ({
|
|
84
|
+
id: row.id,
|
|
85
|
+
integrationId: row.integrationId,
|
|
86
|
+
runId: row.runId ?? null,
|
|
87
|
+
scopeEntityType: row.scopeEntityType ?? null,
|
|
88
|
+
scopeEntityId: row.scopeEntityId ?? null,
|
|
89
|
+
level: row.level,
|
|
90
|
+
message: row.message,
|
|
91
|
+
code: row.code ?? null,
|
|
92
|
+
payload: row.payload ?? null,
|
|
93
|
+
createdAt: toIsoString(row.createdAt)
|
|
94
|
+
}))
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
const openApi = {
|
|
98
|
+
tags: [paymentGatewaysTag],
|
|
99
|
+
summary: "Get payment transaction details",
|
|
100
|
+
methods: {
|
|
101
|
+
GET: {
|
|
102
|
+
summary: "Get payment transaction details",
|
|
103
|
+
tags: [paymentGatewaysTag],
|
|
104
|
+
responses: [
|
|
105
|
+
{ status: 200, description: "Payment transaction details" },
|
|
106
|
+
{ status: 404, description: "Transaction not found" }
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var route_default = GET;
|
|
112
|
+
export {
|
|
113
|
+
GET,
|
|
114
|
+
route_default as default,
|
|
115
|
+
metadata,
|
|
116
|
+
openApi
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/payment_gateways/api/transactions/%5Bid%5D/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport type { IntegrationLogService } from '../../../../integrations/lib/log-service'\nimport { GatewayTransaction } from '../../../data/entities'\nimport { paymentGatewaysTag } from '../../openapi'\n\nexport const metadata = {\n path: '/payment_gateways/transactions/[id]',\n GET: { requireAuth: true, requireFeatures: ['payment_gateways.view'] },\n}\n\nfunction toIsoString(value: unknown): string | null {\n if (!value) return null\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string') {\n const parsed = new Date(value)\n if (!Number.isNaN(parsed.getTime())) return parsed.toISOString()\n return value\n }\n const parsed = new Date(value as string | number)\n return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString()\n}\n\nexport async function GET(req: Request, { params }: { params: Promise<{ id: string }> | { id: string } }) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const resolvedParams = await params\n const transactionId = resolvedParams?.id\n if (!transactionId) {\n return NextResponse.json({ error: 'Transaction id is required' }, { status: 400 })\n }\n\n const { resolve } = await createRequestContainer()\n const scope = { organizationId: auth.orgId as string, tenantId: auth.tenantId }\n const em = resolve('em') as EntityManager\n const integrationLogService = resolve('integrationLogService') as IntegrationLogService\n const transaction = await findOneWithDecryption(\n em,\n GatewayTransaction,\n {\n id: transactionId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n },\n undefined,\n scope,\n )\n\n if (!transaction) {\n return NextResponse.json({ error: 'Transaction not found' }, { status: 404 })\n }\n\n const integrationId = `gateway_${transaction.providerKey}`\n const { items: logRows } = await integrationLogService.query(\n {\n integrationId,\n entityType: 'payment_transaction',\n entityId: transactionId,\n page: 1,\n pageSize: 100,\n },\n scope,\n )\n\n return NextResponse.json({\n transaction: {\n id: transaction.id,\n paymentId: transaction.paymentId,\n providerKey: transaction.providerKey,\n providerSessionId: transaction.providerSessionId ?? null,\n gatewayPaymentId: transaction.gatewayPaymentId ?? null,\n gatewayRefundId: transaction.gatewayRefundId ?? null,\n unifiedStatus: transaction.unifiedStatus,\n gatewayStatus: transaction.gatewayStatus ?? null,\n redirectUrl: transaction.redirectUrl ?? null,\n amount: transaction.amount,\n currencyCode: transaction.currencyCode,\n gatewayMetadata: transaction.gatewayMetadata ?? null,\n webhookLog: Array.isArray(transaction.webhookLog) ? transaction.webhookLog : [],\n lastWebhookAt: toIsoString(transaction.lastWebhookAt),\n lastPolledAt: toIsoString(transaction.lastPolledAt),\n expiresAt: toIsoString(transaction.expiresAt),\n createdAt: toIsoString(transaction.createdAt),\n updatedAt: toIsoString(transaction.updatedAt),\n },\n logs: logRows.map((row) => ({\n id: row.id,\n integrationId: row.integrationId,\n runId: row.runId ?? null,\n scopeEntityType: row.scopeEntityType ?? null,\n scopeEntityId: row.scopeEntityId ?? null,\n level: row.level,\n message: row.message,\n code: row.code ?? null,\n payload: row.payload ?? null,\n createdAt: toIsoString(row.createdAt),\n })),\n })\n}\n\nexport const openApi = {\n tags: [paymentGatewaysTag],\n summary: 'Get payment transaction details',\n methods: {\n GET: {\n summary: 'Get payment transaction details',\n tags: [paymentGatewaysTag],\n responses: [\n { status: 200, description: 'Payment transaction details' },\n { status: 404, description: 'Transaction not found' },\n ],\n },\n },\n}\n\nexport default GET\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["parsed"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { getAuthFromRequest } from "@open-mercato/shared/lib/auth/server";
|
|
3
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
4
|
+
import { GatewayTransaction } from "../../data/entities.js";
|
|
5
|
+
import { listTransactionsQuerySchema } from "../../data/validators.js";
|
|
6
|
+
import { paymentGatewaysTag } from "../openapi.js";
|
|
7
|
+
const metadata = {
|
|
8
|
+
path: "/payment_gateways/transactions",
|
|
9
|
+
GET: { requireAuth: true, requireFeatures: ["payment_gateways.view"] }
|
|
10
|
+
};
|
|
11
|
+
function escapeLikePattern(value) {
|
|
12
|
+
return value.replace(/[\\%_]/g, "\\$&");
|
|
13
|
+
}
|
|
14
|
+
function formatDateValue(value) {
|
|
15
|
+
if (!value) return null;
|
|
16
|
+
if (value instanceof Date) return value.toISOString();
|
|
17
|
+
if (typeof value === "string") {
|
|
18
|
+
const parsed = new Date(value);
|
|
19
|
+
if (!Number.isNaN(parsed.getTime())) return parsed.toISOString();
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
const fallback = new Date(value);
|
|
23
|
+
return Number.isNaN(fallback.getTime()) ? null : fallback.toISOString();
|
|
24
|
+
}
|
|
25
|
+
async function GET(req) {
|
|
26
|
+
const auth = await getAuthFromRequest(req);
|
|
27
|
+
if (!auth?.tenantId || !auth.orgId) {
|
|
28
|
+
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
29
|
+
}
|
|
30
|
+
const url = new URL(req.url);
|
|
31
|
+
const parsed = listTransactionsQuerySchema.safeParse(Object.fromEntries(url.searchParams.entries()));
|
|
32
|
+
if (!parsed.success) {
|
|
33
|
+
return NextResponse.json({ error: "Invalid query", details: parsed.error.flatten() }, { status: 400 });
|
|
34
|
+
}
|
|
35
|
+
const { page, pageSize, search, providerKey, status } = parsed.data;
|
|
36
|
+
const offset = (page - 1) * pageSize;
|
|
37
|
+
const { resolve } = await createRequestContainer();
|
|
38
|
+
const em = resolve("em");
|
|
39
|
+
const qb = em.createQueryBuilder(GatewayTransaction, "gt");
|
|
40
|
+
qb.where({
|
|
41
|
+
organizationId: auth.orgId,
|
|
42
|
+
tenantId: auth.tenantId,
|
|
43
|
+
deletedAt: null
|
|
44
|
+
});
|
|
45
|
+
if (providerKey) {
|
|
46
|
+
qb.andWhere({ providerKey });
|
|
47
|
+
}
|
|
48
|
+
if (status) {
|
|
49
|
+
qb.andWhere({ unifiedStatus: status });
|
|
50
|
+
}
|
|
51
|
+
if (search) {
|
|
52
|
+
const pattern = `%${escapeLikePattern(search)}%`;
|
|
53
|
+
qb.andWhere(`(
|
|
54
|
+
cast(gt.id as text) ilike ?
|
|
55
|
+
or cast(gt.payment_id as text) ilike ?
|
|
56
|
+
or coalesce(gt.provider_key, '') ilike ?
|
|
57
|
+
or coalesce(gt.provider_session_id, '') ilike ?
|
|
58
|
+
or coalesce(gt.gateway_payment_id, '') ilike ?
|
|
59
|
+
or coalesce(gt.gateway_refund_id, '') ilike ?
|
|
60
|
+
) escape '\\'`, [pattern, pattern, pattern, pattern, pattern, pattern]);
|
|
61
|
+
}
|
|
62
|
+
const countQb = qb.clone();
|
|
63
|
+
qb.orderBy({ createdAt: "desc" });
|
|
64
|
+
qb.limit(pageSize).offset(offset);
|
|
65
|
+
const [items, total] = await Promise.all([
|
|
66
|
+
qb.getResultList(),
|
|
67
|
+
countQb.count("gt.id", true)
|
|
68
|
+
]);
|
|
69
|
+
return NextResponse.json({
|
|
70
|
+
items: items.map((item) => ({
|
|
71
|
+
id: item.id,
|
|
72
|
+
paymentId: item.paymentId,
|
|
73
|
+
providerKey: item.providerKey,
|
|
74
|
+
providerSessionId: item.providerSessionId ?? null,
|
|
75
|
+
gatewayPaymentId: item.gatewayPaymentId ?? null,
|
|
76
|
+
gatewayRefundId: item.gatewayRefundId ?? null,
|
|
77
|
+
unifiedStatus: item.unifiedStatus,
|
|
78
|
+
gatewayStatus: item.gatewayStatus ?? null,
|
|
79
|
+
amount: item.amount,
|
|
80
|
+
currencyCode: item.currencyCode,
|
|
81
|
+
redirectUrl: item.redirectUrl ?? null,
|
|
82
|
+
lastWebhookAt: formatDateValue(item.lastWebhookAt),
|
|
83
|
+
lastPolledAt: formatDateValue(item.lastPolledAt),
|
|
84
|
+
createdAt: formatDateValue(item.createdAt),
|
|
85
|
+
updatedAt: formatDateValue(item.updatedAt)
|
|
86
|
+
})),
|
|
87
|
+
total,
|
|
88
|
+
page,
|
|
89
|
+
pageSize,
|
|
90
|
+
totalPages: Math.max(1, Math.ceil(total / pageSize))
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
const openApi = {
|
|
94
|
+
tags: [paymentGatewaysTag],
|
|
95
|
+
summary: "List payment transactions",
|
|
96
|
+
methods: {
|
|
97
|
+
GET: {
|
|
98
|
+
summary: "List payment transactions",
|
|
99
|
+
tags: [paymentGatewaysTag],
|
|
100
|
+
responses: [
|
|
101
|
+
{ status: 200, description: "Payment transaction list" }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
var route_default = GET;
|
|
107
|
+
export {
|
|
108
|
+
GET,
|
|
109
|
+
route_default as default,
|
|
110
|
+
metadata,
|
|
111
|
+
openApi
|
|
112
|
+
};
|
|
113
|
+
//# sourceMappingURL=route.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/payment_gateways/api/transactions/route.ts"],
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { GatewayTransaction } from '../../data/entities'\nimport { listTransactionsQuerySchema } from '../../data/validators'\nimport { paymentGatewaysTag } from '../openapi'\n\nexport const metadata = {\n path: '/payment_gateways/transactions',\n GET: { requireAuth: true, requireFeatures: ['payment_gateways.view'] },\n}\n\nfunction escapeLikePattern(value: string): string {\n return value.replace(/[\\\\%_]/g, '\\\\$&')\n}\n\nfunction formatDateValue(value: unknown): string | null {\n if (!value) return null\n if (value instanceof Date) return value.toISOString()\n if (typeof value === 'string') {\n const parsed = new Date(value)\n if (!Number.isNaN(parsed.getTime())) return parsed.toISOString()\n return value\n }\n const fallback = new Date(value as string | number)\n return Number.isNaN(fallback.getTime()) ? null : fallback.toISOString()\n}\n\nexport async function GET(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth?.tenantId || !auth.orgId) {\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n }\n\n const url = new URL(req.url)\n const parsed = listTransactionsQuerySchema.safeParse(Object.fromEntries(url.searchParams.entries()))\n if (!parsed.success) {\n return NextResponse.json({ error: 'Invalid query', details: parsed.error.flatten() }, { status: 400 })\n }\n\n const { page, pageSize, search, providerKey, status } = parsed.data\n const offset = (page - 1) * pageSize\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n const qb = em.createQueryBuilder(GatewayTransaction, 'gt')\n\n qb.where({\n organizationId: auth.orgId,\n tenantId: auth.tenantId,\n deletedAt: null,\n })\n\n if (providerKey) {\n qb.andWhere({ providerKey })\n }\n if (status) {\n qb.andWhere({ unifiedStatus: status })\n }\n if (search) {\n const pattern = `%${escapeLikePattern(search)}%`\n qb.andWhere(`(\n cast(gt.id as text) ilike ?\n or cast(gt.payment_id as text) ilike ?\n or coalesce(gt.provider_key, '') ilike ?\n or coalesce(gt.provider_session_id, '') ilike ?\n or coalesce(gt.gateway_payment_id, '') ilike ?\n or coalesce(gt.gateway_refund_id, '') ilike ?\n ) escape '\\\\'`, [pattern, pattern, pattern, pattern, pattern, pattern])\n }\n\n const countQb = qb.clone()\n qb.orderBy({ createdAt: 'desc' })\n qb.limit(pageSize).offset(offset)\n\n const [items, total] = await Promise.all([\n qb.getResultList(),\n countQb.count('gt.id', true),\n ])\n\n return NextResponse.json({\n items: items.map((item) => ({\n id: item.id,\n paymentId: item.paymentId,\n providerKey: item.providerKey,\n providerSessionId: item.providerSessionId ?? null,\n gatewayPaymentId: item.gatewayPaymentId ?? null,\n gatewayRefundId: item.gatewayRefundId ?? null,\n unifiedStatus: item.unifiedStatus,\n gatewayStatus: item.gatewayStatus ?? null,\n amount: item.amount,\n currencyCode: item.currencyCode,\n redirectUrl: item.redirectUrl ?? null,\n lastWebhookAt: formatDateValue(item.lastWebhookAt),\n lastPolledAt: formatDateValue(item.lastPolledAt),\n createdAt: formatDateValue(item.createdAt),\n updatedAt: formatDateValue(item.updatedAt),\n })),\n total,\n page,\n pageSize,\n totalPages: Math.max(1, Math.ceil(total / pageSize)),\n })\n}\n\nexport const openApi = {\n tags: [paymentGatewaysTag],\n summary: 'List payment transactions',\n methods: {\n GET: {\n summary: 'List payment transactions',\n tags: [paymentGatewaysTag],\n responses: [\n { status: 200, description: 'Payment transaction list' },\n ],\n },\n },\n}\n\nexport default GET\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAE7B,SAAS,0BAA0B;AACnC,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,mCAAmC;AAC5C,SAAS,0BAA0B;AAE5B,MAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AACvE;AAEA,SAAS,kBAAkB,OAAuB;AAChD,SAAO,MAAM,QAAQ,WAAW,MAAM;AACxC;AAEA,SAAS,gBAAgB,OAA+B;AACtD,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,iBAAiB,KAAM,QAAO,MAAM,YAAY;AACpD,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAAS,IAAI,KAAK,KAAK;AAC7B,QAAI,CAAC,OAAO,MAAM,OAAO,QAAQ,CAAC,EAAG,QAAO,OAAO,YAAY;AAC/D,WAAO;AAAA,EACT;AACA,QAAM,WAAW,IAAI,KAAK,KAAwB;AAClD,SAAO,OAAO,MAAM,SAAS,QAAQ,CAAC,IAAI,OAAO,SAAS,YAAY;AACxE;AAEA,eAAsB,IAAI,KAAc;AACtC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,MAAM,YAAY,CAAC,KAAK,OAAO;AAClC,WAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACrE;AAEA,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,QAAM,SAAS,4BAA4B,UAAU,OAAO,YAAY,IAAI,aAAa,QAAQ,CAAC,CAAC;AACnG,MAAI,CAAC,OAAO,SAAS;AACnB,WAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,SAAS,OAAO,MAAM,QAAQ,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACvG;AAEA,QAAM,EAAE,MAAM,UAAU,QAAQ,aAAa,OAAO,IAAI,OAAO;AAC/D,QAAM,UAAU,OAAO,KAAK;AAC5B,QAAM,EAAE,QAAQ,IAAI,MAAM,uBAAuB;AACjD,QAAM,KAAK,QAAQ,IAAI;AACvB,QAAM,KAAK,GAAG,mBAAmB,oBAAoB,IAAI;AAEzD,KAAG,MAAM;AAAA,IACP,gBAAgB,KAAK;AAAA,IACrB,UAAU,KAAK;AAAA,IACf,WAAW;AAAA,EACb,CAAC;AAED,MAAI,aAAa;AACf,OAAG,SAAS,EAAE,YAAY,CAAC;AAAA,EAC7B;AACA,MAAI,QAAQ;AACV,OAAG,SAAS,EAAE,eAAe,OAAO,CAAC;AAAA,EACvC;AACA,MAAI,QAAQ;AACV,UAAM,UAAU,IAAI,kBAAkB,MAAM,CAAC;AAC7C,OAAG,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOI,CAAC,SAAS,SAAS,SAAS,SAAS,SAAS,OAAO,CAAC;AAAA,EACxE;AAEA,QAAM,UAAU,GAAG,MAAM;AACzB,KAAG,QAAQ,EAAE,WAAW,OAAO,CAAC;AAChC,KAAG,MAAM,QAAQ,EAAE,OAAO,MAAM;AAEhC,QAAM,CAAC,OAAO,KAAK,IAAI,MAAM,QAAQ,IAAI;AAAA,IACvC,GAAG,cAAc;AAAA,IACjB,QAAQ,MAAM,SAAS,IAAI;AAAA,EAC7B,CAAC;AAED,SAAO,aAAa,KAAK;AAAA,IACvB,OAAO,MAAM,IAAI,CAAC,UAAU;AAAA,MAC1B,IAAI,KAAK;AAAA,MACT,WAAW,KAAK;AAAA,MAChB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK,qBAAqB;AAAA,MAC7C,kBAAkB,KAAK,oBAAoB;AAAA,MAC3C,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,eAAe,KAAK;AAAA,MACpB,eAAe,KAAK,iBAAiB;AAAA,MACrC,QAAQ,KAAK;AAAA,MACb,cAAc,KAAK;AAAA,MACnB,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe,gBAAgB,KAAK,aAAa;AAAA,MACjD,cAAc,gBAAgB,KAAK,YAAY;AAAA,MAC/C,WAAW,gBAAgB,KAAK,SAAS;AAAA,MACzC,WAAW,gBAAgB,KAAK,SAAS;AAAA,IAC3C,EAAE;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,KAAK,IAAI,GAAG,KAAK,KAAK,QAAQ,QAAQ,CAAC;AAAA,EACrD,CAAC;AACH;AAEO,MAAM,UAAU;AAAA,EACrB,MAAM,CAAC,kBAAkB;AAAA,EACzB,SAAS;AAAA,EACT,SAAS;AAAA,IACP,KAAK;AAAA,MACH,SAAS;AAAA,MACT,MAAM,CAAC,kBAAkB;AAAA,MACzB,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,2BAA2B;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { NextResponse } from "next/server";
|
|
2
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
3
|
+
import { findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
4
|
+
import { readJsonSafe } from "@open-mercato/shared/lib/http/readJsonSafe";
|
|
5
|
+
import { getWebhookHandler } from "@open-mercato/shared/modules/payment_gateways/types";
|
|
6
|
+
import { GatewayTransaction } from "../../../data/entities.js";
|
|
7
|
+
import { getPaymentGatewayQueue } from "../../../lib/queue.js";
|
|
8
|
+
import { processPaymentGatewayWebhookJob } from "../../../lib/webhook-processor.js";
|
|
9
|
+
import { paymentGatewaysTag } from "../../openapi.js";
|
|
10
|
+
const metadata = {
|
|
11
|
+
path: "/payment_gateways/webhook/[provider]",
|
|
12
|
+
POST: { requireAuth: false }
|
|
13
|
+
};
|
|
14
|
+
function readScopeFromEventData(data) {
|
|
15
|
+
const metadata2 = data.metadata;
|
|
16
|
+
if (!metadata2 || typeof metadata2 !== "object") return null;
|
|
17
|
+
const metadataRecord = metadata2;
|
|
18
|
+
const organizationId = typeof metadataRecord.organizationId === "string" ? metadataRecord.organizationId.trim() : "";
|
|
19
|
+
const tenantId = typeof metadataRecord.tenantId === "string" ? metadataRecord.tenantId.trim() : "";
|
|
20
|
+
if (!organizationId || !tenantId) return null;
|
|
21
|
+
return { organizationId, tenantId };
|
|
22
|
+
}
|
|
23
|
+
async function POST(req, { params }) {
|
|
24
|
+
const resolvedParams = await params;
|
|
25
|
+
const providerKey = resolvedParams.provider;
|
|
26
|
+
const container = await createRequestContainer();
|
|
27
|
+
const registration = getWebhookHandler(providerKey);
|
|
28
|
+
if (!registration) {
|
|
29
|
+
return NextResponse.json({ error: `No webhook handler for provider: ${providerKey}` }, { status: 404 });
|
|
30
|
+
}
|
|
31
|
+
const rawBody = await req.text();
|
|
32
|
+
const headers = {};
|
|
33
|
+
req.headers.forEach((value, key) => {
|
|
34
|
+
headers[key] = value;
|
|
35
|
+
});
|
|
36
|
+
const service = container.resolve("paymentGatewayService");
|
|
37
|
+
const em = container.resolve("em");
|
|
38
|
+
const integrationCredentialsService = container.resolve("integrationCredentialsService");
|
|
39
|
+
const queue = getPaymentGatewayQueue(registration.queue ?? "payment-gateways-webhook");
|
|
40
|
+
const payload = await readJsonSafe(rawBody);
|
|
41
|
+
const sessionIdHint = registration.readSessionIdHint?.(payload) ?? null;
|
|
42
|
+
try {
|
|
43
|
+
const candidates = sessionIdHint ? await findWithDecryption(
|
|
44
|
+
em,
|
|
45
|
+
GatewayTransaction,
|
|
46
|
+
{
|
|
47
|
+
providerKey,
|
|
48
|
+
providerSessionId: sessionIdHint,
|
|
49
|
+
deletedAt: null
|
|
50
|
+
},
|
|
51
|
+
{ limit: 10, orderBy: { createdAt: "desc" } }
|
|
52
|
+
) : [];
|
|
53
|
+
let transaction = null;
|
|
54
|
+
let matchedScope = null;
|
|
55
|
+
let event = null;
|
|
56
|
+
let lastVerificationError = null;
|
|
57
|
+
for (const candidate of candidates) {
|
|
58
|
+
const candidateScope = { organizationId: candidate.organizationId, tenantId: candidate.tenantId };
|
|
59
|
+
const credentials = await integrationCredentialsService.resolve(`gateway_${providerKey}`, candidateScope) ?? {};
|
|
60
|
+
try {
|
|
61
|
+
event = await registration.handler({ rawBody, headers, credentials });
|
|
62
|
+
transaction = candidate;
|
|
63
|
+
matchedScope = candidateScope;
|
|
64
|
+
break;
|
|
65
|
+
} catch (error) {
|
|
66
|
+
lastVerificationError = error;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!event) {
|
|
70
|
+
try {
|
|
71
|
+
event = await registration.handler({ rawBody, headers, credentials: {} });
|
|
72
|
+
} catch (error) {
|
|
73
|
+
throw lastVerificationError ?? error;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (!event) {
|
|
77
|
+
throw new Error("Webhook verification failed");
|
|
78
|
+
}
|
|
79
|
+
if (!transaction && sessionIdHint) {
|
|
80
|
+
const derivedScope = readScopeFromEventData(event.data);
|
|
81
|
+
if (derivedScope) {
|
|
82
|
+
transaction = await service.findTransactionBySessionId(sessionIdHint, derivedScope, providerKey);
|
|
83
|
+
matchedScope = transaction ? { organizationId: transaction.organizationId, tenantId: transaction.tenantId } : derivedScope;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const scope = transaction ? { organizationId: transaction.organizationId, tenantId: transaction.tenantId } : matchedScope ?? readScopeFromEventData(event.data);
|
|
87
|
+
const jobPayload = {
|
|
88
|
+
providerKey,
|
|
89
|
+
event,
|
|
90
|
+
transactionId: transaction?.id ?? null,
|
|
91
|
+
scope
|
|
92
|
+
};
|
|
93
|
+
if (process.env.QUEUE_STRATEGY === "async") {
|
|
94
|
+
await queue.enqueue({
|
|
95
|
+
name: "payment-gateway-webhook",
|
|
96
|
+
payload: jobPayload
|
|
97
|
+
});
|
|
98
|
+
} else {
|
|
99
|
+
await processPaymentGatewayWebhookJob(
|
|
100
|
+
{
|
|
101
|
+
em: container.resolve("em"),
|
|
102
|
+
paymentGatewayService: service,
|
|
103
|
+
integrationLogService: container.resolve("integrationLogService")
|
|
104
|
+
},
|
|
105
|
+
jobPayload
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
return NextResponse.json({ received: true, queued: true }, { status: 202 });
|
|
109
|
+
} catch (err) {
|
|
110
|
+
const message = err instanceof Error ? err.message : "Webhook verification failed";
|
|
111
|
+
return NextResponse.json({ error: message }, { status: 401 });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const openApi = {
|
|
115
|
+
tags: [paymentGatewaysTag],
|
|
116
|
+
summary: "Receive payment gateway webhook",
|
|
117
|
+
methods: {
|
|
118
|
+
POST: {
|
|
119
|
+
summary: "Process inbound webhook from payment provider",
|
|
120
|
+
tags: [paymentGatewaysTag],
|
|
121
|
+
responses: [
|
|
122
|
+
{ status: 202, description: "Webhook accepted for async processing" },
|
|
123
|
+
{ status: 401, description: "Signature verification failed" },
|
|
124
|
+
{ status: 404, description: "Unknown provider" }
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
var route_default = POST;
|
|
130
|
+
export {
|
|
131
|
+
POST,
|
|
132
|
+
route_default as default,
|
|
133
|
+
metadata,
|
|
134
|
+
openApi
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=route.js.map
|