@pandait.tech/payment-nuvei 1.1.2 → 1.1.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.
@@ -161,6 +161,8 @@ interface NuveiWebhookPayload {
161
161
  id: string;
162
162
  status: string;
163
163
  status_detail: number;
164
+ /** Desenlace en texto: APPROVED, CANCELLED, EXPIRED, REJECTED o PENDING. */
165
+ current_status?: string;
164
166
  dev_reference: string;
165
167
  amount: number;
166
168
  authorization_code: string | null;
@@ -161,6 +161,8 @@ interface NuveiWebhookPayload {
161
161
  id: string;
162
162
  status: string;
163
163
  status_detail: number;
164
+ /** Desenlace en texto: APPROVED, CANCELLED, EXPIRED, REJECTED o PENDING. */
165
+ current_status?: string;
164
166
  dev_reference: string;
165
167
  amount: number;
166
168
  authorization_code: string | null;
@@ -407,7 +407,7 @@ var NUVEI_ERROR_MESSAGES = {
407
407
  23: "Transacci\xF3n rechazada. Intenta de nuevo m\xE1s tarde.",
408
408
  31: "Tu banco requiere verificaci\xF3n OTP. Ingresa el c\xF3digo enviado a tu tel\xE9fono.",
409
409
  36: "Tu banco requiere verificaci\xF3n adicional 3DS. Completa el proceso en la ventana emergente.",
410
- 37: "Tu banco requiere verificaci\xF3n adicional 3DS. Completa el proceso en la ventana emergente."
410
+ 37: "Tu banco rechaz\xF3 la autenticaci\xF3n 3DS. Intenta con otra tarjeta."
411
411
  };
412
412
  var THREEDS_AUTH_MESSAGES = {
413
413
  N: "Autenticaci\xF3n 3DS rechazada por tu banco. Intenta con otra tarjeta.",
@@ -893,8 +893,9 @@ function createWebhookHandler(deps) {
893
893
  const currentStatus = orderDoc.data()?.status;
894
894
  const finalStatuses = ["paid", "delivered", "shipped", "refunded"];
895
895
  const statusDetail = Number(transaction.status_detail);
896
- const isAuthPending = statusDetail === 36 || statusDetail === 37;
897
- const shouldUpdateStatus = isApproved || !isAuthPending && !finalStatuses.includes(currentStatus);
896
+ const currentStatusRaw = transaction.current_status;
897
+ const isPendingNotice = typeof currentStatusRaw === "string" && currentStatusRaw.toUpperCase() === "PENDING" || [1, 31, 35, 36].includes(statusDetail);
898
+ const shouldUpdateStatus = isApproved || !isPendingNotice && !finalStatuses.includes(currentStatus);
898
899
  const orderData = orderDoc.data() ?? {};
899
900
  const webhookAuthCode = transaction.authorization_code;
900
901
  const hasValidAuthCode = typeof webhookAuthCode === "string" && webhookAuthCode.trim().length > 0 && webhookAuthCode !== "null";
@@ -1247,7 +1248,29 @@ function create3dsCompleteHandler(deps) {
1247
1248
  const txId = verifyResult.transaction?.id ?? raw["transaction_id"] ?? transactionId;
1248
1249
  const txAuthCode = verifyResult.transaction?.authorization_code ?? raw["authorization_code"] ?? null;
1249
1250
  const isSuccess = (txStatus === "success" || txStatus === 1) && txStatusDetail === 3;
1250
- const isStillPending = !isSuccess && (txStatusDetail === 36 || txStatusDetail === 37 || txStatus === "pending");
1251
+ const isStillPending = !isSuccess && // 37 = "Rejected by 3DS" (doc oficial): no espera. Un 37 que llegue pendiente
1252
+ // sigue entrando por txStatus === "pending".
1253
+ (txStatusDetail === 36 || txStatus === "pending");
1254
+ if (!isSuccess && (txStatusDetail === 36 || txStatusDetail === 37)) {
1255
+ const threeDSData = verifyResult["3ds"];
1256
+ const challengeHtml = threeDSData?.browser_response?.challenge_request || threeDSData?.browser_response?.hidden_iframe || "";
1257
+ if (challengeHtml) {
1258
+ await db.collection("orders").doc(orderId).update({
1259
+ nuveiTransactionId: txId,
1260
+ isDeviceFingerprint: FieldValue.delete(),
1261
+ updatedAt: /* @__PURE__ */ new Date(),
1262
+ threeDSCres: FieldValue.delete()
1263
+ });
1264
+ return json({
1265
+ challenge: true,
1266
+ challengeHtml,
1267
+ isDeviceFingerprint: false,
1268
+ orderId,
1269
+ nuveiTransactionId: txId,
1270
+ statusDetail: txStatusDetail
1271
+ });
1272
+ }
1273
+ }
1251
1274
  if (isStillPending) {
1252
1275
  logger.log(
1253
1276
  `[3ds-complete] Still pending: txStatus=${txStatus} detail=${txStatusDetail}. Polling continues.`
@@ -1291,26 +1314,6 @@ function create3dsCompleteHandler(deps) {
1291
1314
  orderId
1292
1315
  });
1293
1316
  }
1294
- if (txStatusDetail === 36 || txStatusDetail === 37) {
1295
- const threeDSData = verifyResult["3ds"];
1296
- const challengeHtml = threeDSData?.browser_response?.challenge_request || threeDSData?.browser_response?.hidden_iframe || "";
1297
- if (challengeHtml) {
1298
- await db.collection("orders").doc(orderId).update({
1299
- nuveiTransactionId: txId,
1300
- isDeviceFingerprint: FieldValue.delete(),
1301
- updatedAt: /* @__PURE__ */ new Date(),
1302
- threeDSCres: FieldValue.delete()
1303
- });
1304
- return json({
1305
- challenge: true,
1306
- challengeHtml,
1307
- isDeviceFingerprint: false,
1308
- orderId,
1309
- nuveiTransactionId: txId,
1310
- statusDetail: txStatusDetail
1311
- });
1312
- }
1313
- }
1314
1317
  await db.collection("orders").doc(orderId).update({
1315
1318
  status: "failed",
1316
1319
  chargeResponseAt: /* @__PURE__ */ new Date(),