
# Payment Lib

## Required Implementations

- 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)

## LoadCheckoutPaymentContext

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:  
```js  
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 como `LineItems`.  A seguir eles serão mais detalhados.

# Checkout [argument]
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](#fields)                                                      |
| addPaymentOption       | Adiciona o método criado ao checkout                                                                                           |
| closeAlert           | Fecha o alerta de erro no Checkout, caso este esteja aberto.                                                              |
| setInstallments | Atualiza o array com as opções de parcelamento. [Exemplo](#parcelas)                                                                  |
| changePaymentBenefit | Altera o texto de benefício (desconto/parcelamento) exibido na opção de pagamento registrada por este script. [Exemplo](#changepaymentbenefit) |
| 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

## getData

exemplo do objeto data:

```js
{
  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:

```js
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')
    }
  });
});
```

## http
exemplo:

```js
Checkout.http.post('/checkout/payment/', {
  cartId: cartId,
  cartHash: cartHash,
  endpoint: 'transparent',
  method: 'moip'
}).then(function (response) {
  // do something with response
});
```

# PaymentMethods [argument]  

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
  - WalletPayment

A diferença entre as classes dos métodos é o template e os inputs disponíveis em cada um. [Lista de inputs](#checkout-form-data)

Exemplo utilizando `CustomPayment`

```js
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: 

```js
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.

## fields
Utilizado para indicar quais inputs opcionais do checkout estarão habilitados. A lista de campos depende do template.

### CardPayment:
|          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                      |


### DebitPayment:
|          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                      |

### BoletoPayment:
|        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' }...] |

### PixPayment:
|        Nome        |     Descrição     |  Tipo   |                   Exemplo                   |
| ------------------ | ----------------- | ------- | ------------------------------------------- |
| holder_name        | Nome do comprador | boolean | true or false                               |
| holder_id_number   | Documento  (CPF)  | boolean | true or false                               |

### Geral
|        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:

```js
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:

```js
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:

```js
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 }
    });
  }
});
```

## scripts  
Utilizado para carregar algum script externo dependente, antes de add o método ao checkout.

## onLoad
Função executada após o método ser adicionado.

## onDataChange
Função executada sempre que algum dado do carrinho é alterado

## onSubmit
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:

```js
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);
});
```

## Checkout form data
Os dados do formulário do checkout podem ser encontrados no objeto `Checkout.getData('form')`, os possíveis dados são:

### CardPayment:

|        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   |

### DebitPayment:
|      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   |

### BoletoPayment:
|      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.

## Parcelas
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       |

```js
const installments = [{
	quantity: 1,
	installmentAmount: 25,
	totalAmount: 25
}, {
	quantity: 2,
	installmentAmount: 13,
	totalAmount: 26
}, {
	quantity: 3,
	installmentAmount: 10,
	totalAmount: 30
}]

Checkout.setInstallments(installments)
```

![image](https://user-images.githubusercontent.com/9080850/70733355-eb116e80-1ce8-11ea-8885-c8bc68cbb4f4.png)

### Credit Card Payment Without Leaving the Checkout
```js
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);

});
```

## changePaymentBenefit

Altera dinamicamente o texto de benefício (desconto, parcelamento, "sem juros", etc.) exibido
abaixo do título da opção de pagamento, para um gateway adicionado por este script via
`Checkout.addPaymentOption`.

Equivale, dentro do contexto do PaymentLib, ao `window.SDKCheckout.changePaymentBenefit` que
o lojista usa do lado do tema. Os dois caminhos convergem para o mesmo estado
(`partners.customBenefits`), então o último a chamar vence.

### Contrato

```js
Checkout.changePaymentBenefit({
  id: 'acme_credit',        // string: id usado em PaymentMethods.X({ id })
  value: '12x sem juros'    // string: texto exibido como benefício
});
```

- `id` **deve** ser o mesmo `id` passado a um `PaymentMethods.X({ id })` já registrado via
  `Checkout.addPaymentOption` neste script. Ids não registrados são ignorados e logados.
- `id` e `value` precisam ser strings. Payloads inválidos são ignorados e logados.
- Chamadas repetidas para o mesmo `id` sobrescrevem o valor anterior.
- Deve ser chamado **depois** de `addPaymentOption` — tipicamente em `onLoad` ou
  `onDataChange`.

### Uso mínimo

```js
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
  var Credit = PaymentMethods.Transparent.CardPayment({
    id: 'acme_credit',
    name: 'ACME Credit',
    onLoad: function () {
      Checkout.changePaymentBenefit({
        id: 'acme_credit',
        value: '12x sem juros'
      });
    }
  });

  Checkout.addPaymentOption(Credit);
});
```

### Atualização dinâmica com `onDataChange`

```js
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
  var Credit = PaymentMethods.Transparent.CardPayment({
    id: 'acme_credit',
    name: 'ACME Credit',
    onDataChange: Checkout.utils.throttle(function () {
      var total = Checkout.getData('totalPrice');
      var label = total >= 200 ? '12x sem juros' : '3x sem juros';

      Checkout.changePaymentBenefit({
        id: 'acme_credit',
        value: label
      });
    }, 700)
  });

  Checkout.addPaymentOption(Credit);
});
```

### Múltiplos gateways do mesmo parceiro

```js
LoadCheckoutPaymentContext(function (Checkout, PaymentMethods) {
  var Credit = PaymentMethods.Transparent.CardPayment({ id: 'acme_credit' });
  var Pix    = PaymentMethods.Transparent.PixPayment({ id: 'acme_pix' });

  Checkout.addPaymentOption(Credit);
  Checkout.addPaymentOption(Pix);

  Checkout.changePaymentBenefit({ id: 'acme_credit', value: '10% OFF em 1x' });
  Checkout.changePaymentBenefit({ id: 'acme_pix',    value: '15% OFF no Pix' });
});
```

## Utils  

- 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

