@easypayment/medusa-payment-paypal 0.9.4 → 0.9.6
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/.medusa/server/src/admin/index.d.ts +2 -0
- package/.medusa/server/src/admin/index.d.ts.map +1 -0
- package/.medusa/server/src/admin/index.js +190 -233
- package/.medusa/server/src/admin/index.js.map +1 -0
- package/.medusa/server/src/admin/index.mjs +191 -234
- package/.medusa/server/src/admin/routes/settings/paypal/_components/FieldRow.d.ts +8 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/FieldRow.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/FieldRow.js +8 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/FieldRow.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/SectionCard.d.ts +8 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/SectionCard.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/SectionCard.js +8 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/SectionCard.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Tabs.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Tabs.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Tabs.js +25 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Tabs.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Toast.d.ts +12 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Toast.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Toast.js +22 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_components/Toast.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_utils/adminFetch.d.ts +7 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_utils/adminFetch.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_utils/adminFetch.js +40 -0
- package/.medusa/server/src/admin/routes/settings/paypal/_utils/adminFetch.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/additional-settings/page.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/additional-settings/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/additional-settings/page.js +76 -0
- package/.medusa/server/src/admin/routes/settings/paypal/additional-settings/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/advanced-card-payments/page.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/advanced-card-payments/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/advanced-card-payments/page.js +81 -0
- package/.medusa/server/src/admin/routes/settings/paypal/advanced-card-payments/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/apple-pay/page.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/apple-pay/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/apple-pay/page.js +9 -0
- package/.medusa/server/src/admin/routes/settings/paypal/apple-pay/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts +20 -0
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js +440 -0
- package/.medusa/server/src/admin/routes/settings/paypal/connection/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/google-pay/page.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/google-pay/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/google-pay/page.js +9 -0
- package/.medusa/server/src/admin/routes/settings/paypal/google-pay/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/page.d.ts +4 -0
- package/.medusa/server/src/admin/routes/settings/paypal/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/page.js +14 -0
- package/.medusa/server/src/admin/routes/settings/paypal/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/pay-later-messaging/page.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/pay-later-messaging/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/pay-later-messaging/page.js +9 -0
- package/.medusa/server/src/admin/routes/settings/paypal/pay-later-messaging/page.js.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/paypal-settings/page.d.ts +2 -0
- package/.medusa/server/src/admin/routes/settings/paypal/paypal-settings/page.d.ts.map +1 -0
- package/.medusa/server/src/admin/routes/settings/paypal/paypal-settings/page.js +109 -0
- package/.medusa/server/src/admin/routes/settings/paypal/paypal-settings/page.js.map +1 -0
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts +1 -1
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js +24 -9
- package/.medusa/server/src/api/admin/payment-collections/[id]/payment-sessions/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/disconnect/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/disconnect/route.js +10 -3
- package/.medusa/server/src/api/admin/paypal/disconnect/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/environment/route.js +2 -2
- package/.medusa/server/src/api/admin/paypal/environment/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js +3 -2
- package/.medusa/server/src/api/admin/paypal/onboard-complete/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-link/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js +4 -4
- package/.medusa/server/src/api/admin/paypal/onboarding-status/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/save-credentials/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/save-credentials/route.js +21 -8
- package/.medusa/server/src/api/admin/paypal/save-credentials/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/settings/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/settings/route.js +34 -4
- package/.medusa/server/src/api/admin/paypal/settings/route.js.map +1 -1
- package/.medusa/server/src/api/admin/paypal/status/route.d.ts.map +1 -1
- package/.medusa/server/src/api/admin/paypal/status/route.js +11 -5
- package/.medusa/server/src/api/admin/paypal/status/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/capture-order/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/capture-order/route.js +21 -3
- package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/config/route.js +2 -2
- package/.medusa/server/src/api/store/paypal/config/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/create-order/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/create-order/route.js +13 -9
- package/.medusa/server/src/api/store/paypal/create-order/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/settings/route.js +3 -3
- package/.medusa/server/src/api/store/paypal/settings/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/webhook/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/webhook/route.js +10 -3
- package/.medusa/server/src/api/store/paypal/webhook/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.js +7 -4
- package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
- package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js +3 -3
- package/.medusa/server/src/modules/paypal/clients/paypal-seller.client.js.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.d.ts +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.js +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.js.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.d.ts +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.js +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.js.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.d.ts +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.js +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.js.map +1 -1
- package/.medusa/server/src/modules/paypal/migrations/20270202000000_align_nullable_defaults.d.ts +6 -0
- package/.medusa/server/src/modules/paypal/migrations/20270202000000_align_nullable_defaults.d.ts.map +1 -0
- package/.medusa/server/src/modules/paypal/migrations/20270202000000_align_nullable_defaults.js +25 -0
- package/.medusa/server/src/modules/paypal/migrations/20270202000000_align_nullable_defaults.js.map +1 -0
- package/.medusa/server/src/modules/paypal/models/paypal_connection.d.ts +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_connection.js +3 -3
- package/.medusa/server/src/modules/paypal/models/paypal_connection.js.map +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_metric.d.ts +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_metric.js +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_metric.js.map +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.d.ts +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js +1 -1
- package/.medusa/server/src/modules/paypal/models/paypal_webhook_event.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js +95 -76
- package/.medusa/server/src/modules/paypal/payment-provider/card-service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/service.js +39 -89
- package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js +7 -0
- package/.medusa/server/src/modules/paypal/payment-provider/webhook-utils.js.map +1 -1
- package/.medusa/server/src/modules/paypal/service.d.ts +10 -8
- package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/service.js +56 -51
- package/.medusa/server/src/modules/paypal/service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/types/config.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/types/config.js +11 -2
- package/.medusa/server/src/modules/paypal/types/config.js.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/paypal-auth.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/utils/paypal-auth.js +1 -0
- package/.medusa/server/src/modules/paypal/utils/paypal-auth.js.map +1 -1
- package/.medusa/server/src/modules/paypal/webhook-processor.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/webhook-processor.js +1 -1
- package/.medusa/server/src/modules/paypal/webhook-processor.js.map +1 -1
- package/.medusa/server/src/subscribers/paypal-order-invoice.js +4 -4
- package/.medusa/server/src/subscribers/paypal-order-invoice.js.map +1 -1
- package/package.json +1 -1
- package/src/admin/index.ts +1 -7
- package/src/admin/routes/settings/paypal/_components/FieldRow.tsx +29 -0
- package/src/admin/routes/settings/paypal/_components/SectionCard.tsx +26 -0
- package/src/admin/routes/settings/paypal/_components/Toast.tsx +4 -3
- package/src/admin/routes/settings/paypal/_utils/adminFetch.ts +32 -0
- package/src/admin/routes/settings/paypal/additional-settings/page.tsx +23 -83
- package/src/admin/routes/settings/paypal/advanced-card-payments/page.tsx +17 -77
- package/src/admin/routes/settings/paypal/connection/page.tsx +88 -45
- package/src/admin/routes/settings/paypal/paypal-settings/page.tsx +23 -101
- package/src/api/admin/payment-collections/[id]/payment-sessions/route.ts +26 -9
- package/src/api/admin/paypal/disconnect/route.ts +9 -3
- package/src/api/admin/paypal/environment/route.ts +2 -2
- package/src/api/admin/paypal/onboard-complete/route.ts +4 -3
- package/src/api/admin/paypal/onboarding-link/route.ts +1 -1
- package/src/api/admin/paypal/onboarding-status/route.ts +5 -5
- package/src/api/admin/paypal/save-credentials/route.ts +24 -9
- package/src/api/admin/paypal/settings/route.ts +35 -4
- package/src/api/admin/paypal/status/route.ts +10 -5
- package/src/api/store/paypal/capture-order/route.ts +27 -3
- package/src/api/store/paypal/config/route.ts +2 -2
- package/src/api/store/paypal/create-order/route.ts +16 -10
- package/src/api/store/paypal/settings/route.ts +3 -3
- package/src/api/store/paypal/webhook/route.ts +13 -3
- package/src/api/store/paypal-complete/route.ts +8 -4
- package/src/modules/paypal/clients/paypal-seller.client.ts +3 -3
- package/src/modules/paypal/migrations/20270101090000_set_paypal_environment_default_live.ts +1 -1
- package/src/modules/paypal/migrations/20270102090000_add_paypal_seller_email.ts +1 -1
- package/src/modules/paypal/migrations/20270103090000_add_paypal_seller_merchant_id.ts +1 -1
- package/src/modules/paypal/migrations/20270202000000_align_nullable_defaults.ts +44 -0
- package/src/modules/paypal/models/paypal_connection.ts +3 -3
- package/src/modules/paypal/models/paypal_metric.ts +1 -1
- package/src/modules/paypal/models/paypal_webhook_event.ts +1 -1
- package/src/modules/paypal/payment-provider/card-service.ts +120 -80
- package/src/modules/paypal/payment-provider/service.ts +44 -93
- package/src/modules/paypal/payment-provider/webhook-utils.ts +9 -0
- package/src/modules/paypal/service.ts +79 -66
- package/src/modules/paypal/types/config.ts +18 -2
- package/src/modules/paypal/utils/paypal-auth.ts +1 -0
- package/src/modules/paypal/webhook-processor.ts +8 -5
- package/src/subscribers/paypal-order-invoice.ts +4 -4
|
@@ -1,38 +1,9 @@
|
|
|
1
|
-
import React, { useEffect, useRef, useState } from "react"
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from "react"
|
|
2
2
|
import PayPalTabs from "../_components/Tabs"
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
query?: Record<string, string>
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
async function adminFetch<T = unknown>(path: string, opts: AdminFetchOptions = {}): Promise<T> {
|
|
11
|
-
const { method = "GET", body, query } = opts
|
|
12
|
-
let url = path
|
|
13
|
-
if (query && Object.keys(query).length > 0) {
|
|
14
|
-
const params = new URLSearchParams(query)
|
|
15
|
-
url = `${path}?${params.toString()}`
|
|
16
|
-
}
|
|
17
|
-
const headers: Record<string, string> = { Accept: "application/json" }
|
|
18
|
-
if (body !== undefined) headers["Content-Type"] = "application/json"
|
|
19
|
-
if (typeof window !== "undefined") {
|
|
20
|
-
const token = (window as any).__medusa__?.token
|
|
21
|
-
if (token) headers["Authorization"] = `Bearer ${token}`
|
|
22
|
-
}
|
|
23
|
-
const res = await fetch(url, {
|
|
24
|
-
method, headers, credentials: "include",
|
|
25
|
-
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
26
|
-
})
|
|
27
|
-
const text = await res.text().catch(() => "")
|
|
28
|
-
if (!res.ok) {
|
|
29
|
-
if (res.status === 401) throw new Error("Unauthorized (401) - session may have expired. Please reload and log in again.")
|
|
30
|
-
if (res.status === 403) throw new Error("Forbidden (403) - you do not have permission to perform this action.")
|
|
31
|
-
throw new Error(text || `Request failed with status ${res.status}`)
|
|
32
|
-
}
|
|
33
|
-
if (!text) return {} as T
|
|
34
|
-
try { return JSON.parse(text) as T } catch { return {} as T }
|
|
35
|
-
}
|
|
3
|
+
import SectionCard from "../_components/SectionCard"
|
|
4
|
+
import FieldRow from "../_components/FieldRow"
|
|
5
|
+
import Toast, { ToastState } from "../_components/Toast"
|
|
6
|
+
import { adminFetch } from "../_utils/adminFetch"
|
|
36
7
|
|
|
37
8
|
type ButtonColor = "gold" | "blue" | "silver" | "black" | "white"
|
|
38
9
|
type ButtonShape = "rect" | "pill"
|
|
@@ -79,51 +50,6 @@ const LABEL_OPTIONS: { value: ButtonLabel; label: string }[] = [
|
|
|
79
50
|
{ value: "pay", label: "Pay" },
|
|
80
51
|
]
|
|
81
52
|
|
|
82
|
-
function SectionCard({
|
|
83
|
-
title,
|
|
84
|
-
description,
|
|
85
|
-
children,
|
|
86
|
-
right,
|
|
87
|
-
}: {
|
|
88
|
-
title: string
|
|
89
|
-
description?: string
|
|
90
|
-
children: React.ReactNode
|
|
91
|
-
right?: React.ReactNode
|
|
92
|
-
}) {
|
|
93
|
-
return (
|
|
94
|
-
<div className="rounded-xl border border-ui-border-base bg-ui-bg-base shadow-sm">
|
|
95
|
-
<div className="flex items-start justify-between gap-4 border-b border-ui-border-base p-4">
|
|
96
|
-
<div>
|
|
97
|
-
<div className="text-base font-semibold text-ui-fg-base">{title}</div>
|
|
98
|
-
{description ? <div className="mt-1 text-sm text-ui-fg-subtle">{description}</div> : null}
|
|
99
|
-
</div>
|
|
100
|
-
{right}
|
|
101
|
-
</div>
|
|
102
|
-
<div className="p-4">{children}</div>
|
|
103
|
-
</div>
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function FieldRow({
|
|
108
|
-
label,
|
|
109
|
-
hint,
|
|
110
|
-
children,
|
|
111
|
-
}: {
|
|
112
|
-
label: string
|
|
113
|
-
hint?: React.ReactNode
|
|
114
|
-
children: React.ReactNode
|
|
115
|
-
}) {
|
|
116
|
-
return (
|
|
117
|
-
<div className="grid grid-cols-12 items-start gap-4 py-3">
|
|
118
|
-
<div className="col-span-12 md:col-span-4">
|
|
119
|
-
<div className="text-sm font-medium text-ui-fg-base">{label}</div>
|
|
120
|
-
{hint ? <div className="mt-1 text-xs text-ui-fg-subtle">{hint}</div> : null}
|
|
121
|
-
</div>
|
|
122
|
-
<div className="col-span-12 md:col-span-8">{children}</div>
|
|
123
|
-
</div>
|
|
124
|
-
)
|
|
125
|
-
}
|
|
126
|
-
|
|
127
53
|
export default function PayPalSettingsTab() {
|
|
128
54
|
const [form, setForm] = useState<PayPalSettingsForm>({
|
|
129
55
|
enabled: true,
|
|
@@ -137,9 +63,11 @@ export default function PayPalSettingsTab() {
|
|
|
137
63
|
})
|
|
138
64
|
const [loading, setLoading] = useState(false)
|
|
139
65
|
const [saving, setSaving] = useState(false)
|
|
140
|
-
const [toast, setToast] = useState<
|
|
66
|
+
const [toast, setToast] = useState<ToastState>(null)
|
|
141
67
|
const didInit = useRef(false)
|
|
142
68
|
|
|
69
|
+
const dismissToast = useCallback(() => setToast(null), [])
|
|
70
|
+
|
|
143
71
|
useEffect(() => {
|
|
144
72
|
if (didInit.current) return
|
|
145
73
|
didInit.current = true
|
|
@@ -184,16 +112,14 @@ export default function PayPalSettingsTab() {
|
|
|
184
112
|
...saved,
|
|
185
113
|
}))
|
|
186
114
|
}
|
|
187
|
-
setToast({
|
|
188
|
-
window.setTimeout(() => setToast(null), 2500)
|
|
115
|
+
setToast({ kind: "success", message: "Settings saved" })
|
|
189
116
|
} catch (e: unknown) {
|
|
190
117
|
setToast({
|
|
191
|
-
|
|
118
|
+
kind: "error",
|
|
192
119
|
message:
|
|
193
120
|
(e instanceof Error ? e.message : "") ||
|
|
194
121
|
"Failed to save settings.",
|
|
195
122
|
})
|
|
196
|
-
window.setTimeout(() => setToast(null), 3500)
|
|
197
123
|
} finally {
|
|
198
124
|
setSaving(false)
|
|
199
125
|
}
|
|
@@ -213,17 +139,7 @@ export default function PayPalSettingsTab() {
|
|
|
213
139
|
|
|
214
140
|
<PayPalTabs />
|
|
215
141
|
|
|
216
|
-
{toast
|
|
217
|
-
<div
|
|
218
|
-
className="fixed right-6 top-6 z-50 rounded-md border border-ui-border-base bg-ui-bg-base px-4 py-3 text-sm shadow-lg"
|
|
219
|
-
role="status"
|
|
220
|
-
aria-live="polite"
|
|
221
|
-
>
|
|
222
|
-
<span className={toast.type === "success" ? "text-ui-fg-base" : "text-ui-fg-error"}>
|
|
223
|
-
{toast.message}
|
|
224
|
-
</span>
|
|
225
|
-
</div>
|
|
226
|
-
) : null}
|
|
142
|
+
<Toast toast={toast} onClose={dismissToast} />
|
|
227
143
|
|
|
228
144
|
<SectionCard
|
|
229
145
|
title="PayPal Settings"
|
|
@@ -255,8 +171,9 @@ export default function PayPalSettingsTab() {
|
|
|
255
171
|
</label>
|
|
256
172
|
</FieldRow>
|
|
257
173
|
|
|
258
|
-
<FieldRow label="Title">
|
|
174
|
+
<FieldRow label="Title" htmlFor="pp-title">
|
|
259
175
|
<input
|
|
176
|
+
id="pp-title"
|
|
260
177
|
value={form.title}
|
|
261
178
|
onChange={(e) => setForm((p) => ({ ...p, title: e.target.value }))}
|
|
262
179
|
className="w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive"
|
|
@@ -273,8 +190,9 @@ export default function PayPalSettingsTab() {
|
|
|
273
190
|
>
|
|
274
191
|
<div className="divide-y divide-ui-border-base">
|
|
275
192
|
|
|
276
|
-
<FieldRow label="Button Color">
|
|
193
|
+
<FieldRow label="Button Color" htmlFor="pp-btn-color">
|
|
277
194
|
<select
|
|
195
|
+
id="pp-btn-color"
|
|
278
196
|
value={form.buttonColor}
|
|
279
197
|
onChange={(e) => setForm((p) => ({ ...p, buttonColor: e.target.value as ButtonColor }))}
|
|
280
198
|
className="w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive"
|
|
@@ -287,8 +205,9 @@ export default function PayPalSettingsTab() {
|
|
|
287
205
|
</select>
|
|
288
206
|
</FieldRow>
|
|
289
207
|
|
|
290
|
-
<FieldRow label="Button Shape">
|
|
208
|
+
<FieldRow label="Button Shape" htmlFor="pp-btn-shape">
|
|
291
209
|
<select
|
|
210
|
+
id="pp-btn-shape"
|
|
292
211
|
value={form.buttonShape}
|
|
293
212
|
onChange={(e) => setForm((p) => ({ ...p, buttonShape: e.target.value as ButtonShape }))}
|
|
294
213
|
className="w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive"
|
|
@@ -301,8 +220,9 @@ export default function PayPalSettingsTab() {
|
|
|
301
220
|
</select>
|
|
302
221
|
</FieldRow>
|
|
303
222
|
|
|
304
|
-
<FieldRow label="Button Width">
|
|
223
|
+
<FieldRow label="Button Width" htmlFor="pp-btn-width">
|
|
305
224
|
<select
|
|
225
|
+
id="pp-btn-width"
|
|
306
226
|
value={form.buttonWidth}
|
|
307
227
|
onChange={(e) => setForm((p) => ({ ...p, buttonWidth: e.target.value as ButtonWidth }))}
|
|
308
228
|
className="w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive"
|
|
@@ -315,8 +235,9 @@ export default function PayPalSettingsTab() {
|
|
|
315
235
|
</select>
|
|
316
236
|
</FieldRow>
|
|
317
237
|
|
|
318
|
-
<FieldRow label="Button Height">
|
|
238
|
+
<FieldRow label="Button Height" htmlFor="pp-btn-height">
|
|
319
239
|
<select
|
|
240
|
+
id="pp-btn-height"
|
|
320
241
|
value={String(form.buttonHeight)}
|
|
321
242
|
onChange={(e) => setForm((p) => ({ ...p, buttonHeight: Number(e.target.value) }))}
|
|
322
243
|
className="w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive"
|
|
@@ -329,8 +250,9 @@ export default function PayPalSettingsTab() {
|
|
|
329
250
|
</select>
|
|
330
251
|
</FieldRow>
|
|
331
252
|
|
|
332
|
-
<FieldRow label="Button Label">
|
|
253
|
+
<FieldRow label="Button Label" htmlFor="pp-btn-label">
|
|
333
254
|
<select
|
|
255
|
+
id="pp-btn-label"
|
|
334
256
|
value={form.buttonLabel}
|
|
335
257
|
onChange={(e) => setForm((p) => ({ ...p, buttonLabel: e.target.value as ButtonLabel }))}
|
|
336
258
|
className="w-full rounded-md border border-ui-border-base bg-ui-bg-base px-3 py-2 text-sm text-ui-fg-base outline-none focus:ring-2 focus:ring-ui-border-interactive"
|
|
@@ -7,18 +7,35 @@ type CreatePaymentSessionBody = {
|
|
|
7
7
|
customer_id?: string
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
const ALLOWED_PROVIDERS = new Set([
|
|
11
|
+
"pp_paypal_paypal",
|
|
12
|
+
"pp_paypal_card_paypal_card",
|
|
13
|
+
])
|
|
14
|
+
|
|
10
15
|
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
11
16
|
const collectionId = req.params.id
|
|
12
17
|
const { provider_id, data, customer_id } = req.body as CreatePaymentSessionBody
|
|
13
18
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
if (!provider_id || !ALLOWED_PROVIDERS.has(provider_id)) {
|
|
20
|
+
return res.status(400).json({ message: "Invalid or unsupported provider_id" })
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (!collectionId || typeof collectionId !== "string") {
|
|
24
|
+
return res.status(400).json({ message: "Invalid collection id" })
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const { result } = await createPaymentSessionsWorkflow(req.scope).run({
|
|
29
|
+
input: {
|
|
30
|
+
payment_collection_id: collectionId,
|
|
31
|
+
provider_id,
|
|
32
|
+
customer_id,
|
|
33
|
+
data,
|
|
34
|
+
},
|
|
35
|
+
})
|
|
22
36
|
|
|
23
|
-
|
|
37
|
+
res.status(200).json({ payment_session: result })
|
|
38
|
+
} catch {
|
|
39
|
+
res.status(500).json({ message: "Failed to create payment session" })
|
|
40
|
+
}
|
|
24
41
|
}
|
|
@@ -2,7 +2,13 @@ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
|
2
2
|
import type PayPalModuleService from "../../../../modules/paypal/service"
|
|
3
3
|
|
|
4
4
|
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
try {
|
|
6
|
+
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
7
|
+
await paypal.disconnect()
|
|
8
|
+
return res.json({ ok: true })
|
|
9
|
+
} catch (e: unknown) {
|
|
10
|
+
const message = e instanceof Error ? e.message : String(e)
|
|
11
|
+
console.error("[PayPal] disconnect failed:", message)
|
|
12
|
+
return res.status(500).json({ message: "Failed to disconnect PayPal" })
|
|
13
|
+
}
|
|
8
14
|
}
|
|
@@ -19,7 +19,7 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
19
19
|
await paypal.setEnvironment(env)
|
|
20
20
|
const status = await paypal.getStatus()
|
|
21
21
|
return res.json(status)
|
|
22
|
-
} catch
|
|
23
|
-
return res.status(500).json({ message:
|
|
22
|
+
} catch {
|
|
23
|
+
return res.status(500).json({ message: "Failed to update environment" })
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -25,10 +25,11 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
return res.json({ ok: true })
|
|
28
|
-
} catch (e:
|
|
29
|
-
|
|
28
|
+
} catch (e: unknown) {
|
|
29
|
+
const message = e instanceof Error ? e.message : String(e)
|
|
30
|
+
console.error("[PayPal] onboard-complete failed:", message)
|
|
30
31
|
return res.status(500).json({
|
|
31
|
-
message:
|
|
32
|
+
message: "Failed to exchange and save PayPal credentials",
|
|
32
33
|
})
|
|
33
34
|
}
|
|
34
35
|
}
|
|
@@ -33,7 +33,7 @@ export async function POST(req: AuthenticatedMedusaRequest, res: MedusaResponse)
|
|
|
33
33
|
} catch (e: any) {
|
|
34
34
|
console.error("[paypal_onboarding] onboarding-link error:", e?.message || e, e?.stack)
|
|
35
35
|
return res.status(500).json({
|
|
36
|
-
message:
|
|
36
|
+
message: "Failed to generate PayPal onboarding link",
|
|
37
37
|
})
|
|
38
38
|
}
|
|
39
39
|
}
|
|
@@ -6,12 +6,12 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
|
6
6
|
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
7
7
|
const status = await paypal.getStatus()
|
|
8
8
|
return res.json(status)
|
|
9
|
-
} catch (e:
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
} catch (e: unknown) {
|
|
10
|
+
const message = e instanceof Error ? e.message : String(e)
|
|
11
|
+
console.error("[paypal_onboarding] onboarding-status error:", message)
|
|
12
|
+
return res.status(500).json({
|
|
13
13
|
status: "disconnected",
|
|
14
|
-
|
|
14
|
+
message: "Failed to retrieve PayPal status",
|
|
15
15
|
})
|
|
16
16
|
}
|
|
17
17
|
}
|
|
@@ -6,17 +6,32 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
6
6
|
const body = req.body as {
|
|
7
7
|
clientId?: string
|
|
8
8
|
clientSecret?: string
|
|
9
|
-
environment?:
|
|
9
|
+
environment?: string
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
if (!body?.clientId ||
|
|
13
|
-
return res.status(400).json({ message: "
|
|
12
|
+
if (!body?.clientId || typeof body.clientId !== "string" || body.clientId.length > 200) {
|
|
13
|
+
return res.status(400).json({ message: "Invalid or missing clientId" })
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
if (!body?.clientSecret || typeof body.clientSecret !== "string" || body.clientSecret.length > 200) {
|
|
17
|
+
return res.status(400).json({ message: "Invalid or missing clientSecret" })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const environment =
|
|
21
|
+
body.environment === "sandbox" || body.environment === "live"
|
|
22
|
+
? body.environment
|
|
23
|
+
: undefined
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
await paypal.saveAndHydrateSellerCredentials({
|
|
27
|
+
clientId: body.clientId.trim(),
|
|
28
|
+
clientSecret: body.clientSecret.trim(),
|
|
29
|
+
environment,
|
|
30
|
+
})
|
|
31
|
+
return res.json({ ok: true })
|
|
32
|
+
} catch (e: unknown) {
|
|
33
|
+
const message = e instanceof Error ? e.message : String(e)
|
|
34
|
+
console.error("[PayPal] save-credentials failed:", message)
|
|
35
|
+
return res.status(500).json({ message: "Failed to save PayPal credentials" })
|
|
36
|
+
}
|
|
22
37
|
}
|
|
@@ -2,13 +2,44 @@ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
|
2
2
|
import type PayPalModuleService from "../../../../modules/paypal/service"
|
|
3
3
|
|
|
4
4
|
export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
try {
|
|
6
|
+
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
7
|
+
return res.json(await paypal.getSettings())
|
|
8
|
+
} catch (e: unknown) {
|
|
9
|
+
console.error("[PayPal] settings GET failed:", e instanceof Error ? e.message : e)
|
|
10
|
+
return res.status(500).json({ message: "Failed to load PayPal settings" })
|
|
11
|
+
}
|
|
7
12
|
}
|
|
8
13
|
|
|
14
|
+
const ALLOWED_SETTINGS_KEYS = new Set([
|
|
15
|
+
"additional_settings",
|
|
16
|
+
"paypal_settings",
|
|
17
|
+
"advanced_card_payments",
|
|
18
|
+
"pay_later_messaging",
|
|
19
|
+
"apple_pay",
|
|
20
|
+
"google_pay",
|
|
21
|
+
"api_details",
|
|
22
|
+
])
|
|
23
|
+
|
|
9
24
|
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
10
25
|
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
11
26
|
|
|
12
|
-
const
|
|
13
|
-
|
|
27
|
+
const raw = (req.body && typeof req.body === "object") ? (req.body as Record<string, unknown>) : {}
|
|
28
|
+
const patch: Record<string, unknown> = {}
|
|
29
|
+
for (const key of Object.keys(raw)) {
|
|
30
|
+
if (ALLOWED_SETTINGS_KEYS.has(key)) {
|
|
31
|
+
patch[key] = raw[key]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (Object.keys(patch).length === 0) {
|
|
36
|
+
return res.status(400).json({ message: "No valid settings fields provided" })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
return res.json(await paypal.saveSettings(patch as Record<string, Record<string, unknown>>))
|
|
41
|
+
} catch (e: unknown) {
|
|
42
|
+
console.error("[PayPal] settings POST failed:", e instanceof Error ? e.message : e)
|
|
43
|
+
return res.status(500).json({ message: "Failed to save PayPal settings" })
|
|
44
|
+
}
|
|
14
45
|
}
|
|
@@ -2,11 +2,16 @@ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
|
2
2
|
import type PayPalModuleService from "../../../../modules/paypal/service"
|
|
3
3
|
|
|
4
4
|
export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
5
|
-
|
|
5
|
+
try {
|
|
6
|
+
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const q = (req.query || {}) as Record<string, any>
|
|
9
|
+
const envParam = (q.environment || q.env) as string | undefined
|
|
10
|
+
const env = envParam === "live" ? "live" : envParam === "sandbox" ? "sandbox" : undefined
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
return res.json(await paypal.getStatus(env))
|
|
13
|
+
} catch (e: unknown) {
|
|
14
|
+
console.error("[PayPal] status GET failed:", e instanceof Error ? e.message : e)
|
|
15
|
+
return res.status(500).json({ message: "Failed to retrieve PayPal status" })
|
|
16
|
+
}
|
|
12
17
|
}
|
|
@@ -8,6 +8,8 @@ import { isPayPalProviderId } from "../../../../modules/paypal/utils/provider-id
|
|
|
8
8
|
|
|
9
9
|
const BN_CODE = "MBJTechnolabs_SI_SPB"
|
|
10
10
|
|
|
11
|
+
const PAYPAL_ORDER_ID_RE = /^[A-Z0-9]{10,25}$/
|
|
12
|
+
|
|
11
13
|
type Body = {
|
|
12
14
|
cart_id: string
|
|
13
15
|
order_id: string
|
|
@@ -188,6 +190,27 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
188
190
|
return res.status(400).json({ message: "cart_id and order_id are required" })
|
|
189
191
|
}
|
|
190
192
|
|
|
193
|
+
if (typeof cartId !== "string" || !cartId.startsWith("cart_")) {
|
|
194
|
+
return res.status(400).json({ message: "Invalid cart_id format" })
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (!PAYPAL_ORDER_ID_RE.test(orderId)) {
|
|
198
|
+
return res.status(400).json({ message: "Invalid order_id format" })
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const session = await findPayPalSessionForCart(cartId, scope)
|
|
202
|
+
if (session) {
|
|
203
|
+
const sessionOrderId = String(
|
|
204
|
+
(session.session_data?.paypal as Record<string, unknown>)?.order_id ||
|
|
205
|
+
session.session_data?.order_id || ""
|
|
206
|
+
)
|
|
207
|
+
if (sessionOrderId && sessionOrderId !== orderId) {
|
|
208
|
+
return res.status(400).json({
|
|
209
|
+
message: "order_id does not match the payment session for this cart",
|
|
210
|
+
})
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
191
214
|
const existingCapture = await getExistingCapture(cartId, orderId, scope)
|
|
192
215
|
if (existingCapture) {
|
|
193
216
|
return res.json({ capture: existingCapture })
|
|
@@ -207,10 +230,11 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
207
230
|
: "capture"
|
|
208
231
|
|
|
209
232
|
const requestId = resolveIdempotencyKey(req, "capture-order", `pp-capture-${orderId}`)
|
|
233
|
+
const safeOrderId = encodeURIComponent(orderId)
|
|
210
234
|
const endpoint =
|
|
211
235
|
paymentAction === "authorize"
|
|
212
|
-
? `${base}/v2/checkout/orders/${
|
|
213
|
-
: `${base}/v2/checkout/orders/${
|
|
236
|
+
? `${base}/v2/checkout/orders/${safeOrderId}/authorize`
|
|
237
|
+
: `${base}/v2/checkout/orders/${safeOrderId}/capture`
|
|
214
238
|
|
|
215
239
|
const ppResp = await fetch(endpoint, {
|
|
216
240
|
method: "POST",
|
|
@@ -260,6 +284,6 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
260
284
|
await paypal.recordMetric("capture_order_failed")
|
|
261
285
|
} catch {
|
|
262
286
|
}
|
|
263
|
-
return res.status(500).json({ message:
|
|
287
|
+
return res.status(500).json({ message: "Failed to capture PayPal order" })
|
|
264
288
|
}
|
|
265
289
|
}
|
|
@@ -94,7 +94,7 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
|
94
94
|
button_height: paypalSettings.buttonHeight ?? 45,
|
|
95
95
|
button_label: paypalSettings.buttonLabel || "paypal",
|
|
96
96
|
})
|
|
97
|
-
} catch
|
|
98
|
-
return res.status(500).json({ message:
|
|
97
|
+
} catch {
|
|
98
|
+
return res.status(500).json({ message: "Failed to load PayPal config" })
|
|
99
99
|
}
|
|
100
100
|
}
|
|
@@ -111,10 +111,14 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
111
111
|
const cartId = body.cart_id
|
|
112
112
|
const isCardPayment = !!(body as any).is_card_payment
|
|
113
113
|
|
|
114
|
-
if (!cartId) {
|
|
114
|
+
if (!cartId || typeof cartId !== "string") {
|
|
115
115
|
return res.status(400).json({ message: "cart_id is required" })
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
if (!cartId.startsWith("cart_")) {
|
|
119
|
+
return res.status(400).json({ message: "Invalid cart_id format" })
|
|
120
|
+
}
|
|
121
|
+
|
|
118
122
|
const existingOrderId = await getExistingPayPalOrderId(req, cartId)
|
|
119
123
|
if (existingOrderId) {
|
|
120
124
|
return res.json({ id: existingOrderId })
|
|
@@ -290,11 +294,13 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
290
294
|
)
|
|
291
295
|
const roundedItemSumFixed = parseFloat(roundedItemSum.toFixed(exponent))
|
|
292
296
|
|
|
293
|
-
const
|
|
297
|
+
const finalPurchaseItems = purchaseItemsRaw.map((item: any) => item.paypalItem)
|
|
294
298
|
|
|
295
|
-
const
|
|
299
|
+
const adjustedItemTotal = sendItemDetails && finalPurchaseItems.length > 0
|
|
300
|
+
? roundedItemSumFixed
|
|
301
|
+
: subtotalMajor
|
|
296
302
|
|
|
297
|
-
const
|
|
303
|
+
const diff = parseFloat((subtotalMajor - roundedItemSumFixed).toFixed(exponent))
|
|
298
304
|
|
|
299
305
|
if (Math.abs(diff) > 0.000001 && sendItemDetails && finalPurchaseItems.length > 0) {
|
|
300
306
|
finalPurchaseItems.push({
|
|
@@ -438,12 +444,12 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
438
444
|
await paypal.recordMetric("create_order_failed")
|
|
439
445
|
} catch {
|
|
440
446
|
}
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
+
const rawMessage = e?.message || ""
|
|
448
|
+
const isCurrencyError =
|
|
449
|
+
rawMessage.includes("PayPal does not support currency") ||
|
|
450
|
+
rawMessage.includes("PayPal is configured for")
|
|
451
|
+
const status = isCurrencyError ? 400 : 500
|
|
452
|
+
const message = isCurrencyError ? rawMessage : "Failed to create PayPal order"
|
|
447
453
|
return res.status(status).json({ message })
|
|
448
454
|
}
|
|
449
455
|
}
|
|
@@ -11,9 +11,9 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
|
11
11
|
|
|
12
12
|
return res.json({
|
|
13
13
|
paymentAction: additionalSettings.paymentAction === "authorize" ? "authorize" : "capture",
|
|
14
|
-
advancedCardEnabled: advancedCard.enabled
|
|
14
|
+
advancedCardEnabled: advancedCard.enabled !== false,
|
|
15
15
|
})
|
|
16
|
-
} catch
|
|
17
|
-
return res.status(500).json({ message:
|
|
16
|
+
} catch {
|
|
17
|
+
return res.status(500).json({ message: "Failed to load PayPal settings" })
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -140,6 +140,16 @@ async function verifyWebhookSignature(
|
|
|
140
140
|
webhook_event: body,
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
const certUrl = verifyPayload.cert_url
|
|
144
|
+
if (
|
|
145
|
+
certUrl &&
|
|
146
|
+
!certUrl.startsWith("https://www.paypal.com/") &&
|
|
147
|
+
!certUrl.startsWith("https://api-m.paypal.com/") &&
|
|
148
|
+
!certUrl.startsWith("https://api-m.sandbox.paypal.com/")
|
|
149
|
+
) {
|
|
150
|
+
throw new Error("Invalid paypal-cert-url: must originate from paypal.com")
|
|
151
|
+
}
|
|
152
|
+
|
|
143
153
|
const missing = Object.entries(verifyPayload)
|
|
144
154
|
.filter(([k, v]) => k !== "webhook_id" && k !== "webhook_event" && !v)
|
|
145
155
|
.map(([k]) => k)
|
|
@@ -208,7 +218,7 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
208
218
|
console.error("[PayPal] webhook: signature verification failed:", e?.message)
|
|
209
219
|
return res
|
|
210
220
|
.status(401)
|
|
211
|
-
.json({ message:
|
|
221
|
+
.json({ message: "Webhook signature verification failed" })
|
|
212
222
|
}
|
|
213
223
|
|
|
214
224
|
const eventVersion = normalizeEventVersion(payload)
|
|
@@ -316,10 +326,10 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
316
326
|
await paypal.recordMetric("webhook_failed").catch(() => {})
|
|
317
327
|
|
|
318
328
|
if (!retryable) {
|
|
319
|
-
return res.status(200).json({ ok: false, message:
|
|
329
|
+
return res.status(200).json({ ok: false, message: "Webhook processing failed" })
|
|
320
330
|
}
|
|
321
331
|
return res
|
|
322
332
|
.status(500)
|
|
323
|
-
.json({ message:
|
|
333
|
+
.json({ message: "PayPal webhook processing error" })
|
|
324
334
|
}
|
|
325
335
|
}
|
|
@@ -6,8 +6,12 @@ import type PayPalModuleService from "../../../modules/paypal/service"
|
|
|
6
6
|
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
7
7
|
const { cart_id } = req.body as { cart_id: string }
|
|
8
8
|
|
|
9
|
-
if (!cart_id) {
|
|
10
|
-
return res.status(400).json({
|
|
9
|
+
if (!cart_id || typeof cart_id !== "string") {
|
|
10
|
+
return res.status(400).json({ message: "cart_id is required" })
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (!cart_id.startsWith("cart_")) {
|
|
14
|
+
return res.status(400).json({ message: "Invalid cart_id format" })
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
try {
|
|
@@ -36,7 +40,7 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
36
40
|
)[0]
|
|
37
41
|
|
|
38
42
|
if (!session) {
|
|
39
|
-
return res.status(400).json({
|
|
43
|
+
return res.status(400).json({ message: "No PayPal payment session found for cart" })
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
const currentStatus = String(session.status || "")
|
|
@@ -90,6 +94,6 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
|
90
94
|
return res.json({ success: true, session_id: session.id })
|
|
91
95
|
} catch (e: any) {
|
|
92
96
|
console.error("[paypal-complete] error:", e?.message || e)
|
|
93
|
-
return res.status(500).json({
|
|
97
|
+
return res.status(500).json({ message: "Internal error" })
|
|
94
98
|
}
|
|
95
99
|
}
|