I'm developing an online shop, I have basically finished my application, at the moment I'm developing the payment part. My app consists on flutter, althought all my payment authorization and configs are stored in google cloud functions for safety reasons. For payments I'm using the Cielo Payment sandbox, with is a payment method that has sandbox so I can make my tests. I'm getting some error from my functions in google cloud with wasn't suppose to happen.
This is the website from cielo so I can acquire the keys for sandbox: https://cadastrosandbox.cieloecommerce.cielo.com.br/
The error I get:
Unhandled error TypeError: Cannot read property 'Code' of undefined
This is my index.ts:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import {CieloConstructor, Cielo,
TransactionCreditCardRequestModel,
EnumBrands, CaptureRequestModel} from "cielo";
// CaptureRequestModel, CancelTransactionRequestModel,
// TransactionCreditCardResponseModel
admin.initializeApp(functions.config().firebase);
// // Start writing Firebase Functions
// // https://firebase.google.com/docs/functions/typescript
const merchantId = functions.config().cielo.merchantid;
const merchantKey = functions.config().cielo.merchantkey;
const cieloParams: CieloConstructor = {
merchantId: merchantId,
merchantKey: merchantKey,
sandbox: true,
debug: true, // Remover quando for fazer transações reais
};
const cielo = new Cielo(cieloParams);
export const authorizeCreditCard = functions.https.
onCall( async (data, context) => {
if (data === null) {
return {"success": false, "error":
{"code": -1, "message": "Dados não informados"}};
}
if (!context.auth) {
return {"success": false, "error":
{"code": -1, "message": "Nenhum usuário logado"}};
}
const userId = context.auth.uid;
const snapshot = await admin.firestore().collection("users").
doc(userId).get();
const userData = snapshot.data() || {};
console.log("Iniciando autorização");
let brand: EnumBrands;
switch (data.creditCard.brand) {
case "VISA":
brand = EnumBrands.VISA;
break;
case "MASTERCARD":
brand = EnumBrands.MASTER;
break;
case "AMEX":
brand = EnumBrands.AMEX;
break;
case "ELO":
brand = EnumBrands.ELO;
break;
case "JCB":
brand = EnumBrands.JCB;
break;
case "DINERSCLUB":
brand = EnumBrands.DINERS;
break;
case "DISCOVER":
brand = EnumBrands.DISCOVERY;
break;
case "HIPERCARD":
brand = EnumBrands.HIPERCARD;
break;
default:
return {
"success": false, "error": {
"code": -1, "message": "Cartão não suportado: " +
data.creditCard.brand,
},
};
}
const saleData: TransactionCreditCardRequestModel = {
merchantOrderId: data.merchantOrderId,
customer: {
name: userData.name,
identity: data.cpf,
identityType: "CPF",
email: userData.email,
deliveryAddress: {
street: userData.address.street,
number: userData.address.number,
complement: userData.address.complement,
zipCode: userData.address.zipCode.replace(".", "").replace("-", ""),
city: userData.address.city,
state: userData.address.state,
country: "BRA",
district: userData.address.district,
},
},
payment: {
currency: "BRL",
country: "BRA",
amount: data.amount,
installments: data.installments,
softDescriptor: data.softDescriptor.substring(0, 13),
type: data.paymentType,
capture: false,
creditCard: {
cardNumber: data.creditCard.cardNumber,
holder: data.creditCard.holder,
expirationDate: data.creditCard.expirationDate,
securityCode: data.creditCard.securityCode,
brand: brand,
},
},
};
try {
const transaction = await cielo.creditCard.transaction(saleData);
if (transaction.payment.status === 1) {
return {
"success": true,
"paymentId": transaction.payment.paymentId,
};
} else {
let message = "";
switch (transaction.payment.returnCode) {
case "5":
message = "Não Autorizada";
break;
case "57":
message = "Cartão expirado";
break;
case "78":
message = "Cartão bloqueado";
break;
case "99":
message = "Timeout";
break;
case "77":
message = "Cartão cancelado";
break;
case "70":
message = "Problemas com o Cartão de Crédito";
break;
default:
message = transaction.payment.returnMessage;
break;
}
return {
"success": false,
"status": transaction.payment.status,
"error": {
"code": transaction.payment.returnCode,
"message": message,
},
};
}
} catch (error) {
return {
"success": false,
"error": {
"code": error.response[0].Code,
"message": error.response[0].Message,
},
};
}
});
export const captureCreditCard = functions.https.
onCall( async (data, context) => {
if (data === null) {
return {"success": false, "error":
{"code": -1, "message": "Dados não informados"}};
}
if (!context.auth) {
return {"success": false, "error":
{"code": -1, "message": "Nenhum usuário logado"}};
}
const captureParams: CaptureRequestModel = {
paymentId: data.payId,
};
try {
const capture = await cielo.creditCard.
captureSaleTransaction(captureParams);
if (capture.status == 2) {
return {
"success": true,
};
} else {
return {
"success": false,
"status": capture.status,
"error": {
"code": capture.returnCode,
"message": capture.returnMessage,
},
};
}
} catch (error) {
return {
"success": false,
"error": {
"code": error.response[0].Code,
"message": error.response[0].Message,
},
};
}
});
My cielo_payment.dart:
import 'dart:collection';
import 'package:cloud_functions/cloud_functions.dart';
import 'package:flutter/cupertino.dart';
import 'package:loja_virtual_nnananene/models/credit_card.dart';
import 'package:loja_virtual_nnananene/models/user.dart';
class CieloPayment {
final functions = CloudFunctions.instance;
Future<String>? authorize(
{CreditCard? creditCard, num? price, String? orderId, User? user}) async {
try {
final Map<String, dynamic> dataSale = {
'merchantOrderId': orderId,
'amount': (price! * 100).toInt(),
'softDescriptor': 'Nnananene',
'installments': 1,
'creditCard': creditCard!.toJson(),
'cpf': user!.cpf,
'paymentType': 'CreditCard',
};
final HttpsCallable callable =
functions.getHttpsCallable(functionName: 'authorizeCreditCard');
callable.timeout = const Duration(seconds: 60);
final response = await callable.call(dataSale);
print(response.data);
final data = Map<String, dynamic>.from(response.data);
if (data['success'] as bool) {
return data['paymentId'];
} else {
debugPrint('${data['error']['message']}');
return Future.error(data['error']['message']);
}
} catch (e) {
debugPrint('$e');
return Future.error('Falha ao processar transação. Tente novamente.');
}
}
Future<void> capture(String payId) async {
final Map<String, dynamic> captureData = {'payId': payId};
final HttpsCallable callable =
functions.getHttpsCallable(functionName: 'captureCreditCard');
callable.timeout = const Duration(seconds: 60);
final response = await callable.call(captureData);
final data = Map<String, dynamic>.from(response.data as LinkedHashMap);
if (data['success'] as bool) {
debugPrint('Captura realizada com sucesso');
} else {
debugPrint('${data['error']['message']}');
return Future.error(data['error']['message']);
}
}
Future<void> cancel(String payId) async {
final Map<String, dynamic> cancelData = {'payId': payId};
final HttpsCallable callable =
functions.getHttpsCallable(functionName: 'cancelCreditCard');
callable.timeout = const Duration(seconds: 60);
final response = await callable.call(cancelData);
final data = Map<String, dynamic>.from(response.data as LinkedHashMap);
if (data['success'] as bool) {
debugPrint('Cancelamento realizado com sucesso');
} else {
debugPrint('${data['error']['message']}');
return Future.error(data['error']['message']);
}
}
}
My checkout_manager.dart where everything happens:
Future<void> checkout(
{CreditCard? creditCard,
Function? onStockFail,
Function? onSuccess,
Function? onPayFail}) async {
loading = true;
final orderId = await _getOrderId();
try {
String? payId = await cieloPayment.authorize(
creditCard: creditCard,
price: cartManager!.totalPrice,
orderId: orderId.toString(),
user: cartManager!.user,
);
debugPrint('success $payId');
} catch (e) {
onPayFail!(e);
loading = false;
return;
}
try {
await _decrementStock();
} catch (e) {
onStockFail!(e);
loading = false;
return;
}
This are the lines the error refers to:
line 150:43 - "code": error.respose[0].Code, // 43 refers to the dot in .Code
line 95:5 - cardNumber: data.creditCard.cardNumber,
This is the error I get from my app, this is not a true credit card, and In the sandbox, when the card finishes with 1, is a successful transaction.
This is the print from dataSale and response:
The error was at the validation from the card expiraation date, with had spaces causing an error
Change the following
error.response[0].Code
error.response[0].Message
to this:
error.code
error.message
The correct way to get an error's code
and message
in Node.js is by calling .code and .message on the error object itself.