@easypayment/medusa-paypal 0.6.4 → 0.6.5

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.
@@ -180,9 +180,6 @@ function AdditionalSettingsTab() {
180
180
  )
181
181
  ] }) });
182
182
  }
183
- function PayPalApplePayPage() {
184
- return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
185
- }
186
183
  async function adminFetch$1(path, opts = {}) {
187
184
  var _a;
188
185
  const { method = "GET", body, query } = opts;
@@ -322,6 +319,9 @@ function AdvancedCardPaymentsTab() {
322
319
  )
323
320
  ] }) });
324
321
  }
322
+ function PayPalApplePayPage() {
323
+ return /* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Navigate, { to: "/settings/paypal/connection", replace: true });
324
+ }
325
325
  const config = adminSdk.defineRouteConfig({
326
326
  label: "PayPal Connection",
327
327
  hide: true
@@ -1206,14 +1206,14 @@ const routeModule = {
1206
1206
  Component: AdditionalSettingsTab,
1207
1207
  path: "/settings/paypal/additional-settings"
1208
1208
  },
1209
- {
1210
- Component: PayPalApplePayPage,
1211
- path: "/settings/paypal/apple-pay"
1212
- },
1213
1209
  {
1214
1210
  Component: AdvancedCardPaymentsTab,
1215
1211
  path: "/settings/paypal/advanced-card-payments"
1216
1212
  },
1213
+ {
1214
+ Component: PayPalApplePayPage,
1215
+ path: "/settings/paypal/apple-pay"
1216
+ },
1217
1217
  {
1218
1218
  Component: PayPalConnectionPage,
1219
1219
  path: "/settings/paypal/connection"
@@ -179,9 +179,6 @@ function AdditionalSettingsTab() {
179
179
  )
180
180
  ] }) });
181
181
  }
182
- function PayPalApplePayPage() {
183
- return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
184
- }
185
182
  async function adminFetch$1(path, opts = {}) {
186
183
  var _a;
187
184
  const { method = "GET", body, query } = opts;
@@ -321,6 +318,9 @@ function AdvancedCardPaymentsTab() {
321
318
  )
322
319
  ] }) });
323
320
  }
321
+ function PayPalApplePayPage() {
322
+ return /* @__PURE__ */ jsx(Navigate, { to: "/settings/paypal/connection", replace: true });
323
+ }
324
324
  const config = defineRouteConfig({
325
325
  label: "PayPal Connection",
326
326
  hide: true
@@ -1205,14 +1205,14 @@ const routeModule = {
1205
1205
  Component: AdditionalSettingsTab,
1206
1206
  path: "/settings/paypal/additional-settings"
1207
1207
  },
1208
- {
1209
- Component: PayPalApplePayPage,
1210
- path: "/settings/paypal/apple-pay"
1211
- },
1212
1208
  {
1213
1209
  Component: AdvancedCardPaymentsTab,
1214
1210
  path: "/settings/paypal/advanced-card-payments"
1215
1211
  },
1212
+ {
1213
+ Component: PayPalApplePayPage,
1214
+ path: "/settings/paypal/apple-pay"
1215
+ },
1216
1216
  {
1217
1217
  Component: PayPalConnectionPage,
1218
1218
  path: "/settings/paypal/connection"
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/api/store/paypal-complete/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAK7E,wBAAsB,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,2BAgEjE"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/api/store/paypal-complete/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAK7E,wBAAsB,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,cAAc,2BAmGjE"}
@@ -8,17 +8,6 @@ async function POST(req, res) {
8
8
  return res.status(400).json({ error: "cart_id is required" });
9
9
  }
10
10
  try {
11
- const paypal = req.scope.resolve("paypal_onboarding");
12
- const settings = await paypal.getSettings().catch(() => ({}));
13
- const settingsData = settings && typeof settings === "object" && "data" in settings
14
- ? (settings.data ?? {})
15
- : {};
16
- const additionalSettings = (settingsData.additional_settings || {});
17
- const paymentAction = typeof additionalSettings.paymentAction === "string"
18
- ? additionalSettings.paymentAction
19
- : "capture";
20
- const sessionStatus = paymentAction === "authorize" ? "authorized" : "captured";
21
- const timestampKey = paymentAction === "authorize" ? "authorized_at" : "captured_at";
22
11
  const query = req.scope.resolve("query");
23
12
  const { data: carts } = await query.graph({
24
13
  entity: "cart",
@@ -26,6 +15,7 @@ async function POST(req, res) {
26
15
  "id",
27
16
  "payment_collection.payment_sessions.id",
28
17
  "payment_collection.payment_sessions.data",
18
+ "payment_collection.payment_sessions.status",
29
19
  "payment_collection.payment_sessions.provider_id",
30
20
  "payment_collection.payment_sessions.created_at",
31
21
  "payment_collection.payment_sessions.amount",
@@ -40,14 +30,52 @@ async function POST(req, res) {
40
30
  if (!session) {
41
31
  return res.status(400).json({ error: "No PayPal payment session found for cart" });
42
32
  }
33
+ // If already authorized or captured, nothing to do
34
+ const currentStatus = String(session.status || "");
35
+ if (currentStatus === "authorized" || currentStatus === "captured") {
36
+ console.info("[paypal-complete] session already in terminal status:", currentStatus);
37
+ return res.json({ success: true, session_id: session.id, status: currentStatus });
38
+ }
43
39
  const paymentModule = req.scope.resolve(utils_1.Modules.PAYMENT);
44
- await paymentModule.updatePaymentSession({
45
- id: session.id,
46
- data: { ...(session.data || {}), [timestampKey]: new Date().toISOString() },
47
- status: sessionStatus,
48
- amount: session.amount,
49
- currency_code: session.currency_code,
50
- });
40
+ // Read LIVE session data from DB — gets the latest state written by capture-order
41
+ // (avoids overwriting authorization_id / capture_id that capture-order just saved)
42
+ const [liveSession] = await paymentModule.listPaymentSessions({ id: [session.id] }, { take: 1 });
43
+ const liveData = (liveSession?.data || {});
44
+ // Determine payment action from settings
45
+ const paypal = req.scope.resolve("paypal_onboarding");
46
+ const settings = await paypal.getSettings().catch(() => ({}));
47
+ const settingsData = settings && typeof settings === "object" && "data" in settings
48
+ ? (settings.data ?? {})
49
+ : {};
50
+ const additionalSettings = (settingsData.additional_settings || {});
51
+ const paymentAction = typeof additionalSettings.paymentAction === "string"
52
+ ? additionalSettings.paymentAction
53
+ : "capture";
54
+ const timestampKey = paymentAction === "authorize" ? "authorized_at" : "captured_at";
55
+ // Only write timestamp if not already present — avoids overwriting capture-order's data
56
+ if (!liveData[timestampKey]) {
57
+ await paymentModule.updatePaymentSession({
58
+ id: session.id,
59
+ data: {
60
+ ...liveData,
61
+ [timestampKey]: new Date().toISOString(),
62
+ },
63
+ amount: liveSession?.amount ?? session.amount,
64
+ currency_code: liveSession?.currency_code ?? session.currency_code,
65
+ });
66
+ }
67
+ // Trigger Medusa's payment state machine — the only correct way to move
68
+ // a session from "pending" → "authorized".
69
+ // Calls the provider's authorizePayment() which checks for
70
+ // authorization_id / authorized_at in data and returns status: "authorized".
71
+ try {
72
+ await paymentModule.authorizePaymentSession(session.id, {});
73
+ console.info("[paypal-complete] authorizePaymentSession succeeded for session", session.id);
74
+ }
75
+ catch (e) {
76
+ // Throws if session is already authorized/captured — that's expected and fine
77
+ console.warn("[paypal-complete] authorizePaymentSession non-fatal:", e?.message);
78
+ }
51
79
  return res.json({ success: true, session_id: session.id });
52
80
  }
53
81
  catch (e) {
@@ -1 +1 @@
1
- {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../../src/api/store/paypal-complete/route.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../../src/api/store/paypal-complete/route.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easypayment/medusa-paypal",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "description": "Industry-standard PayPal integration for Medusa v2",
5
5
  "license": "MIT",
6
6
  "main": "./.medusa/server/src/index.js",
@@ -11,21 +11,6 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
11
11
  }
12
12
 
13
13
  try {
14
- const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
15
- const settings = await paypal.getSettings().catch(() => ({}))
16
- const settingsData =
17
- settings && typeof settings === "object" && "data" in settings
18
- ? ((settings as { data?: Record<string, any> }).data ?? {})
19
- : {}
20
- const additionalSettings = (settingsData.additional_settings || {}) as Record<string, any>
21
- const paymentAction =
22
- typeof additionalSettings.paymentAction === "string"
23
- ? additionalSettings.paymentAction
24
- : "capture"
25
-
26
- const sessionStatus = paymentAction === "authorize" ? "authorized" : "captured"
27
- const timestampKey = paymentAction === "authorize" ? "authorized_at" : "captured_at"
28
-
29
14
  const query = req.scope.resolve("query")
30
15
  const { data: carts } = await query.graph({
31
16
  entity: "cart",
@@ -33,6 +18,7 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
33
18
  "id",
34
19
  "payment_collection.payment_sessions.id",
35
20
  "payment_collection.payment_sessions.data",
21
+ "payment_collection.payment_sessions.status",
36
22
  "payment_collection.payment_sessions.provider_id",
37
23
  "payment_collection.payment_sessions.created_at",
38
24
  "payment_collection.payment_sessions.amount",
@@ -53,18 +39,67 @@ export async function POST(req: MedusaRequest, res: MedusaResponse) {
53
39
  return res.status(400).json({ error: "No PayPal payment session found for cart" })
54
40
  }
55
41
 
42
+ // If already authorized or captured, nothing to do
43
+ const currentStatus = String(session.status || "")
44
+ if (currentStatus === "authorized" || currentStatus === "captured") {
45
+ console.info("[paypal-complete] session already in terminal status:", currentStatus)
46
+ return res.json({ success: true, session_id: session.id, status: currentStatus })
47
+ }
48
+
56
49
  const paymentModule = req.scope.resolve(Modules.PAYMENT) as IPaymentModuleService
57
- await (paymentModule as any).updatePaymentSession({
58
- id: session.id,
59
- data: { ...(session.data || {}), [timestampKey]: new Date().toISOString() },
60
- status: sessionStatus as any,
61
- amount: session.amount,
62
- currency_code: session.currency_code,
63
- })
50
+
51
+ // Read LIVE session data from DB — gets the latest state written by capture-order
52
+ // (avoids overwriting authorization_id / capture_id that capture-order just saved)
53
+ const [liveSession] = await paymentModule.listPaymentSessions(
54
+ { id: [session.id] },
55
+ { take: 1 }
56
+ )
57
+
58
+ const liveData = (liveSession?.data || {}) as Record<string, any>
59
+
60
+ // Determine payment action from settings
61
+ const paypal = req.scope.resolve<PayPalModuleService>("paypal_onboarding")
62
+ const settings = await paypal.getSettings().catch(() => ({}))
63
+ const settingsData =
64
+ settings && typeof settings === "object" && "data" in settings
65
+ ? ((settings as { data?: Record<string, any> }).data ?? {})
66
+ : {}
67
+ const additionalSettings = (settingsData.additional_settings || {}) as Record<string, any>
68
+ const paymentAction =
69
+ typeof additionalSettings.paymentAction === "string"
70
+ ? additionalSettings.paymentAction
71
+ : "capture"
72
+
73
+ const timestampKey = paymentAction === "authorize" ? "authorized_at" : "captured_at"
74
+
75
+ // Only write timestamp if not already present — avoids overwriting capture-order's data
76
+ if (!liveData[timestampKey]) {
77
+ await (paymentModule as any).updatePaymentSession({
78
+ id: session.id,
79
+ data: {
80
+ ...liveData,
81
+ [timestampKey]: new Date().toISOString(),
82
+ },
83
+ amount: liveSession?.amount ?? session.amount,
84
+ currency_code: liveSession?.currency_code ?? session.currency_code,
85
+ })
86
+ }
87
+
88
+ // Trigger Medusa's payment state machine — the only correct way to move
89
+ // a session from "pending" → "authorized".
90
+ // Calls the provider's authorizePayment() which checks for
91
+ // authorization_id / authorized_at in data and returns status: "authorized".
92
+ try {
93
+ await (paymentModule as any).authorizePaymentSession(session.id, {})
94
+ console.info("[paypal-complete] authorizePaymentSession succeeded for session", session.id)
95
+ } catch (e: any) {
96
+ // Throws if session is already authorized/captured — that's expected and fine
97
+ console.warn("[paypal-complete] authorizePaymentSession non-fatal:", e?.message)
98
+ }
64
99
 
65
100
  return res.json({ success: true, session_id: session.id })
66
101
  } catch (e: any) {
67
102
  console.error("[paypal-complete] error:", e?.message || e)
68
103
  return res.status(500).json({ error: e?.message || "Internal error" })
69
104
  }
70
- }
105
+ }