auttarjsclass
Version:
Auttar WebSocket JS Class. An easy implementation of Auttar WebSocket Service.
377 lines (345 loc) • 13.6 kB
JavaScript
/* eslint-disable no-underscore-dangle */
import { required, logError, logInfo } from './helpers';
const privateVariables = {
transactions: {
credit: {
base: 112,
installment: 113,
installmentWithInterest: 114,
},
debit: {
base: 101,
voucher: 106,
},
cancel: 128,
confirm: 6,
requestCancel: 191,
},
return: {
success: 0,
timeOut: 1,
notAuthorizes: 5,
internetError: 10,
intertefError: 12,
error: 20,
ecommerceError: 30,
},
errorCodes: {
5300: 'Valor não informado',
5301: 'Cartão inválido',
5302: 'Cartão vencido',
5303: 'Data de vencimento inválido',
5304: 'Código de segurança inválido',
5305: 'Taxa de serviço excede limite',
5306: 'Operação não permitida',
5307: 'Dados inválidos',
5308: 'Valor mínimo da parcela inválido',
5309: 'Número de parcelas inválido',
5310: 'Número de parcelas excede limite',
5311: 'Valor da entrada maior ou igual ao valor da transação',
5312: 'Valor da parcela inválido',
5313: 'Data inválida',
5314: 'Prazo excede limite',
5316: 'NSU inválido',
5317: 'Operação cancelada pelo usuário',
5318: 'Documento inválido (CPF ou CNPJ)',
5319: 'Valor do documento inválido',
5328: 'Erro na captura de dados do Pin-Pad',
5329: 'Erro na captura do chip ou cartão removido antes da hora.',
5364: 'Data de emissão do cartão inválida',
5355: 'O tipo de financiamento informado não é coerente com o número de parcelas',
},
ws: null,
timeout: null,
close: true,
timeoutConn: null,
};
function _disconnect() {
privateVariables.ws.close();
}
function _clearTimeout() {
privateVariables.close = false;
clearTimeout(privateVariables.timeoutConn);
}
function _timeout(time = 10000) {
privateVariables.close = true;
privateVariables.timeoutConn = setTimeout(() => {
if (privateVariables.close) {
privateVariables.ws.close();
} else {
_clearTimeout();
}
}, time);
}
function _connect(host, payload) {
return new Promise((resolve, reject) => {
if (privateVariables.ws === null) {
privateVariables.ws = new WebSocket(host);
} else if (privateVariables.ws.readyState === 2 || privateVariables.ws.readyState === 3) {
_disconnect();
try {
privateVariables.ws = new WebSocket(host);
} catch (e) {
reject(e);
}
}
_timeout();
privateVariables.ws.onopen = function(evt) {
_clearTimeout();
privateVariables.ws.send(JSON.stringify(payload));
_timeout(60000);
};
privateVariables.ws.onmessage = function(evtMsg) {
_clearTimeout();
resolve(JSON.parse(evtMsg.data));
};
privateVariables.ws.onerror = function(evtError) {
_clearTimeout();
reject(evtError);
};
});
}
/**
* @typedef {Object} AuttarCupomLinha
* @property {string} linha
*/
/** @typedef {Object} AuttarSuccessResponse
* @property {String} bandeira
* @property {String} cartao
* @property {String} codigoAprovacao
* @property {String} codigoErro
* @property {String} codigoRespAutorizadora
* @property {Array} cupomCliente
* @property {Array.<AuttarCupomLinha>} cupomEstabelecimento
* @property {Array.<AuttarCupomLinha>} cupomReduzido
* @property {Array} display
* @property {Number} nsuAutorizadora
* @property {Number} nsuCTF
* @property {Number} operacao
* @property {String} redeAdquirente
* @property {Number} retorno
* @property {String} valorTransacao
*/
/**
* @class Auttar WebSocket
* @constructor {AuttarConstructor}
*/
/**
* @typedef {object} AuttarConstructor
* @property {string} host - WebSocket Host URL
* @property {boolean} debug - Método debug da classe
* @property {string} orderId - Número de identificação da venda
* @property {float} amount - Valor da venda
* @property {AuttarSuccessResponse} ctfTrasaction - Objecto de resposta do websocket
*/
class Auttar {
/**
* Construtor da classe
* @param {AuttarConstructor} props
*/
constructor(props) {
this.__host = props.host || 'ws://localhost:2500';
this.debug = props.debug || false;
this.orderId = props.orderId || '';
this.__amount = 0;
if (props.amount) this.amount = props.amount;
this.__transactionDate = (new Date(Date.now())).toLocaleDateString('pt-BR', {
year: '2-digit',
month: '2-digit',
day: '2-digit',
timeZone: 'America/Sao_Paulo',
}).replace(/\//g, '');
this.ctfTransaction = {};
}
debugLog(message) {
if (this.debug) {
logInfo(message);
}
}
classError(message) {
this.debugLog((typeof message === 'object') ? message.text : message);
return new Error(message);
}
get amount() {
return this.__amount;
}
/**
* Define o valor em para a classe em centavos
* @param value
*/
set amount(value) {
if (typeof value === 'number' && value <= 0) {
throw new Error('Não é possível definir um valor menor ou igual a zero.');
} else {
this.__amount = parseFloat(value) * 100;
}
}
/**
* Pagamento com cartão de crédito, podendo ser declarado com parcelamento e se o juro é da administradora.
* @param {number} installments - número de parcelas
* @param {boolean} withInterest - juros pela administradora
* @returns {Promise<AuttarSuccessResponse>}
*/
credit(installments = 1, withInterest = false) {
return new Promise((resolve, reject) => {
const requisition = {
valorTransacao: this.amount,
documento: this.orderId,
operacao: privateVariables.transactions.credit.base,
dataTransacao: this.__transactionDate,
};
if (installments > 1) {
requisition.operacao = privateVariables.transactions.credit.installment;
requisition.numeroParcelas = installments;
}
if (installments > 1 && withInterest) {
requisition.operacao = privateVariables.transactions.credit.installmentWithInterest;
requisition.numeroParcelas = installments;
}
this.debugLog(`Pagamento com cartão de crédito. Operação: ${requisition.operacao}. Valor ${this.amount} centavos`);
_connect(this.__host, requisition)
.then((response) => {
if (response.retorno > 0) {
const errorMsg = privateVariables.errorCodes[response.codigoErro] ||
(response.display.length) ?
response.display.map(m => m.mensagem).join(' ') :
' ';
const error = this.classError(`Transação não concluída ${response.codigoErro}: ${errorMsg}`);
reject(error);
}
this.ctfTransaction = {
...response,
dataTransacao: this.__transactionDate,
};
this.debugLog(`Resposta do servidor -> ${JSON.stringify(response)}`);
resolve(response);
});
});
}
/**
* Pagamento com cartão de crédito, podendo ser declarado com parcelamento e se o juro é da administradora.
* @param {boolean} isVoucher
* @returns {Promise<AuttarSuccessResponse>}
*/
debit(isVoucher = false) {
return new Promise((resolve, reject) => {
const operacao = isVoucher ?
privateVariables.transactions.debit.voucher :
privateVariables.transactions.debit.base;
this.debugLog(`Pagamento com cartão de débito. Operação: ${operacao}. Valor ${this.amount} centavos`);
_connect(this.__host, {
valorTransacao: this.amount,
documento: this.orderId,
dataTransacao: this.__transactionDate,
operacao,
})
.then((response) => {
if (response.retorno > 0) {
const errorMsg = privateVariables.errorCodes[response.codigoErro] ||
(response.display.length) ?
response.display.map(m => m.mensagem).join(' ') :
' ';
const error = this.classError(`Transação não concluída ${response.codigoErro}: ${errorMsg}`);
reject(error);
}
this.ctfTransaction = {
...response,
dataTransacao: this.__transactionDate,
};
this.debugLog(`Resposta do servidor -> ${JSON.stringify(response)}`);
resolve(response);
});
});
}
/**
* Confirma a operação com o CTF
* @returns {Promise<void>}
*/
confirm() {
return new Promise((resolve, reject) => {
const operacao = privateVariables.transactions.confirm;
this.debugLog(`Confirmação de pagamento da operação realizada.
Operação: ${this.ctfTransaction.operacao}
Data: ${this.ctfTransaction.dataTransacao}
Valor: ${this.amount}
Bandeira: ${this.ctfTransaction.bandeira}
Cartão: ${this.ctfTransaction.cartao}`);
_connect(this.__host, { operacao })
.then((response) => {
if (response.retorno > 0) {
const errorMsg = privateVariables.errorCodes[response.codigoErro] ||
(response.display.length) ?
response.display.map(m => m.mensagem).join(' ') :
' ';
reject(this.classError(`Transação não concluída ${response.codigoErro}: ${errorMsg}`));
}
this.ctfTransaction = Object.assign(this.ctfTransaction, response);
this.debugLog(`Resposta do servidor -> ${JSON.stringify(response)}`);
resolve(response);
});
});
}
/**
* Inicia o processo de cancelamento de compra.
* @returns {Promise<void>}
*/
requestCancellation() {
return new Promise((resolve, reject) => {
const operacao = privateVariables.transactions.requestCancel;
this.debugLog(`Requisição de cancelamento de compra.
Operação: ${this.ctfTransaction.operacao}
Data: ${this.ctfTransaction.dataTransacao}
Valor: ${this.amount}
NSU: ${this.ctfTransaction.nsuCTF}`);
_connect(this.__host, { operacao })
.then((response) => {
if (response.retorno > 0) {
const errorMsg = privateVariables.errorCodes[response.codigoErro] ||
(response.display.length) ?
response.display.map(m => m.mensagem).join(' ') :
' ';
reject(this.classError(`Transação não concluída ${response.codigoErro}: ${errorMsg}`));
}
this.debugLog(`Resposta do servidor -> ${JSON.stringify(response)}`);
resolve(response);
});
});
}
/**
* Realiza o cancelamento da compra.
* @param {string} prop.dataTransacao
* @param {number} prop.amount
* @param {string} prop.nsuCTF
* @param {string} prop.operacao
* @returns {Promise<any>}
*/
cancel(prop = {}) {
return new Promise((resolve, reject) => {
const operacao = privateVariables.transactions.cancel;
const tefOperacao = prop.operacao || this.ctfTransaction.operacao;
const tefDataTransacao = prop.dataTransacao || this.ctfTransaction.dataTransacao;
const tefAmount = prop.amount ? (parseFloat(prop.amount) * 100) : this.ctfTransaction.valorTransacao;
const tefNsuCTF = prop.nsuCTF || this.ctfTransaction.nsuCTF;
this.debugLog(`Cancelamento de compra.
Operação: ${tefOperacao}
Data: ${tefDataTransacao}
Valor: ${tefAmount}
NSU: ${tefNsuCTF}`);
_connect(this.__host, {
operacao,
valorTransacao: tefAmount,
dataTransacao: tefDataTransacao,
nsuCTF: tefNsuCTF,
})
.then((response) => {
if (response.retorno > 0) {
const errorMsg = privateVariables.errorCodes[response.codigoErro] || response.display[0].mensagem;
reject(this.classError(`Transação não concluída ${response.codigoErro}: ${errorMsg}`));
}
this.debugLog(`Resposta do servidor -> ${JSON.stringify(response)}`);
resolve(response);
});
});
}
}
export default Auttar;