@easypayment/medusa-paypal 0.6.4 → 0.6.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.js +10 -10
- package/.medusa/server/src/admin/index.mjs +10 -10
- package/.medusa/server/src/api/store/paypal-complete/route.d.ts.map +1 -1
- package/.medusa/server/src/api/store/paypal-complete/route.js +46 -18
- package/.medusa/server/src/api/store/paypal-complete/route.js.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts +0 -8
- package/.medusa/server/src/modules/paypal/payment-provider/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/payment-provider/service.js +129 -131
- package/.medusa/server/src/modules/paypal/payment-provider/service.js.map +1 -1
- package/.medusa/server/src/modules/paypal/service.d.ts +0 -46
- package/.medusa/server/src/modules/paypal/service.d.ts.map +1 -1
- package/.medusa/server/src/modules/paypal/service.js +0 -94
- package/.medusa/server/src/modules/paypal/service.js.map +1 -1
- package/package.json +1 -1
- package/src/api/store/paypal-complete/route.ts +58 -23
- package/src/modules/paypal/payment-provider/service.ts +196 -244
- package/src/modules/paypal/service.ts +0 -98
|
@@ -103,10 +103,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
103
103
|
return env === "live" ? onboarding.partner_merchant_id_live : onboarding.partner_merchant_id_sandbox
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
/**
|
|
107
|
-
* We keep a single row in DB and store the currently selected environment there.
|
|
108
|
-
* If no row exists yet, default to live (production).
|
|
109
|
-
*/
|
|
110
106
|
private async getCurrentRow(): Promise<any | null> {
|
|
111
107
|
const rows = await this.listPayPalConnections({})
|
|
112
108
|
return rows?.[0] ?? null
|
|
@@ -185,10 +181,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
185
181
|
}
|
|
186
182
|
}
|
|
187
183
|
|
|
188
|
-
// Fallback: traverse nested values so shapes like
|
|
189
|
-
// { email_address: { value: "seller@example.com" } }
|
|
190
|
-
// or { email: { address: "seller@example.com" } }
|
|
191
|
-
// are still detected.
|
|
192
184
|
queue.push(...Object.values(obj))
|
|
193
185
|
}
|
|
194
186
|
}
|
|
@@ -406,18 +398,12 @@ class PayPalModuleService extends MedusaService({
|
|
|
406
398
|
})
|
|
407
399
|
}
|
|
408
400
|
|
|
409
|
-
/**
|
|
410
|
-
* Set environment based on admin UI selection (WooCommerce-style).
|
|
411
|
-
* Switching environment clears stored credentials and requires re-onboarding.
|
|
412
|
-
*/
|
|
413
|
-
|
|
414
401
|
async setEnvironment(env: Environment) {
|
|
415
402
|
const nextEnv: Environment = env === "sandbox" ? "sandbox" : "live"
|
|
416
403
|
const row = await this.getCurrentRow()
|
|
417
404
|
const previousEnv = (row?.environment as Environment) || "live"
|
|
418
405
|
|
|
419
406
|
if (!row) {
|
|
420
|
-
// Create a row with no credentials yet for either environment
|
|
421
407
|
const created = await this.createPayPalConnections({
|
|
422
408
|
environment: nextEnv,
|
|
423
409
|
status: "disconnected",
|
|
@@ -438,7 +424,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
438
424
|
return created
|
|
439
425
|
}
|
|
440
426
|
|
|
441
|
-
// Just switch the active environment (do NOT wipe other env credentials)
|
|
442
427
|
await this.updatePayPalConnections({
|
|
443
428
|
id: row.id,
|
|
444
429
|
environment: nextEnv,
|
|
@@ -450,7 +435,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
450
435
|
},
|
|
451
436
|
})
|
|
452
437
|
|
|
453
|
-
// Sync top-level fields/status for the active env so existing code keeps working
|
|
454
438
|
const updated = await this.getCurrentRow()
|
|
455
439
|
if (updated) {
|
|
456
440
|
await this.syncRowFieldsFromMetadata(updated, nextEnv)
|
|
@@ -463,36 +447,18 @@ class PayPalModuleService extends MedusaService({
|
|
|
463
447
|
return await this.getCurrentRow()
|
|
464
448
|
}
|
|
465
449
|
|
|
466
|
-
/**
|
|
467
|
-
* ✅ WooCommerce-style signup link generation (your service returns PayPal partner-referrals JSON)
|
|
468
|
-
*
|
|
469
|
-
* - POST to your PHP service (WPG_ONBOARDING_URL)
|
|
470
|
-
* - Content-Type: application/x-www-form-urlencoded
|
|
471
|
-
* - fields: email, sandbox, return_url, return_url_description, products[], partner_merchant_id
|
|
472
|
-
*
|
|
473
|
-
* Response formats supported:
|
|
474
|
-
* 1) PayPal partner-referrals JSON: { links: [ { rel: "action_url", href: "..." }, ... ] }
|
|
475
|
-
* 2) Custom JSON: { onboarding_url: "..." }
|
|
476
|
-
* 3) Plain URL string
|
|
477
|
-
*/
|
|
478
450
|
async createOnboardingLink(input?: { email?: string; products?: string[] }) {
|
|
479
451
|
const { onboarding } = await this.ensureSettingsDefaults()
|
|
480
452
|
const return_url = `${String(onboarding.backend_url || "").replace(/\/$/, "")}/admin/paypal/onboard-complete`
|
|
481
453
|
const env = await this.getCurrentEnvironment()
|
|
482
454
|
const partner_merchant_id = await this.getPartnerMerchantId(env)
|
|
483
455
|
|
|
484
|
-
// Match WooCommerce behavior: prefer the current admin user email when available.
|
|
485
|
-
// If it's missing, continue without it (some services can infer or ignore the field).
|
|
486
456
|
const email = (input?.email || "").trim()
|
|
487
457
|
|
|
488
458
|
if (!partner_merchant_id) {
|
|
489
459
|
throw new Error("Missing PAYPAL_PARTNER_MERCHANT_ID_* env for current environment")
|
|
490
460
|
}
|
|
491
461
|
|
|
492
|
-
// NOTE:
|
|
493
|
-
// We intentionally avoid DB access here because Medusa v2 has a known issue where
|
|
494
|
-
// MedusaService-generated DB methods can throw 'fork' errors when called outside a transaction context.
|
|
495
|
-
// We store onboarding state later when the JS callback returns authCode/sharedId.
|
|
496
462
|
const form = new URLSearchParams()
|
|
497
463
|
if (email) {
|
|
498
464
|
form.set("email", email)
|
|
@@ -504,10 +470,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
504
470
|
|
|
505
471
|
const products = input?.products?.length ? input.products : ["PPCP"]
|
|
506
472
|
|
|
507
|
-
// WooCommerce/wp_remote_request encodes PHP arrays like products[0]=PPCP.
|
|
508
|
-
// To maximize compatibility with your existing PHP bridge, we send BOTH:
|
|
509
|
-
// - products[0], products[1], ...
|
|
510
|
-
// - products[] (common PHP convention)
|
|
511
473
|
products.forEach((p, i) => {
|
|
512
474
|
form.append(`products[${i}]`, p)
|
|
513
475
|
form.append("products[]", p)
|
|
@@ -526,7 +488,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
526
488
|
|
|
527
489
|
const trimmed = text.trim()
|
|
528
490
|
|
|
529
|
-
// plain URL
|
|
530
491
|
if (trimmed.startsWith("http")) {
|
|
531
492
|
return { onboarding_url: trimmed, return_url }
|
|
532
493
|
}
|
|
@@ -538,22 +499,13 @@ class PayPalModuleService extends MedusaService({
|
|
|
538
499
|
throw new Error(`Invalid onboarding link response (not JSON / URL): ${trimmed.slice(0, 200)}`)
|
|
539
500
|
}
|
|
540
501
|
|
|
541
|
-
/**
|
|
542
|
-
* ✅ WooCommerce-style wrapper support
|
|
543
|
-
*
|
|
544
|
-
* Your PHP service (same as WooCommerce) often returns a wrapper like:
|
|
545
|
-
* { result, http_code, headers, body }
|
|
546
|
-
* where `body` is the actual PayPal partner-referrals JSON string.
|
|
547
|
-
*/
|
|
548
502
|
if (json?.body) {
|
|
549
503
|
const inner = typeof json.body === "string" ? json.body.trim() : json.body
|
|
550
504
|
|
|
551
|
-
// body is a plain URL
|
|
552
505
|
if (typeof inner === "string" && inner.startsWith("http")) {
|
|
553
506
|
return { onboarding_url: inner, return_url }
|
|
554
507
|
}
|
|
555
508
|
|
|
556
|
-
// body is JSON string/object
|
|
557
509
|
try {
|
|
558
510
|
json = typeof inner === "string" ? JSON.parse(inner) : inner
|
|
559
511
|
} catch {
|
|
@@ -565,7 +517,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
565
517
|
}
|
|
566
518
|
}
|
|
567
519
|
|
|
568
|
-
// Typical error shape: { name, message, debug_id, details: [...], links: [...] }
|
|
569
520
|
if (json?.name && json?.message && (json?.debug_id || json?.details || json?.links)) {
|
|
570
521
|
const debug = json.debug_id ? ` debug_id=${json.debug_id}` : ""
|
|
571
522
|
const details = Array.isArray(json.details)
|
|
@@ -584,12 +535,10 @@ class PayPalModuleService extends MedusaService({
|
|
|
584
535
|
throw new Error(`PayPal onboarding error: ${json.name}: ${json.message}.${debug}${details ? ` Details: ${details}` : ""}`)
|
|
585
536
|
}
|
|
586
537
|
|
|
587
|
-
// custom json
|
|
588
538
|
if (json?.onboarding_url && String(json.onboarding_url).startsWith("http")) {
|
|
589
539
|
return { onboarding_url: String(json.onboarding_url), return_url }
|
|
590
540
|
}
|
|
591
541
|
|
|
592
|
-
// PayPal partner-referrals format: links[] rel=action_url
|
|
593
542
|
const links = Array.isArray(json?.links) ? json.links : null
|
|
594
543
|
if (links) {
|
|
595
544
|
const action = links.find(
|
|
@@ -611,7 +560,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
611
560
|
const env = await this.getCurrentEnvironment()
|
|
612
561
|
|
|
613
562
|
if (row) {
|
|
614
|
-
// MedusaService-generated update methods expect an object that includes the entity id
|
|
615
563
|
await this.updatePayPalConnections({ id: row.id, status: "pending" })
|
|
616
564
|
return
|
|
617
565
|
}
|
|
@@ -645,29 +593,16 @@ class PayPalModuleService extends MedusaService({
|
|
|
645
593
|
})
|
|
646
594
|
}
|
|
647
595
|
|
|
648
|
-
/**
|
|
649
|
-
* Exchange authCode/sharedId for seller API credentials (server-side) and save in DB.
|
|
650
|
-
*
|
|
651
|
-
* This calls an optional exchange service you control:
|
|
652
|
-
* PAYPAL_EXCHANGE_SERVICE_URL or PAYPAL_PARTNER_EXCHANGE_URL
|
|
653
|
-
*
|
|
654
|
-
* Expected JSON response:
|
|
655
|
-
* { clientId: string, clientSecret: string, merchantId?: string }
|
|
656
|
-
*/
|
|
657
596
|
async exchangeAndSaveSellerCredentials(input: {
|
|
658
597
|
authCode: string
|
|
659
598
|
sharedId: string
|
|
660
599
|
env?: "sandbox" | "live"
|
|
661
600
|
}) {
|
|
662
|
-
// 1) Persist callback (sharedId/authCode) first
|
|
663
601
|
await this.saveOnboardCallback({ authCode: input.authCode, sharedId: input.sharedId })
|
|
664
602
|
|
|
665
|
-
// 2) Exchange authCode + sharedId (+ seller nonce) to get SELLER access token
|
|
666
603
|
const env = (input.env || (await this.getCurrentEnvironment())) as Environment
|
|
667
604
|
const baseUrl = env === "live" ? "https://api-m.paypal.com" : "https://api-m.sandbox.paypal.com"
|
|
668
605
|
|
|
669
|
-
// IMPORTANT: code_verifier MUST match the seller_nonce used when creating the onboarding link.
|
|
670
|
-
// In WooCommerce you use a fixed nonce() and it works, so we do the same here (no DB storage).
|
|
671
606
|
const { onboarding } = await this.ensureSettingsDefaults()
|
|
672
607
|
const sellerNonce = (onboarding.seller_nonce || "").trim()
|
|
673
608
|
if (!sellerNonce) {
|
|
@@ -709,7 +644,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
709
644
|
throw new Error("PayPal token exchange succeeded but access_token is missing.")
|
|
710
645
|
}
|
|
711
646
|
|
|
712
|
-
// 3) Use SELLER access token to fetch seller REST API credentials
|
|
713
647
|
const partnerMerchantId = await this.getPartnerMerchantId(env)
|
|
714
648
|
if (!partnerMerchantId) {
|
|
715
649
|
throw new Error("Missing PayPal partner merchant id configuration.")
|
|
@@ -755,7 +689,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
755
689
|
null
|
|
756
690
|
|
|
757
691
|
if (!sellerEmail) {
|
|
758
|
-
// Use all available merchant/payer ID candidates from the token and credential responses
|
|
759
692
|
const merchantCandidates = [
|
|
760
693
|
String(credJson.payer_id || "").trim(),
|
|
761
694
|
String(credJson.merchant_id || "").trim(),
|
|
@@ -777,8 +710,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
777
710
|
}
|
|
778
711
|
}
|
|
779
712
|
|
|
780
|
-
// 4) Save seller credentials (marks status = connected)
|
|
781
|
-
// We save FIRST so that getAppAccessToken() works for the post-save email lookup below
|
|
782
713
|
await this.saveSellerCredentials({
|
|
783
714
|
clientId,
|
|
784
715
|
clientSecret,
|
|
@@ -786,9 +717,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
786
717
|
sellerEmail,
|
|
787
718
|
})
|
|
788
719
|
|
|
789
|
-
// 5) Post-save email lookup via merchant_id.
|
|
790
|
-
// Some partner accounts do not have permission to query by tracking_id,
|
|
791
|
-
// so we only rely on merchant integration detail lookup.
|
|
792
720
|
if (!sellerEmail && sellerMerchantId) {
|
|
793
721
|
try {
|
|
794
722
|
const appAccessToken = await this.getAppAccessToken()
|
|
@@ -801,10 +729,8 @@ class PayPalModuleService extends MedusaService({
|
|
|
801
729
|
console.warn("[PayPal] Post-save merchant_id email lookup failed:", e?.message || e)
|
|
802
730
|
}
|
|
803
731
|
}
|
|
804
|
-
|
|
805
732
|
}
|
|
806
733
|
|
|
807
|
-
|
|
808
734
|
async saveSellerCredentials(input: {
|
|
809
735
|
clientId: string
|
|
810
736
|
clientSecret: string
|
|
@@ -1114,7 +1040,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
1114
1040
|
|
|
1115
1041
|
const meta = (row.metadata || {}) as any
|
|
1116
1042
|
const creds = { ...(meta.credentials || {}) }
|
|
1117
|
-
// Remove only the active environment credentials
|
|
1118
1043
|
delete creds[env]
|
|
1119
1044
|
|
|
1120
1045
|
const hasAnyCreds = Object.values(creds).some((v: any) => {
|
|
@@ -1188,12 +1113,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
1188
1113
|
return accessToken
|
|
1189
1114
|
}
|
|
1190
1115
|
|
|
1191
|
-
/**
|
|
1192
|
-
* Generate a client token for PayPal JS SDK (required for CardFields/PaymentFields).
|
|
1193
|
-
* This token is short-lived and safe to send to the browser.
|
|
1194
|
-
*
|
|
1195
|
-
* PayPal endpoint: POST /v1/identity/generate-token
|
|
1196
|
-
*/
|
|
1197
1116
|
async generateClientToken(opts?: { locale?: string }): Promise<string> {
|
|
1198
1117
|
const env = await this.getCurrentEnvironment()
|
|
1199
1118
|
const baseUrl = env === "live" ? "https://api-m.paypal.com" : "https://api-m.sandbox.paypal.com"
|
|
@@ -1224,20 +1143,12 @@ class PayPalModuleService extends MedusaService({
|
|
|
1224
1143
|
return token
|
|
1225
1144
|
}
|
|
1226
1145
|
|
|
1227
|
-
/**
|
|
1228
|
-
* GLOBAL PayPal settings (single row)
|
|
1229
|
-
*/
|
|
1230
1146
|
async getSettings() {
|
|
1231
1147
|
const rows = await this.listPayPalSettings({})
|
|
1232
1148
|
const row = rows?.[0]
|
|
1233
1149
|
return { data: (row?.data || {}) as Record<string, any> }
|
|
1234
1150
|
}
|
|
1235
1151
|
|
|
1236
|
-
/**
|
|
1237
|
-
* Deep-merge patch into current settings.
|
|
1238
|
-
* Nested objects (additional_settings, api_details, etc.) are merged,
|
|
1239
|
-
* not replaced.
|
|
1240
|
-
*/
|
|
1241
1152
|
private deepMerge(
|
|
1242
1153
|
target: Record<string, any>,
|
|
1243
1154
|
source: Record<string, any>
|
|
@@ -1278,9 +1189,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
1278
1189
|
return { data: next }
|
|
1279
1190
|
}
|
|
1280
1191
|
|
|
1281
|
-
/**
|
|
1282
|
-
* Active credentials based on selected environment in the single connection row.
|
|
1283
|
-
*/
|
|
1284
1192
|
async getActiveCredentials() {
|
|
1285
1193
|
const row = await this.getCurrentRow()
|
|
1286
1194
|
const env = await this.getCurrentEnvironment()
|
|
@@ -1411,7 +1319,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
1411
1319
|
return null
|
|
1412
1320
|
}
|
|
1413
1321
|
|
|
1414
|
-
|
|
1415
1322
|
async recordMetric(name: string, metadata?: Record<string, unknown>) {
|
|
1416
1323
|
const existing = await this.listPayPalMetrics({ name })
|
|
1417
1324
|
const row = existing?.[0]
|
|
@@ -1438,11 +1345,6 @@ class PayPalModuleService extends MedusaService({
|
|
|
1438
1345
|
}
|
|
1439
1346
|
|
|
1440
1347
|
async recordPaymentLog(eventType: string, metadata?: Record<string, unknown>) {
|
|
1441
|
-
const payload = {
|
|
1442
|
-
event_type: eventType,
|
|
1443
|
-
metadata: metadata ?? {},
|
|
1444
|
-
created_at: new Date().toISOString(),
|
|
1445
|
-
}
|
|
1446
1348
|
return await this.recordAuditEvent(`payment_${eventType}`, metadata)
|
|
1447
1349
|
}
|
|
1448
1350
|
|