@easypayment/medusa-paypal 0.2.5 → 0.2.7
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.js +1194 -1194
- package/.medusa/server/src/admin/index.mjs +1194 -1194
- package/.medusa/server/src/api/middlewares.d.ts +3 -0
- package/.medusa/server/src/api/middlewares.d.ts.map +1 -0
- package/.medusa/server/src/api/middlewares.js +16 -0
- package/.medusa/server/src/api/middlewares.js.map +1 -0
- 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 +79 -65
- package/.medusa/server/src/api/store/paypal/capture-order/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal/config/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal/config/route.js +9 -2
- package/.medusa/server/src/api/store/paypal/config/route.js.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.d.ts +3 -0
- package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -0
- package/.medusa/server/src/api/store/paypal-complete/route.js +42 -0
- package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -0
- 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 +54 -4
- 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 +4 -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 +63 -5
- package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
- package/package.json +1 -1
- package/src/api/middlewares.ts +14 -0
- package/src/api/store/paypal/capture-order/route.ts +284 -270
- package/src/api/store/paypal/config/route.ts +12 -8
- package/src/api/store/paypal-complete/route.ts +46 -0
- package/src/modules/paypal/payment-provider/card-service.ts +54 -4
- package/src/modules/paypal/payment-provider/service.ts +77 -17
|
@@ -1,270 +1,284 @@
|
|
|
1
|
-
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
2
|
-
import { randomUUID } from "crypto"
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
req.headers["
|
|
47
|
-
req.headers["
|
|
48
|
-
req.headers["
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}`
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
270
|
-
|
|
1
|
+
import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
|
2
|
+
import { randomUUID } from "crypto"
|
|
3
|
+
import { Pool } from "pg"
|
|
4
|
+
import type PayPalModuleService from "../../../../modules/paypal/service"
|
|
5
|
+
import { isPayPalProviderId } from "../../../../modules/paypal/utils/provider-ids"
|
|
6
|
+
|
|
7
|
+
type Body = {
|
|
8
|
+
cart_id: string
|
|
9
|
+
order_id: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function getPayPalApiBase(environment: string) {
|
|
13
|
+
return environment === "live"
|
|
14
|
+
? "https://api-m.paypal.com"
|
|
15
|
+
: "https://api-m.sandbox.paypal.com"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function getPayPalAccessToken(opts: {
|
|
19
|
+
environment: string
|
|
20
|
+
client_id: string
|
|
21
|
+
client_secret: string
|
|
22
|
+
}) {
|
|
23
|
+
const base = await getPayPalApiBase(opts.environment)
|
|
24
|
+
const auth = Buffer.from(`${opts.client_id}:${opts.client_secret}`).toString("base64")
|
|
25
|
+
|
|
26
|
+
const resp = await fetch(`${base}/v1/oauth2/token`, {
|
|
27
|
+
method: "POST",
|
|
28
|
+
headers: {
|
|
29
|
+
Authorization: `Basic ${auth}`,
|
|
30
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
31
|
+
},
|
|
32
|
+
body: "grant_type=client_credentials",
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const text = await resp.text()
|
|
36
|
+
if (!resp.ok) {
|
|
37
|
+
throw new Error(`PayPal token error (${resp.status}): ${text}`)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const json = JSON.parse(text)
|
|
41
|
+
return { accessToken: String(json.access_token), base }
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveIdempotencyKey(req: MedusaRequest, suffix: string, fallback: string) {
|
|
45
|
+
const header =
|
|
46
|
+
req.headers["idempotency-key"] ||
|
|
47
|
+
req.headers["Idempotency-Key"] ||
|
|
48
|
+
req.headers["x-idempotency-key"] ||
|
|
49
|
+
req.headers["X-Idempotency-Key"]
|
|
50
|
+
const key = Array.isArray(header) ? header[0] : header
|
|
51
|
+
if (key && String(key).trim()) {
|
|
52
|
+
return `${String(key).trim()}-${suffix}`
|
|
53
|
+
}
|
|
54
|
+
return fallback || `pp-${suffix}-${randomUUID()}`
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Find the PayPal payment session for a cart using direct DB query.
|
|
59
|
+
* Replaces the broken paymentCollectionService.retrieveByCartId() call.
|
|
60
|
+
*/
|
|
61
|
+
async function findPayPalSessionForCart(cartId: string): Promise<{
|
|
62
|
+
session_id: string
|
|
63
|
+
session_data: Record<string, any>
|
|
64
|
+
session_status: string
|
|
65
|
+
} | null> {
|
|
66
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
|
|
67
|
+
try {
|
|
68
|
+
const { rows } = await pool.query(
|
|
69
|
+
`SELECT ps.id as session_id, ps.data as session_data, ps.status as session_status
|
|
70
|
+
FROM payment_session ps
|
|
71
|
+
JOIN payment_collection pc ON ps.payment_collection_id = pc.id
|
|
72
|
+
JOIN cart_payment_collection cpc ON cpc.payment_collection_id = pc.id
|
|
73
|
+
WHERE cpc.cart_id = $1
|
|
74
|
+
AND ps.provider_id LIKE '%paypal%'
|
|
75
|
+
ORDER BY ps.created_at DESC
|
|
76
|
+
LIMIT 1`,
|
|
77
|
+
[cartId]
|
|
78
|
+
)
|
|
79
|
+
return rows[0] ?? null
|
|
80
|
+
} catch {
|
|
81
|
+
return null
|
|
82
|
+
} finally {
|
|
83
|
+
await pool.end()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Update the PayPal payment session status and data directly via DB.
|
|
89
|
+
*/
|
|
90
|
+
async function updatePayPalSession(
|
|
91
|
+
sessionId: string,
|
|
92
|
+
status: string,
|
|
93
|
+
extraData: Record<string, any>
|
|
94
|
+
): Promise<void> {
|
|
95
|
+
const pool = new Pool({ connectionString: process.env.DATABASE_URL })
|
|
96
|
+
try {
|
|
97
|
+
await pool.query(
|
|
98
|
+
`UPDATE payment_session
|
|
99
|
+
SET status = $1,
|
|
100
|
+
data = data || $2::jsonb
|
|
101
|
+
WHERE id = $3`,
|
|
102
|
+
[status, JSON.stringify(extraData), sessionId]
|
|
103
|
+
)
|
|
104
|
+
} catch {
|
|
105
|
+
// ignore
|
|
106
|
+
} finally {
|
|
107
|
+
await pool.end()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function attachPayPalCaptureToSession(
|
|
112
|
+
cartId: string,
|
|
113
|
+
orderId: string,
|
|
114
|
+
capture: any
|
|
115
|
+
) {
|
|
116
|
+
try {
|
|
117
|
+
const session = await findPayPalSessionForCart(cartId)
|
|
118
|
+
if (!session) {
|
|
119
|
+
console.warn("[PayPal] attachPayPalCaptureToSession: no session found for cart", cartId)
|
|
120
|
+
return
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const captureId =
|
|
124
|
+
capture?.purchase_units?.[0]?.payments?.captures?.[0]?.id ||
|
|
125
|
+
capture?.id
|
|
126
|
+
|
|
127
|
+
await updatePayPalSession(session.session_id, "authorized", {
|
|
128
|
+
paypal: {
|
|
129
|
+
...((session.session_data || {}).paypal || {}),
|
|
130
|
+
order_id: orderId,
|
|
131
|
+
capture_id: captureId,
|
|
132
|
+
capture,
|
|
133
|
+
},
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
console.info("[PayPal] session authorized via DB:", session.session_id)
|
|
137
|
+
} catch {
|
|
138
|
+
// ignore
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
async function attachPayPalAuthorizationToSession(
|
|
143
|
+
cartId: string,
|
|
144
|
+
orderId: string,
|
|
145
|
+
authorization: any
|
|
146
|
+
) {
|
|
147
|
+
try {
|
|
148
|
+
const session = await findPayPalSessionForCart(cartId)
|
|
149
|
+
if (!session) {
|
|
150
|
+
console.warn("[PayPal] attachPayPalAuthorizationToSession: no session found for cart", cartId)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const authorizationId =
|
|
155
|
+
authorization?.purchase_units?.[0]?.payments?.authorizations?.[0]?.id
|
|
156
|
+
|
|
157
|
+
await updatePayPalSession(session.session_id, "authorized", {
|
|
158
|
+
paypal: {
|
|
159
|
+
...((session.session_data || {}).paypal || {}),
|
|
160
|
+
order_id: orderId,
|
|
161
|
+
authorization_id: authorizationId,
|
|
162
|
+
authorization,
|
|
163
|
+
},
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
console.info("[PayPal] session authorized via DB:", session.session_id)
|
|
167
|
+
} catch {
|
|
168
|
+
// ignore
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function getExistingCapture(cartId: string, orderId: string) {
|
|
173
|
+
try {
|
|
174
|
+
const session = await findPayPalSessionForCart(cartId)
|
|
175
|
+
if (!session) return null
|
|
176
|
+
|
|
177
|
+
const paypalData = (session.session_data || {}).paypal || {}
|
|
178
|
+
const existingOrderId = String(paypalData.order_id || "")
|
|
179
|
+
if (existingOrderId && existingOrderId !== orderId) return null
|
|
180
|
+
if (paypalData.capture) return paypalData.capture
|
|
181
|
+
if (paypalData.capture_id) return { id: paypalData.capture_id }
|
|
182
|
+
return null
|
|
183
|
+
} catch {
|
|
184
|
+
return null
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function POST(req: MedusaRequest, res: MedusaResponse) {
|
|
189
|
+
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
190
|
+
let debugId: string | null = null
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
const body = (req.body || {}) as Body
|
|
194
|
+
const cartId = body.cart_id
|
|
195
|
+
const orderId = body.order_id
|
|
196
|
+
|
|
197
|
+
if (!cartId || !orderId) {
|
|
198
|
+
return res.status(400).json({ message: "cart_id and order_id are required" })
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const existingCapture = await getExistingCapture(cartId, orderId)
|
|
202
|
+
if (existingCapture) {
|
|
203
|
+
return res.json({ capture: existingCapture })
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const creds = await paypal.getActiveCredentials()
|
|
207
|
+
const { accessToken, base } = await getPayPalAccessToken(creds)
|
|
208
|
+
const settings = await paypal.getSettings().catch(() => ({}))
|
|
209
|
+
const data =
|
|
210
|
+
settings && typeof settings === "object" && "data" in settings
|
|
211
|
+
? ((settings as { data?: Record<string, any> }).data ?? {})
|
|
212
|
+
: {}
|
|
213
|
+
const additionalSettings = (data.additional_settings || {}) as Record<string, any>
|
|
214
|
+
const paymentAction =
|
|
215
|
+
typeof additionalSettings.paymentAction === "string"
|
|
216
|
+
? additionalSettings.paymentAction
|
|
217
|
+
: "capture"
|
|
218
|
+
|
|
219
|
+
const requestId = resolveIdempotencyKey(req, "capture-order", `pp-capture-${orderId}`)
|
|
220
|
+
const endpoint =
|
|
221
|
+
paymentAction === "authorize"
|
|
222
|
+
? `${base}/v2/checkout/orders/${orderId}/authorize`
|
|
223
|
+
: `${base}/v2/checkout/orders/${orderId}/capture`
|
|
224
|
+
|
|
225
|
+
const ppResp = await fetch(endpoint, {
|
|
226
|
+
method: "POST",
|
|
227
|
+
headers: {
|
|
228
|
+
Authorization: `Bearer ${accessToken}`,
|
|
229
|
+
"Content-Type": "application/json",
|
|
230
|
+
"PayPal-Request-Id": requestId,
|
|
231
|
+
},
|
|
232
|
+
})
|
|
233
|
+
|
|
234
|
+
const ppText = await ppResp.text()
|
|
235
|
+
debugId = ppResp.headers.get("paypal-debug-id")
|
|
236
|
+
if (!ppResp.ok) {
|
|
237
|
+
throw new Error(
|
|
238
|
+
`PayPal capture error (${ppResp.status}): ${ppText}${debugId ? ` debug_id=${debugId}` : ""}`
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const payload = JSON.parse(ppText)
|
|
243
|
+
console.info("[PayPal] capture-order raw payload:", JSON.stringify(payload, null, 2))
|
|
244
|
+
if (paymentAction === "authorize") {
|
|
245
|
+
await attachPayPalAuthorizationToSession(cartId, orderId, payload)
|
|
246
|
+
} else {
|
|
247
|
+
await attachPayPalCaptureToSession(cartId, orderId, payload)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
console.info("[PayPal] capture-order", {
|
|
251
|
+
cart_id: cartId,
|
|
252
|
+
order_id: orderId,
|
|
253
|
+
request_id: requestId,
|
|
254
|
+
debug_id: ppResp.headers.get("paypal-debug-id"),
|
|
255
|
+
capture_id: payload?.id,
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
try {
|
|
259
|
+
await paypal.recordMetric(
|
|
260
|
+
paymentAction === "authorize" ? "authorize_order_success" : "capture_order_success"
|
|
261
|
+
)
|
|
262
|
+
} catch {
|
|
263
|
+
// ignore metrics failures
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return paymentAction === "authorize"
|
|
267
|
+
? res.json({ authorization: payload })
|
|
268
|
+
: res.json({ capture: payload })
|
|
269
|
+
} catch (e: any) {
|
|
270
|
+
try {
|
|
271
|
+
const body = (req.body || {}) as Body
|
|
272
|
+
await paypal.recordAuditEvent("capture_order_failed", {
|
|
273
|
+
cart_id: body.cart_id,
|
|
274
|
+
order_id: body.order_id,
|
|
275
|
+
debug_id: debugId,
|
|
276
|
+
message: e?.message || String(e),
|
|
277
|
+
})
|
|
278
|
+
await paypal.recordMetric("capture_order_failed")
|
|
279
|
+
} catch {
|
|
280
|
+
// ignore audit logging failures
|
|
281
|
+
}
|
|
282
|
+
return res.status(500).json({ message: e?.message || "Failed to capture PayPal order" })
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -8,18 +8,12 @@ import {
|
|
|
8
8
|
|
|
9
9
|
export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
10
10
|
const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
|
|
11
|
-
|
|
12
11
|
try {
|
|
13
12
|
const creds = await paypal.getActiveCredentials()
|
|
14
13
|
const apiDetails = await paypal.getApiDetails().catch(() => null)
|
|
15
|
-
|
|
16
|
-
// CardFields/PaymentFields require a client token on the script tag.
|
|
17
|
-
// Generate it server-side and return it with config.
|
|
18
14
|
const client_token = await paypal.generateClientToken({ locale: "en_US" }).catch(() => "")
|
|
19
|
-
|
|
20
15
|
const cartId = (req.query?.cart_id as string) || ""
|
|
21
16
|
const query = req.scope.resolve("query")
|
|
22
|
-
|
|
23
17
|
let currency = normalizeCurrencyCode(
|
|
24
18
|
apiDetails?.apiDetails?.currency_code || process.env.PAYPAL_CURRENCY || "EUR"
|
|
25
19
|
)
|
|
@@ -29,7 +23,6 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
|
29
23
|
fields: ["id", "currency_code", "region.currency_code"],
|
|
30
24
|
filters: { id: cartId },
|
|
31
25
|
})
|
|
32
|
-
|
|
33
26
|
const cart = carts?.[0]
|
|
34
27
|
if (cart) {
|
|
35
28
|
currency = normalizeCurrencyCode(
|
|
@@ -37,13 +30,23 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
|
37
30
|
)
|
|
38
31
|
}
|
|
39
32
|
}
|
|
40
|
-
|
|
41
33
|
const compatibility = getPayPalCurrencyCompatibility({
|
|
42
34
|
currencyCode: currency,
|
|
43
35
|
paypalCurrencyOverride:
|
|
44
36
|
apiDetails?.apiDetails?.currency_code || process.env.PAYPAL_CURRENCY,
|
|
45
37
|
})
|
|
46
38
|
|
|
39
|
+
// Read payment action from settings so frontend SDK uses correct intent
|
|
40
|
+
const settings = await paypal.getSettings().catch(() => ({}))
|
|
41
|
+
const additionalSettings =
|
|
42
|
+
settings && typeof settings === "object" && "data" in settings
|
|
43
|
+
? ((settings as any).data?.additional_settings || {})
|
|
44
|
+
: {}
|
|
45
|
+
const paymentAction =
|
|
46
|
+
typeof additionalSettings.paymentAction === "string"
|
|
47
|
+
? additionalSettings.paymentAction
|
|
48
|
+
: "capture"
|
|
49
|
+
|
|
47
50
|
return res.json({
|
|
48
51
|
environment: creds.environment,
|
|
49
52
|
client_id: creds.client_id,
|
|
@@ -52,6 +55,7 @@ export async function GET(req: MedusaRequest, res: MedusaResponse) {
|
|
|
52
55
|
currency_errors: compatibility.errors,
|
|
53
56
|
supported_currencies: getPayPalSupportedCurrencies(),
|
|
54
57
|
client_token,
|
|
58
|
+
intent: paymentAction, // "capture" or "authorize"
|
|
55
59
|
})
|
|
56
60
|
} catch (e: any) {
|
|
57
61
|
return res.status(500).json({ message: e?.message || "Failed to load PayPal config" })
|