pagarme-bifrost-js
Version:
PagarMe Bifrost WebSocket JS Class. An easy implementation of PagarMe Bifrost WebSocket Service.
1 lines • 33 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","sources":["../src/helpers.js","../src/webSocket.js","../src/index.js"],"sourcesContent":["const NAME = '%c Pagar.Me Bifrost ';\nconst BACKGROUND = 'background:#f26722 ; padding: 2px; border-radius: 2px; color: #fff ';\n\nexport function required(name, param) {\n if (param === undefined) {\n throw new Error(`Parâmetro obrigatório ${name} não declarado.`);\n }\n\n return param;\n}\n\nexport function logInfo(msg) {\n console.log(NAME, BACKGROUND, msg); // eslint-disable-line no-console\n}\n\nexport function logError(msg) {\n console.error(NAME, BACKGROUND, msg); // eslint-disable-line no-console\n}\n\n/**\n * Add spaces to match the max screen length\n * @param {string} text\n * @param {number} maxChar\n * @returns {string}\n */\nexport function addSpaces(text, maxChar) {\n return text\n .split('')\n .concat(...Array(maxChar).fill(' '))\n .slice(0, maxChar)\n .join('');\n}\n\nexport default {\n required,\n logInfo,\n logError,\n addSpaces,\n};\n","/* eslint-disable no-underscore-dangle */\nimport { logInfo, required } from './helpers';\n\nconst privateVariables = {\n request: {\n listDevices: 1,\n initialize: 2,\n process: 4,\n finish: 5,\n displayMessage: 6,\n status: 7,\n closeContext: 8,\n },\n response: {\n unknownCommand: 0,\n devicesListed: 1,\n initialized: 2,\n alreadyInitialized: 3,\n processed: 4,\n finished: 5,\n messageDisplayed: 6,\n status: 7,\n contextClosed: 8,\n error: 9,\n },\n paymentMethods: {\n credit: 1,\n debit: 2,\n },\n errorStrings: {\n errorContextString: 'Device already in use by context ',\n errorInitialize: 'An error has occured with the [Initialize] request. See the log and contact the support.',\n errorOperationErrored: 'Transaction Errored',\n errorOperationFailed: 'Error: 43',\n errorOperationCanceled: 'Transaction Canceled',\n catastroficError: 'Error: 14',\n },\n ws: null,\n timeout: null,\n close: true,\n timeoutConn: null,\n};\n\nfunction _connect(host, payload) {\n if (privateVariables.ws === null) {\n privateVariables.ws = new WebSocket(host);\n } else if (privateVariables.ws.readyState === 2 || privateVariables.ws.readyState === 3) {\n _disconnect();\n privateVariables.ws = new WebSocket(host);\n }\n\n return new Promise((resolve, reject) => {\n try {\n _timeout();\n\n const sendRequest = () => {\n _clearTimeout();\n privateVariables.ws.send(JSON.stringify(payload));\n _timeout(60000);\n }\n\n if (privateVariables.ws.readyState === 0) {\n privateVariables.ws.onopen = () => {\n sendRequest();\n };\n } else if (privateVariables.ws.readyState === 1) {\n sendRequest();\n }\n\n privateVariables.ws.onmessage = (evtMsg) => {\n _clearTimeout();\n resolve(JSON.parse(evtMsg.data));\n };\n\n privateVariables.ws.onerror = (evtError) => {\n _clearTimeout();\n if (evtError) reject(evtError);\n };\n } catch (e) {\n reject(e);\n }\n });\n}\n\nfunction _disconnect() {\n privateVariables.ws.close();\n privateVariables.ws = null;\n}\n\nfunction _clearTimeout() {\n privateVariables.close = false;\n clearTimeout(privateVariables.timeoutConn);\n}\n\nfunction _timeout(time = 10000) {\n privateVariables.close = true;\n privateVariables.timeoutConn = setTimeout(() => {\n if (privateVariables.close) {\n privateVariables.ws.close();\n } else {\n _clearTimeout();\n }\n }, time);\n}\n\nclass BifrostWebSocket {\n constructor({ contextId, baudRate, debug, host }) {\n this.debug = debug || false;\n this.contextId = required('contextId', contextId);\n this.baudRate = baudRate || 115200;\n this._connected = false;\n this.devices = [];\n this._host = host || 'wss://localhost:2000/mpos';\n this._amount = 0;\n this._method = '';\n this.lastRequest = null;\n }\n\n debugLog(message) {\n if (this.debug) {\n logInfo(message);\n }\n }\n\n classError(message) {\n this.debugLog((typeof message === 'object') ? message.text : message);\n throw new Error(message);\n }\n\n get amount() {\n return this._amount; // eslint-disable-line\n }\n\n get connected() {\n return (this._connected);\n }\n\n set amount(value) {\n if (typeof value === 'number' && value <= 0) {\n throw new Error('Não é possível definir um valor menor ou igual a zero.');\n } else {\n this._amount = parseFloat(value) * 100;\n }\n }\n\n get method() {\n return this._method;\n }\n\n set method(value) {\n if (typeof value === 'string') {\n if (Object.keys(privateVariables.paymentMethods)\n .includes(value)) {\n this._method = value;\n }\n } else if (typeof value === 'number') {\n if (privateVariables.paymentMethods.find(p => p === value)) {\n this._method = Object.keys(privateVariables.paymentMethods)\n .find(k => privateVariables.paymentMethods[k] === value);\n }\n } else {\n throw new Error('Método de pagamento não permitido.');\n }\n }\n\n defineRequest(value) {\n if (value === undefined) this.lastRequest = null;\n if (this.lastRequest !== null) {\n this.classError('Não é possível fazer requisições asíncronas, termine uma ação antes de executar a outra.');\n }\n\n if (typeof value === 'number') this.lastRequest = value;\n }\n\n /**\n * Terminate the context of the PinPad device\n * @param {string} contextId = null - Optional ContextId to be terminated\n * @returns {Promise<*>}\n */\n async closePinPadContext(contextId) {\n try {\n\n this.debugLog('Fechando contexto do Serviço Bifrost.');\n this.defineRequest(privateVariables.request.closeContext);\n await _connect(this._host, {\n request_type: privateVariables.request.closeContext,\n context_id: contextId || this.contextId,\n });\n this._connected = false;\n this.defineRequest();\n return Promise.resolve(true);\n } catch (error) {\n this.defineRequest();\n return Promise.reject(error);\n } finally {\n await _disconnect();\n }\n }\n\n /**\n * @typedef {object} PinPadDevice\n * @property {string} id - Device ID\n * @property {number} kind - Device Kind\n * @property {string} manufacturer - Device Manufacturer\n * @property {string} name - Device name\n * @property {string} port - Device Port\n */\n /**\n * Get the connected devices on the serial port (COM)\n * @returns {Promise<Array.<PinPadDevice>>}\n */\n async getPinPadDevices() {\n try {\n this.debugLog('Buscando lista de dispositivos do sistema.');\n this.defineRequest(privateVariables.request.listDevices);\n const responseData = await _connect(this._host, {\n request_type: privateVariables.request.listDevices,\n context_id: this.contextId,\n });\n this.debugLog(responseData);\n this.devices = responseData.device_list;\n this.defineRequest();\n return Promise.resolve(this.devices);\n } catch (error) {\n this.defineRequest();\n return Promise.reject(error);\n }\n }\n\n /**\n * @typedef {object} PinPadInitializerParameters\n * @property{string} encryptionKey\n * @property {number} simpleInitialize = null\n * @property {number} timeoutMilliseconds = null\n */\n /**\n * Start the PinPan hardware\n * @param {PinPadInitializerParameters} params\n * @param {number} deviceIndex = 0 - Index of the device in the devices Array.\n */\n async initialize(params, deviceIndex = 0) {\n try {\n this.debugLog(`Conectando ao PinPad ${this.devices[deviceIndex].id}.`);\n this.defineRequest(privateVariables.request.initialize);\n const response = await _connect(this._host, {\n request_type: privateVariables.request.initialize,\n context_id: this.contextId,\n initialize: {\n device_id: this.devices[deviceIndex].id,\n encryption_key: params.encryptionKey,\n baud_rate: this.baudRate,\n simple_initialize: params.simpleInitialize,\n timeout_milliseconds: params.timeoutMilliseconds,\n },\n });\n if (this.lastRequest === privateVariables.request.initialize) {\n this.defineRequest();\n if (response.response_type === privateVariables.response.initialized) {\n this._connected = true;\n return this.debugLog(`PinPad ${this.devices[deviceIndex].id} inicializado com sucesso.`);\n }\n\n if (response.response_type === privateVariables.response.alreadyInitialized) {\n this.debugLog('Serviço Bifrost já inicializado, reiniciando a conexão.');\n await this.closePinPadContext(response.context_id);\n await this.initialize({\n encryptionKey: params.encryptionKey,\n baud_rate: this.baudRate,\n simpleInitialize: params.simpleInitialize,\n timeoutMilliseconds: params.timeoutMilliseconds,\n }, 0);\n return false;\n }\n\n if (response.response_type === privateVariables.response.error && privateVariables.errorStrings.errorInitialize) {\n const nextDevice = (deviceIndex + 1);\n\n if (nextDevice > this.devices.length) {\n await _disconnect();\n this.classError('Não foi possível inicial a conexão com nenhum dispositivo.');\n } else {\n this.debugLog('Dispositivo selecionado não é válido, inicializando novamente com próximo dispositivo da lista.');\n await this.initialize({\n encryptionKey: params.encryptionKey,\n baud_rate: this.baudRate,\n simpleInitialize: params.simpleInitialize,\n timeoutMilliseconds: params.timeoutMilliseconds,\n }, nextDevice);\n return false;\n }\n }\n\n if (response.error === privateVariables.errorStrings.catastroficError) {\n this.classError('Erro catastrófico no sistema. Por favor, reinicialize o PinPad e o Serviço do Bifrost');\n _disconnect();\n return false;\n }\n\n if (response.error && response.error.includes(privateVariables.errorStrings.errorContextString)) {\n this.debugLog('Serviço Bifrost com contexto diferente do definido na classe.');\n const context = response.error.split(privateVariables.errorStrings.errorContextString)[1];\n if (await this.closePinPadContext(context)) {\n await this.initialize({\n encryptionKey: params.encryptionKey,\n baud_rate: this.baudRate,\n simpleInitialize: params.simpleInitialize,\n timeoutMilliseconds: params.timeoutMilliseconds,\n }, 0);\n }\n\n return false;\n }\n }\n return response;\n } catch (error) {\n return Promise.reject(error);\n } finally {\n this.defineRequest();\n }\n }\n\n /**\n * @typedef {object} BifrostServiceStatus\n * @property {boolean} connected - Is device connected\n * @property {string} contextId - Device Context\n * @property {string} connectedDeviceId - Connected Device Id\n */\n /**\n * Get the Bifrost Service Status\n * @returns {Promise<BifrostServiceStatus>}\n */\n async getPinPanStatus() {\n try {\n this.debugLog('Buscando status do serviço Bifrost.');\n this.defineRequest(privateVariables.request.status);\n const responseData = await _connect(this._host, {\n request_type: privateVariables.request.status,\n context_id: this.contextId,\n });\n logInfo(responseData);\n return Promise.resolve({\n connected: !!responseData.status.code,\n contextId: responseData.context_id,\n connectedDeviceId: responseData.status.connected_device_id,\n });\n } catch (error) {\n return Promise.reject(error);\n } finally {\n this.defineRequest();\n }\n }\n\n /**\n * Display a message on the PinPad Device\n * @param message\n * @returns {Promise<*>}\n */\n async displayMessageOnPinPadScreen(message) {\n try {\n this.debugLog(`Mostrando \"${message}\" no display do PinPad.`);\n this.defineRequest(privateVariables.request.displayMessage);\n const responseData = await _connect(this._host, {\n request_type: privateVariables.request.displayMessage,\n context_id: this.contextId,\n display_message: {\n message,\n },\n });\n return Promise.resolve(responseData);\n } catch (error) {\n return Promise.reject(error);\n } finally {\n this.defineRequest();\n }\n }\n\n /**\n * @typedef {object} PaymentStartObject\n * @property {number} amount\n * @property {string} method = 'credit'|'debit'\n */\n /**\n * Start the payment process by setting the amount and method.\n * @param {PaymentStartObject} params\n */\n startPayment(params) {\n try {\n this.amount = params.amount;\n this.method = params.method || privateVariables.paymentMethods.credit;\n } catch (error) {\n throw new Error(error);\n }\n }\n\n /**\n * @typedef {object} PinPadProcessedCardReturn\n * @property {string} card_hash\n * @property {string} card_holder_name\n * @property {number} error_code\n * @property {boolean} is_online_pin\n * @property {number} payment_method\n * @property {number} status\n */\n /**\n * Send the payment request to the PinPad and start the\n * payment process of it.\n * @returns {Promise<Object.<PinPadProcessedCardReturn>>}\n */\n async startPaymentProcess() {\n try {\n this.debugLog(`Iniciando processo de pagamento. Venda via ${this.method}, valor ${this.amount / 100}`);\n this.defineRequest(privateVariables.request.process);\n\n const response = await _connect(this._host, {\n request_type: privateVariables.request.process,\n context_id: this.contextId,\n process: {\n amount: this.amount,\n magstripe_payment_method: this.method,\n },\n });\n\n if (this.lastRequest === privateVariables.request.process) {\n if (response.error === privateVariables.errorStrings.errorOperationCanceled) {\n const error = {\n text: 'Operação cancelada pelo usuário.',\n type: 'cardCanceled',\n };\n this.debugLog(error.text);\n return Promise.reject(error);\n }\n\n if (\n response.error === privateVariables.errorStrings.errorOperationErrored\n || response.error === privateVariables.errorStrings.errorOperationFailed\n ) {\n const error = {\n text: 'Aconteceu algum erro na operação, tente novamente.',\n type: 'operationError',\n };\n this.debugLog(error.text);\n return Promise.reject(error);\n }\n\n if (response.response_type === privateVariables.response.processed) {\n return Promise.resolve(response.process);\n }\n }\n } catch (error) {\n return Promise.reject(error);\n } finally {\n this.defineRequest();\n }\n }\n\n /**\n * Finish the payment process of the PinPad\n * @param {string} code\n * @param {string} emvData\n * @returns {Promise<*>}\n */\n async finishPaymentProcess(code, emvData) {\n try {\n this.debugLog(`Finalizando a venda via ${this.method}`);\n this.defineRequest(privateVariables.request.finish);\n return await _connect(this._host, {\n request_type: privateVariables.request.finish,\n context_id: this.contextId,\n finish: {\n success: !!(code && emvData),\n response_code: code || '0000',\n emv_data: emvData || '000000000.0000',\n },\n });\n } catch (error) {\n return Promise.reject(error);\n } finally {\n this.defineRequest();\n }\n }\n}\n\nexport default BifrostWebSocket;\n","/* eslint-disable no-underscore-dangle */\nimport { required, logError, addSpaces } from './helpers';\nimport BifrostWebSocket from './webSocket';\n\n/**\n * Show the error on not connected PinPad\n */\nfunction notConnected() {\n throw new Error('PinPad não foi inicializado. Por favor, inicie o PinPad antes de executar outro comando.');\n}\n\n/**\n * @class PagarMeTEF\n * @constructor PagarMeConstructor\n */\nclass PagarMeBifrost {\n /**\n * Class Constructor\n * @param {Object.<PagarMeConstructor>} params\n */\n /**\n * @typedef {Object} PagarMeConstructor\n * @property {boolean} debug\n * @property {string} host\n * @property {string} contextId\n * @property {number} baudRate\n * @property {string} encryptionKey\n * @property {number} pinPadMaxCharLine\n * @property {number} pinPadMaxChar\n * @property {number} pinPanDisplayLines\n */\n constructor(params) {\n try {\n this.baudRate = params.baudRate || 115200;\n this.contextId = required('contextId', params.contextId);\n this.encryptionKey = required('encryptionKey', params.encryptionKey);\n this.pinPadMaxCharLine = params.pinPadMaxCharLine || 16;\n this.pinPadMaxChar = params.pinPadMaxChar || 32;\n this.pinPanDisplayLines = params.pinPanDisplayLines || 2;\n\n const constructorOptions = {\n debug: params.debug || false,\n contextId: this.contextId,\n host: params.host || 'wss://localhost:2000/mpos',\n };\n\n this.__bifrost__ = new BifrostWebSocket(constructorOptions);\n } catch (error) {\n logError(error, true);\n }\n }\n\n get connected() {\n return this.__bifrost__.connected;\n }\n\n /**\n * Initialize the PinPad\n * @returns {Promise<boolean>}\n */\n async initialize() {\n try {\n await this.__bifrost__.getPinPadDevices();\n await this.__bifrost__.initialize({ encryptionKey: this.encryptionKey });\n return Promise.resolve(true);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Terminate the PinPad\n * @returns {Promise<Boolean>}\n */\n async terminate() {\n return new Promise((resolve, reject) => {\n if (this.connected) {\n this.__bifrost__.closePinPadContext()\n .then(() => {\n resolve(true);\n })\n .catch((e) => {\n reject(e);\n });\n } else {\n notConnected();\n }\n });\n }\n\n /**\n * Restart the PinPad\n * @returns {Promise<boolean>}\n */\n async restart() {\n try {\n await this.terminate();\n return this.initialize();\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Get the PinPad Status\n * @returns {Promise<Object.<BifrostServiceStatus>>}\n */\n async status() {\n try {\n if (!this.connected) notConnected();\n return this.__bifrost__.getPinPanStatus();\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Display a message on the PinPad\n * @param {string|array} message - A message string or an array of messages.\n * @returns {Promise<String>}\n */\n async showMessage(message) {\n try {\n if (!this.connected) notConnected();\n const tefMaxCharLine = this.pinPadMaxCharLine;\n const tefMaxChar = this.pinPadMaxChar;\n let formattedMessage = '';\n\n if (Array.isArray(message)) {\n formattedMessage = message\n .slice(0, this.pinPanDisplayLines)\n .map(m => addSpaces(m, tefMaxCharLine))\n .join('');\n }\n\n if (typeof message === 'string') {\n formattedMessage = addSpaces(message, tefMaxChar);\n }\n\n await this.__bifrost__.displayMessageOnPinPadScreen(formattedMessage);\n return Promise.resolve(formattedMessage);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n\n /**\n * Start the payment process\n * @param {number} amount\n * @param {string|number} method = 'credit'|'debit'|1|2\n * @returns {Promise<Object.<PinPadProcessedCardReturn>>}\n */\n async payment(amount, method) {\n try {\n if (!this.connected) notConnected();\n this.__bifrost__.startPayment({ amount, method });\n const processedPayment = await this.__bifrost__.startPaymentProcess();\n\n return Promise.resolve(processedPayment);\n } catch (error) {\n logError(error);\n await this.showMessage(error.text);\n setTimeout(async () => {\n await this.finish();\n await this.terminate();\n setTimeout(async () => {\n await this.initialize();\n }, 2000);\n }, 2000);\n return Promise.reject(error);\n }\n }\n\n /**\n * @typedef {object} PinPadFinishParameters\n * @property {number} timeout - Timeout in MS between the execution of messages\n * @property {string|array} messages - An string or an Array of messages\n * @property {string} code\n * @property {string} emvData\n */\n /**\n * Finish the PinPad payment process.\n * @param {PinPadFinishParameters} params\n * @returns {Promise<*>}\n */\n async finish(params = {}) {\n try {\n if (!this.connected) notConnected();\n const code = params.code || '';\n const emvData = params.emvData || '';\n const timeOut = params.timeout || 2000;\n const messages = params.messages || null;\n const processed = await this.__bifrost__.finishPaymentProcess(code, emvData);\n\n if (Array.isArray(messages)) {\n messages.forEach((message, index) => {\n setTimeout(async () => {\n await this.showMessage(message);\n }, timeOut * (index + 1));\n });\n }\n\n if (typeof messages === 'string') {\n setTimeout(async () => {\n await this.showMessage(messages);\n }, timeOut);\n }\n\n return Promise.resolve(processed);\n } catch (error) {\n return Promise.reject(error);\n }\n }\n}\n\nexport default PagarMeBifrost;\n"],"names":["NAME","BACKGROUND","required","name","param","undefined","Error","logInfo","msg","console","log","logError","error","addSpaces","text","maxChar","split","concat","Array","fill","slice","join","body","then","result","f","args","i","arguments","length","Promise","resolve","apply","this","e","reject","finalizer","bind","value","direct","thrown","recover","privateVariables","request","listDevices","initialize","process","finish","displayMessage","status","closeContext","response","unknownCommand","devicesListed","initialized","alreadyInitialized","processed","finished","messageDisplayed","contextClosed","paymentMethods","credit","debit","errorStrings","errorContextString","errorInitialize","errorOperationErrored","errorOperationFailed","errorOperationCanceled","catastroficError","ws","timeout","close","timeoutConn","_connect","host","payload","WebSocket","readyState","_disconnect","_timeout","sendRequest","_clearTimeout","send","JSON","stringify","onopen","onmessage","evtMsg","parse","data","onerror","evtError","clearTimeout","time","setTimeout","BifrostWebSocket","contextId","baudRate","debug","_connected","devices","_host","_amount","_method","lastRequest","message","debugLog","_typeof","classError","defineRequest","_this","request_type","context_id","_this2","responseData","device_list","params","deviceIndex","_this3","id","device_id","encryption_key","encryptionKey","baud_rate","simple_initialize","simpleInitialize","timeout_milliseconds","timeoutMilliseconds","response_type","closePinPadContext","nextDevice","includes","context","_this4","connected","code","connectedDeviceId","connected_device_id","_this5","display_message","amount","method","_this6","magstripe_payment_method","type","emvData","_this7","success","response_code","emv_data","parseFloat","Object","keys","find","p","k","notConnected","pinPadMaxCharLine","pinPadMaxChar","pinPanDisplayLines","constructorOptions","__bifrost__","getPinPadDevices","catch","terminate","getPinPanStatus","tefMaxCharLine","tefMaxChar","formattedMessage","isArray","map","m","displayMessageOnPinPadScreen","startPayment","startPaymentProcess","processedPayment","showMessage","timeOut","messages","finishPaymentProcess","forEach","index"],"mappings":"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"}