- Toda lógica principal deve estar contida dentro de LoadCheckoutPaymentContext
- ES5 válido (Pode ser compilado ou o que for, mas é importante ter em conta os browser que damos suporte e não utilizar métodos sem polyfills - inclusive abrimos alguns métodos com polyfills para auxiliar no desenvolvimento)
Este método é exposto em um contexto global através de window.LoadCheckoutPaymentContext, ele é responsável por efetuar o carregamento de todos Plugins dos partners.
Ele espera como parâmetro um método que conterá todo o código do Plugin que é esperado que seja executado dentro do Checkout React.Esse método recebe 2 argumentos como no exemplo a seguir:
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
// Your plugin implementation
})
O método LoadCheckoutPaymentContext
recebe 2 parâmetros, que são:
-
Checkout - Contém os dados e métodos responsáveis por interagir com os componentes do checkout
-
PaymentMethods - Instâncias pré-definidas de como cada tipo de pagamento deve se comportar Cada um desses parâmetros é responsável por controlar como o checkout e seus componentes irá comportar, eles também permitem ao plugin execução de
Ajax Calls
ou por exemplo utilização de dados do carrinho comoLineItems
. A seguir eles serão mais detalhados.
O parâmetro de Checkout é repsonsável por todo comportamento e interação com o Checkout, e possui os seguintes objetos:
Nome | Descrição |
---|---|
updateFields | Atualiza a exibição dos inputs opcionais do checkout. Lista de fields |
addPaymentOption | Adiciona o método criado ao checkout |
setInstallments | Atualiza o array com as opções de parcelamento. Exemplo |
getData | Obtém os dados do carrinho (endereço, dados do form de pagamento, email, país, etc). Abaixo exibiremos um exemplo completo do objeto |
http | Objeto utilizado para fazer ajax calls |
utils | Objeto com funções auxiliar, as funções auxiliares estão listadas abaixo |
- Throttle
- LoadScript
- FlattenObject
exemplo do objeto data:
{
form: {},
order: {
cart: {
id: 164943094,
hash: '640a1214704c0470410d0f0712ca4fe8efb9e5b1',
number: null,
prices: {
shipping: '0.00',
discount_gateway: 0,
discount_coupon: 1.99,
discount_promotion: 0,
discount_coupon_and_promotions: 1.99,
subtotal_with_promotions_and_coupon_applied: 0,
subtotal: 1.99,
total: 0,
total_usd: 0
},
lineItems: [
{
id: 180289687,
name: 'Barato do dia',
price: '1.99',
quantity: 1,
free_shipping: false,
product_id: 42077389,
variant_id: 108691186,
thumbnail: '//d26lpennugtm8s.cloudfront.net/stores/947/640/products/61193340_2332461190364712_7945763697455005696_n1-2cdc274080e83dfe2f15708278623450-100-0.jpg',
variant_values: '',
sku: null,
properties: [],
url: 'https://prefixnot2.lojavirtualnuvem.com.br/produtos/barato-do-dia/?variant=108691186'
}
],
currency: 'BRL',
currencyFormat: {
'short': 'R$%s',
'long': 'R$%s'
},
lang: 'pt',
langCode: 'pt_BR',
coupon: {
id: 535091,
code: 'NOT100',
type: 'percentage',
value: '100.00',
valid: true,
used: 0,
max_uses: null,
start_date: null,
end_date: null,
min_price: null,
categories: null
},
shipping: {
type: 'ship',
method: 'correios',
option: '04510',
branch: null,
disabled: null,
raw_name: 'Correios - PAC',
suboption: null
},
status: {
order: 'open',
order_cancellation_reason: null,
fulfillment: 'unpacked',
payment: 'pending'
},
completedAt: null,
line_items: [
{
id: 180289687,
name: 'Barato do dia',
price: '1.99',
quantity: 1,
free_shipping: false,
product_id: 42077389,
variant_id: 108691186,
thumbnail: '//d26lpennugtm8s.cloudfront.net/stores/947/640/products/61193340_2332461190364712_7945763697455005696_n1-2cdc274080e83dfe2f15708278623450-100-0.jpg',
variant_values: '',
sku: null,
properties: [],
url: 'https://prefixnot2.lojavirtualnuvem.com.br/produtos/barato-do-dia/?variant=108691186'
}
]
},
shippingAddress: {
zipcode: '31330290',
first_name: 'João',
last_name: 'Cesar',
address: 'Avenida Miguel Perrela',
number: '123',
floor: '',
locality: 'Castelo',
city: 'Belo Horizonte',
state: 'Minas Gerais',
country: 'BR',
phone: '',
between_streets: null,
reference: null
},
billingAddress: {
id_number: '12345678910',
zipcode: '31330000',
first_name: 'João',
last_name: 'Cesar',
address: 'Avenida Miguel Perrela',
number: '123',
floor: '',
locality: 'Castelo',
city: 'Belo Horizonte',
state: 'Minas Gerais',
country: 'BR',
phone: ''
},
contact: {
name: 'João Cesar',
email: 'joaocesar123p1@mailinator.com',
phone: '31999999999',
}
},
country: 'BR',
totalPrice: 21,
storeId: 947640,
callbackUrls: {
success: 'https://acmestore.lojavirtualnuvem.com.br/checkout/v3/success/194667243/a69f9c70eade480302bf9544452f9b92c528624e',
failure: 'https://acmestore.lojavirtualnuvem.com.br/checkout/v3/next/194667243/a69f9c70eade480302bf9544452f9b92c528624e',
cancel: 'https://acmestore.lojavirtualnuvem.com.br/checkout/v3/next/194667243/a69f9c70eade480302bf9544452f9b92c528624e'
},
installments: null
}
Exemplo da utilização do método getData
no script de pagamento:
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
var Credit = PaymentMethods.Transparent.CardPayment({
id: 'credit',
name: 'credit',
onSubmit: function() {
// Obtem todos os dados do objeto de data que vimos acima
var data = Checkout.getData()
// Obtem apenas os dados da chave `form` do objeto de data
var form = Checkout.getData('form')
}
});
});
exemplo:
Checkout.http.post('/checkout/payment/', {
cartId: cartId,
cartHash: cartHash,
endpoint: 'transparent',
method: 'moip'
}).then(function (response) {
// do something with response
});
Cada método tem uma pré-configuração, abaixo temos a listagem de todos tipos de pagamento disponíveis:
Nome | Descrição |
---|---|
CustomPayment | Classe contendo os métodos e configurações para o tipo de pagamento custom |
ModalPayment | Classe contendo os métodos e configurações para o tipo de pagamento modal |
RedirectPayment | Classe contendo os métodos e configurações para o tipo de pagamento redirect |
Transparent | Classe contendo os métodos e configurações para o tipo de pagamento transparent. O método transparente possi as seguintes subclasses: |
- CardPayment
- DebitPayment
- BankDebitPayment
- BoletoPayment
- TicketPayment
- WireTransferPayment
- PixPayment
- QrCodePayment
A diferença entre as classes dos métodos é o template e os inputs disponíveis em cada um. Lista de inputs
Exemplo utilizando CustomPayment
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
var Custom = PaymentMethods.CustomPayment({
id: 'custom',
name: 'custom'
});
Checkout.addPaymentOption(Custom);
});
Se o método em questão for Transparent
a instância deve ser invocada utilizando uma das subclasses. Ex:
var Credit = PaymentMethods.Transparent.CardPayment({
id: 'acme_credit'
});
Parâmetros das instancias dos PaymentMethods
:
No exemplo acima passamos apenas o id, abaixo iremos mostrar a lista completa.
Utilizado para indicar quais inputs opcionais do checkout estarão habilitados. A lista de campos depende do template.
Nome | Descrição | Tipo | Exemplo |
---|---|---|---|
bankList | Lista de bancos | array | [{ name: 'Bank1', code: '23' }...] |
issuerList | Lista de bancos (AR) | array | [{ name: 'Itau', id: '11' }...] |
card_holder_id_types | Lista de tipo de documento | array | [{ name: 'DNI', code: 'DNI' }, { name: 'CPF', code: 'CPF' }, { name: 'CNPJ', code: 'CNPJ' }, { name: 'CI', code: 'CI' }, { name: 'LC', code: 'LC' }, { name: 'LE', code: 'LE' }, { name: 'Otro', code: 'Otro'}] |
card_holder_id_number | Documento | boolean | true or false |
card_holder_birth_date | Data de aniversário | boolean | true or false |
card_holder_phone | Telefone | boolean | true or false |
Nome | Descrição | Tipo | Exemplo |
---|---|---|---|
bank_list | Lista de bancos | array | [{ name: 'Bank1', code: '23' }...] |
debit_card_holder_name | Nome do comprador | boolean | true or false |
debit_card_id_number | Documento | boolean | true or false |
Nome | Descrição | Tipo | Exemplo |
---|---|---|---|
boleto_holder_name | Nome do comprador | boolean | true or false |
boleto_id_number | Documento | boolean | true or false |
efectivo_list | ? | array | [{ name: 'Rapipago', code: 'rapipago' }...] |
Nome | Descrição | Tipo | Exemplo |
---|---|---|---|
holder_name | Nome do comprador | boolean | true or false |
holder_id_number | Documento (CPF) | boolean | true or false |
Nome | Descrição | Tipo | Exemplo |
---|---|---|---|
billing_address | Endereço de faturamento | boolean | true or false |
cardBrands | Lista de bandeiras de cartões | object/array | { credit_card: ['visa', ...]... } |
Lista completa de bandeiras de cartões disponiveis: [ 'amex'', 'argencard', 'aura', 'bapropagos', 'cabal', 'cabaldebit', 'cencosud', 'cobroexpress', 'dinersclub', 'discover', 'elo', 'hiper', 'hipercard', 'iltalcred', 'jcb', 'maestro', 'magna', 'mastercard', 'nativa', 'pagofacil', 'rapipago', 'tarjeta-naranja', 'tarjeta-shopping', 'todopago', 'unionpay', 'visa', 'visadebit' ]
Exemplo informando as bandeiras de cartão:
var Credit = PaymentMethods.Transparent.CardPayment({
id: 'credit',
name: 'credit',
fields: {
cardBrands: {
credit_card: ['visa', 'mastercard', 'elo', 'discover']
}
}
});
As bandeiras de cartões são exibidas como imagens no checkout, ao acessar o meio de pagamento em questão
Exemplo ativando data de aniversário e telefone ao form:
var Credit = PaymentMethods.Transparent.CardPayment({
id: 'credit',
name: 'credit',
fields: {
card_holder_birth_date: true,
card_holder_phone: true
}
});
Não é necessário informar o input como false, basta não informar que ele não será exibido.
Caso deseje atualizar um campo do formulário após a inicialização do script, você pode utilizar o método updateFields
que faz parte do objeto Checkout.
Exemplo:
var Credit = PaymentMethods.Transparent.CardPayment({
id: 'credit',
name: 'credit',
onLoad: function() {
Checkout.updateFields({
method: 'credit', // Este valor é o valor do id inserido
value: { card_holder_birth_date: true }
});
}
});
Utilizado para carregar algum script externo dependente, antes de add o método ao checkout.
Função executada após o método ser adicionado.
Função executada sempre que algum dado do carrinho é alterado
Função executada quando o usuário clica em "Finalizar pedido" e todos os campos obrigatórios do carrinho foram preenchidos corretamente
A função onSubmit
recebe um parâmetro chamado callback
, este parâmetro é uma função que é utilizada para retornar ao checkout as informações sobre o processo de pagamento.
A função callback
pode ser invocada passando um objeto como parâmetro, esse objeto aceita as seguintes chaves:
Nome | Descrição |
---|---|
success | Se esta chave for passada como true, o checkout ira atualizar o pedido com as demais chaves passadas abaixo, se for passado false, o checkout irá exibir uma mensagem de erro ao usuário, a mensagem de erro pode ser definida na chave message
|
message | Mensagem exibida ao usuário quando o pagamento falha, a chave success deve ser passada como false |
close | Fecha o pedido (true or false) |
confirmed | Indica se o pagamento do pedido foi confirmado (true or false) |
recovered | ? |
extraBoletoUrl | url do boleto gerado (string) |
extraAuthorized | ? |
redirect | url de redirecionamento para o gateway de pagamento (string) |
skipRedirect | Não realiza o redirecionamento no checkout, neste caso o redirecionamento deve ser feito diretamente no script |
Exemplo:
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
var Custom = PaymentMethods.CustomPayment({
id: 'custom',
name: 'custom',
scripts: 'https://meuscriptonline.com/payment.js',
onLoad: function() {
// do something after the script loads
// Example: generate a token
},
onDataChange: Checkout.utils.throttle(function () {
// do something when data change
// data changed is already available on `Checkout.getData()`
// Example: update credit card installments when order value change
}, 700),
onSubmit: function (callback) {
// do something when user submit payment
callback({
success: true/false,
...
})
}
});
Checkout.addPaymentOption(Custom);
});
Os dados do formulário do checkout podem ser encontrados no objeto Checkout.getData('form')
, os possíveis dados são:
Nome | Descrição | Opcional | Opção correspondente |
---|---|---|---|
cardNumber | número do cartão | Não | |
cardHolderName | nome do titular do cartão | Não | |
cardExpiration | data de expiração do cartão. ex: 12/20
|
Não | |
cardCvv | código de verificação do cartão | Não | |
cardInstallments | número de parcelas | Não | |
cardHolderIdNumber | documento do comprador | Sim | card_holder_id_number |
cardHolderBirthDate | data de aniversário do comprador | Sim | card_holder_birth_date |
cardHolderPhone | telefone do comprador | Sim | card_holder_phone |
bankId | Instituição bancaria | Sim | bankList |
issuerId | Instituição bancaria (Argentina) | Sim | issuerList |
cardHolderIdType | Tipo do documento | Sim | card_holder_id_types |
Nome | Descrição | Opcional | Opção correspondente |
---|---|---|---|
bank | Instituição bancaria | Sim | bank_list |
holderName | Nome do comprador | Sim | debit_card_holder_name |
holderIdNumber | Documento do comprador | Sim | debit_card_id_number |
Nome | Descrição | Opcional | Opção correspondente |
---|---|---|---|
holderName | Nome do comprador | Sim | boleto_holder_name |
holderIdNumber | Documento do comprador | Sim | boleto_id_number |
brand | Valor do select de efectivo (Somente AR) | Sim | efectivo_list |
As classes CustomPayment, ModalPayment e RedirectPayment não possuem inputs, pois o pagamento é realizado externamente. A diferença entre estes métodos é sua categorização e a exibição no checkout.
Para atualizar as parcelas do cartão de credito no checkout utilizamos o método setInstallments
, exemplo:
O objeto dentro do array de installments deve ter as seguintes chaves:
Nome | Descrição |
---|---|
quantity | número da parcela |
installmentAmount | Valor da parcela |
totalAmount | Valor total |
const installments = [{
quantity: 1,
installmentAmount: 25,
totalAmount: 25
}, {
quantity: 2,
installmentAmount: 13,
totalAmount: 26
}, {
quantity: 3,
installmentAmount: 10,
totalAmount: 30
}]
Checkout.setInstallments(installments)
LoadCheckoutPaymentContext(function(Checkout, PaymentMethods) {
var currentTotalPrice = Checkout.getData('order.cart.prices.total');
var currencCreditCardBin = null;
var getCardNumber = function () {
return Checkout.getData('form.cardNumber') || '';
};
var getCardNumberBin = function () {
return getCardNumber().substring(0, 6);
};
var refreshInstallments = function () {
var creditCardBin = getCardNumberBin();
var hasCreditCardBin = creditCardBin && creditCardBin.length >= 6;
var hasPrice = Boolean(Checkout.getData('totalPrice'));
var changedCreditCardBin = creditCardBin !== currencCreditCardBin;
var changedPrice = Checkout.getData('totalPrice') !== currentTotalPrice;
return (hasCreditCardBin && hasPrice) && (changedCreditCardBin || changedPrice);
};
var getInstallments = function() {
Checkout.http.post('https://app.acmepayments.com/installments', {
amount: Checkout.getData('totalPrice'),
bin: getCardNumberBin()
}).then(function (response) {
Checkout.setInstallments(response);
})
}
// Define an object to encapsulate the integration
var AcmeTransparentCredit = PaymentMethods.Transparent.CardPayment({
id: 'acme_credit',
name: 'ACME Credit Payment',
// This function will be called everytime a data on checkout change
onDataChange: Checkout.utils.throttle(function () {
if (refreshInstallments()) {
getInstallments()
} else if (!getCardNumberBin()) {
// Clear installments if customer remove credit card number
Checkout.setInstallments(null);
}
}, 700),
// This function will be called when the consumer finishes the checkout flow so you can initiate the transaction
onSubmit: function(callback) {
// Let's imagine the app providies this endpoint to proccess credit payments
Checkout.http.post('https://app.acmepayments.com/credit-payment', Checkout.getData('form'))
.then(function(response) {
// Now that we have the ACME Payments checkout, invoke the callback telling it we want to close order
callback({
success: true,
close: true,
confirmed: true
});
})
.catch(function(error){
// Handle a potential error in the http request
callback({
success: false
});
});
}
});
// Register the object in the checkout
Checkout.addPaymentOption(AcmeTransparentCredit);
});
- Http (Já com suporte a promises, controle de CSRF com headers pré configurados)## Otimizações
- Hoje expomos alguns métodos que não deveriam estar disponíveis para nossos integrantes, no futuro deveríamos exibir somente o necessário.
- Mover o método http para dentro do objeto de utils