From c3850b1f18f9f1e4ae57285fa928bff6fa7701da Mon Sep 17 00:00:00 2001 From: ffflabs Date: Tue, 18 Feb 2020 20:45:13 -0300 Subject: [PATCH] adds POC of soap async client and methods, and oneclick nullify --- lib/WebPay.js | 410 ++++++++++++++++++++++++++---------------- lib/WebPayOneClick.js | 337 ++++++++++++++++++++++------------ 2 files changed, 473 insertions(+), 274 deletions(-) diff --git a/lib/WebPay.js b/lib/WebPay.js index 419dd40..801cae9 100644 --- a/lib/WebPay.js +++ b/lib/WebPay.js @@ -13,7 +13,7 @@ // // You should have received a copy of the GNU General Public License //along with this program. If not, see . -"use strict"; +'use strict'; const soap = require('soap'); const select = require('xml-crypto').xpath; @@ -28,27 +28,38 @@ const WebPayOneClickMall = require('./WebPayOneClickMall'); const ENV = { INTEGRACION: { - normal: 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', - nullify: 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', - oneclick: 'https://webpay3gint.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', - oneclickmall: 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSOneClickMulticodeService?wsdl' + normal: + 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', + nullify: + 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', + oneclick: + 'https://webpay3gint.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', + oneclickmall: + 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSOneClickMulticodeService?wsdl' }, CERTIFICACION: { - normal: 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', - nullify: 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', - oneclick: 'https://webpay3gint.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', - oneclickmall: 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSOneClickMulticodeService?wsdl' + normal: + 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', + nullify: + 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', + oneclick: + 'https://webpay3gint.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', + oneclickmall: + 'https://webpay3gint.transbank.cl/WSWebpayTransaction/cxf/WSOneClickMulticodeService?wsdl' }, PRODUCCION: { - normal: 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', - nullify: 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', - oneclick: 'https://webpay3g.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', - oneclickmall: 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSOneClickMulticodeService?wsdl' + normal: + 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSWebpayService?wsdl', + nullify: + 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSCommerceIntegrationService?wsdl', + oneclick: + 'https://webpay3g.transbank.cl/webpayserver/wswebpay/OneClickPaymentService?wsdl', + oneclickmall: + 'https://webpay3g.transbank.cl/WSWebpayTransaction/cxf/WSOneClickMulticodeService?wsdl' } }; class WebPay { - /** * Página de transición según dicta Transbank. * @param urlRedirection obtenido de detailOutput al hacer getTransactionResult @@ -57,7 +68,9 @@ class WebPay { * @returns {string} */ static getHtmlTransitionPage(urlRedirection, token_ws, gifUrl) { - gifUrl = gifUrl || 'data:image/gif;base64,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'; + gifUrl = + gifUrl || + 'data:image/gif;base64,R0lGODlhZABkAMQAAAAAAP////z8/Pj4+PX19fHx8e7u7uvr6+fn5+Pj4+Dg4N3d3dra2tbW1tLS0s/Pz8zMzP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAABEALAAAAABkAGQAAAX/ICSO5LgURwMpAmIcJdko40E8UIPHo1LELNXoQRMhYA3BIUEo8iAJxKiQeK6KCQMjIXCsAgtrTuAs3MSjAQP4qwkG4YdA9YiuxdERo81jCHB/EAcKC153PA0qSUUHCzs8D14rMDGPEA5wBAUzfGg0SUILBmIGVQEPgxClYg4Hc2MJTGhcKRADkmJLKy0EYWgLSrsICgNCJIUiDl2uRQW+fQQJroovliQPCAMJdQMolCUPVCIPtxB1b2gvCQMwDAcIuCMOAUo4WQ+aWd88ziJBaKoQLGDnb0CgGAwIEFgjTd4zaOMI7OOxhEsVNVCGoekngsArKw1+OCBAUEQsKywQ/5AzhiahiQATSyiLZEAbAYAjmOyIdhPlqIUMAoyCsEcMNiWdjJIRsSDbwxUFJOUh6tEJIgMGwhzQdgAGAZYyHTRsdUccGgcFAsQDl61KkiVfRYFLEGCbHFwKrMnoxSLMgpPkeCQooBLKgQdahuBMRkogQbEJVJyM4aAmAwVDAWad5MCXgnVWjSRgYKBLA4OhSww+sBZNyEskKWGzsQMs0QGWcTpTACOLv8gx1tVI+sQAAncfcWKGAFTopckiUAgOZmULEepTrRw4NS4AwAY9oRC34kAsDLJP8KXXmxOFiq1RzqA5YACHHDQPXI7wPouwvcOJWRFOaqwM4I8zTW0jk/99gxUGXxNiEAPBUuYIgAYCo5XmwGkURlgSTnssQBJd7EFxAwLH1YTDNBEm9pYCEFohnAgHjAdOjVXIcQhACBRQxAAlCkLScDTKx4MCARThwBE7UsSdOfwJ2ISIJlWxmAgMtCJFLk8+EKUuCPmT3GL02WdhJUPl8RoEGF5JYws4lVmhYjxIJKZt4LD0IIEQiBNFSHXoZMUJAS7W4Io28XmNnbu0RoIPJbD4RBKRBFAADqUEOdgWHaaTYU+uONqDEPhQ0iQPGJFA2zVOHCGMlWIc5EeQrOVwUzgNWHlqCf9UGNM1kvAWA5hvwlGhIm2i8WSfu5r0Q0K4TojnMTj0mor/jEqoUM41MmWyCaQAOaLKN18JiNEAxVQYpK1nsIDZlkat4w1AuqTUi2sKPYCPjy8cucNAY8ClqHiDnXECrJTlVtBB15hFjhfnGCgjFWbomwWBLAhgpTh1HKfsDqsaFQ2SVkFHQkILGeaQGE+GbAUcNRXCMEBdBmCkYFWckKQeNgqz0mI138wGVSjAC5B05hRgXC4JYFJHXdEhXAkCSC2GdDhLR1pYn54NoJYYJ6Sw72B5nTkpYjR8RipOaH39xDoqje3jfTKVRgMDEpszcBacOkBEAmGQVgmO0Skw0rrkTbzHDX8HnlkJCUVFLBqBDIJMRumW4KOIN7GQOSQ4Il4C/5DMVWxSNtOapATpNKNCwyqBWlNHG/hIDUk0JwhNnoUYykGA37GIjs3O1W3DTHRPgaOQCT3nBK9ZIJ4mwmZuMjax2Pn0i180TD0OSXZFGUVf4DeYHAOhzT6ByYF/aVSCEK1wnM/nFKXwkVxi+JhSOAEYHVwBnBoY5JwxomVpziuEIMAo8KE7EggqJcRI3exEkIT0kUBWM7uQj0TAukookHbcKxWXJOEOeIgsPMkSEASWBcDqZekdJ2ReRHZ1B5fhpHaiEUMSKkOu1D3BFf67nZXwZw4eKIMRDZTBI0qFgCQSpU37wsyv2lOrxaBCflSg36QoZIP5IEwOUxzBW8Zxsf/GIMeHQ5gSAaSwr3UpaAxFsOAlZraIs8FxMeBpj4DSJIWQOIAGD0BjyIIyML/RKDSnYU8TcVBHgOhHBFHiRxX+dKkkAASJOFhS8lSlsfLkjU4UOUMSNtkDEVCIblus1KWo8gvq2ABGpCRBK5AiwBnUQJRBAgYSlACj1BBhBK5KyTp8qI6SDCaWkZPEOZp3x+g4cVzrOA+TKPKGOLyiARgSFZZ6IkLXwIFqLNnEpBTBRXE9QT/dJI+3OHGlRy4AJulYQ4+SY75ksCgJsQjPOcPzzjDSqAr2iiU4KNQUY72sASfokwDWoCOEROOe1cAPQZ0CDoeVI2K/cM9bmIBQ70H/bkJeaMQO2MORXuFhACrZaFw8ijKGfKMzeNACF8oTC8nYrgFY8YVawpe/Z3jEh5uqGGRs+oT9adEKlSMExI4gNLQsICVsspToBMUcWbwMB5o4w2yceJQaAc11qqgCZBCSrAp+J6eC4IpXpqUMNm1DAL8bK0Daps0rCIJCHNkivFJoBb4IwC+A+SRCpKcKgSbOCi84zNi0p8OF5tAoYeANTFcAmvO5hyqBwgMK6goEGNTBALlynwywhNa3LFJKhBCWbyhrG1FsAQz8CyIJjHPGK0WBBSjQ5zXIMJKnaixg8foBdmTbgwCxQHR5dNaVEJOYkYBEAKsYwxoaeTsDwee0/ygBwwhSZpRHrrB6ECjEvZ67VyslshJ0kMgCEiQ6YkiiXCgx0CnNZkWSCFC6jy3i+V6BDwOi91EtYOyRXMTLGIGOCqIbAuFM+8w7maODR0oKyTxBvCUdIH21y12C8ZHAPsJJQLD6B3FJkKoejOlkDsZJdqCHptPlICqfCFJeGAWFEwPLHzEBVwwYZVI8wIunkswIoCwJtnrwGDhvy5YtWlOibrKgrp+4n0dl8Id5rNK7MSjmYRToXvzIqyuXJBWjLKhLYUSwEq2CgTCPqgduSgQVoE1PW3pgEMT1CozpWAJBSugoVxhLDshqmhjcCc/GDGQf9TRBtT5yrX1GxJ+XWP+njgEihyIUNJavGcmHgLyXdpEha9XhZ6G1A1BeGPZQKu2oT5jDgKAMhcXtKRgODkbpiRp0CBaFGBcEW4JSkOYmQ4WC7eRhnktceBxPaFmDsaGNgHGUiG1OWUOSgelbbcJKW9XLoQyDGDmucKQ2W5dxDv0c4CTaZ2x2aLReIdcSYIg0pkGNbmSjtBFnOjbjYGqQusrMNKRLDm7Mm1fD5R65lW3VzRlFu1mRFm3WYbpKYIIAtwNugPBtpo0jypSTUWz0gNfha9xSx7wtiPrMiXIrUurpjrptaXRbQKFzUypacRiQkNbke2pdKmAXvBi8W0McUlSGTWe1z8CEMOnhLV//SCepotLgeFw7KZEs/rxhT2qzK7A3dK00cBvOtiv6yh6kKd4dSoOv3+Bo9bb0WvZ/HsmzWQjtfUtupvnYLxQbr84A4NtYhpqtRLcVQG7xo6dE4cHTw0i3OWKOx9IqwcB7bK5uh8ZJQbqNz1ICHNERsSXw+DYMO3STeA1riyZ5XQ9FSnBGpmD1Cq1hM5IFvZvwMQChBysmk5MHFxvsYiw1bzBcU23enVVFQyl57cjeIhIhOwa8x6ABh2gCCyiRHR7Qtuk3/DKkoVAbCmGYLmlrwZlHJ3gV4A0V2sAuIsID/LMobAV1RomQdkBIkaFoKZgHggGmj4qc9W7Q+hRJQjRh/zlhdWW2KprkYxTUKU+gBuewDpy1AqZUBKj0NjmTFk7AadOjZzDwSuMlI3tFPHtxB/pRGdQxKMHwIpBHEU0DJHSxMbaDTnZyTI70ERjSBUAAXV6wQVhCTBx4CdPkGmjDWskHOaIGaZWBESnRI9gwbA/oNCDiZtt3RRtjOMtma7FUOxOWKwoiTupjBrDmaEwxak+wOcvjOakTNokQcSslIxdIPNiENIOGLqwwDliYHu2HQ7MgU10QbOcmCC34NFWwBaQnD6HWbKkGbYvCT/2WVMiQbSAxhGoDXmhwC+Tmh62nh4rIA6ewc2KVaFRYOIcDEgbAg1eyUJomG/pGQfaERXvDRC94ZVhm2DlvkDqn8VQfohxm0GrOsXDSoUYLlC8RAkhiF1wR0XpDQD0NJXPG1iz4UIrHaA40lmVgdzoCxEAyhFp59Yc/9HJSwogz9HbmEHfLxT3hlXcTRFV8hRPytj1DlBmANwyC10U6tETzI0FDklb5FCQ4ZYoQEAIAOw=='; return ` @@ -84,7 +97,6 @@ class WebPay { * @param {number} props.ivaFactor el factor a multiplicar la comisión para determinar el iva. Por defecto es 0.19 */ constructor(props) { - this.commerceCode = props.commerceCode; this.publicKey = props.publicKey; this.privateKey = props.privateKey; @@ -99,39 +111,53 @@ class WebPay { this.privateKey, this.publicKey, 'utf8', - true); + true + ); this.oneclick = new WebPayOneClick(this); this.oneclickmall = new WebPayOneClickMall(this); } - _getClient(type) { - if(type !== 'normal' && type !== 'nullify' && type !== 'oneclick' && type !== 'oneclickmall') { - throw new Error('WebPay::_getClient invalid type parameter. Must be "normal", "nullify", "oneclick" or "oneclickmall"'); + /** + * Gets the soap client for a namespace + * + * @param {string} type The type: one of [normal, nullify, oneclick,oneclickmall] + * @param {Object} [options={}] client options, (see {@link https://github.com/vpulim/node-soap#options Node Soap}) + * @return {Promise} The client {see {@link https://github.com/vpulim/node-soap#client}. + */ + _getClient(type, options = {}) { + if (!['normal', 'nullify', 'oneclick', 'oneclickmall'].includes(type)) { + return Promise.reject( + new Error( + 'WebPay::_getClient invalid type parameter. Must be "normal", "nullify", "oneclick" or "oneclickmall"' + ) + ); } const transactionClientKey = '_transactionClient_' + type; - if(!this[transactionClientKey]) { - return new Promise((resolve, reject) => { - let options = { - ignoredNamespaces: { - namespaces: [], - override: true - }, - endpoint:this.env[type].replace('?wsdl','') - }; - soap.createClient(this.env[type], options, (err, client) => { - if(err) { - return reject(err); - } - this._wsSecurity.promise().then(() => { - client.setSecurity(this._wsSecurity); - this[transactionClientKey] = client; - resolve(this[transactionClientKey]); - }); - }); - }); + if (this[transactionClientKey]) { + return Promise.resolve(this[transactionClientKey]); } - return Promise.resolve(this[transactionClientKey]); + options = { + ignoredNamespaces: { + namespaces: [], + override: true + }, + endpoint: this.env[type].replace('?wsdl', ''), + ...options + }; + return soap + .createClientAsync(this.env[type], options) + .then(client => { + this[transactionClientKey] = client; + return this._wsSecurity.promise(); + }) + .then(() => { + this[transactionClientKey].setSecurity(this._wsSecurity); + return this[transactionClientKey]; + }) + .catch(err => { + return Promise.reject(err); + }); } /** @@ -149,7 +175,7 @@ class WebPay { */ initTransaction(props) { this.verbose && console.log('initTransaction:parameters', props); - if(!props) { + if (!props) { return Promise.reject(new Error('props param missing')); } let wsInitTransactionInput = { @@ -166,25 +192,32 @@ class WebPay { }; return new Promise((resolve, reject) => { - this._getClient('normal').then((client) => { - client.WSWebpayServiceImplService.WSWebpayServiceImplPort.initTransaction({ - wsInitTransactionInput: wsInitTransactionInput - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('initTransaction:error!', err); - return reject(err); - } - this.verbose && console.log('initTransaction:result:', result); - if(this._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('initTransaction: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this._getClient('normal') + .then(client => { + client.WSWebpayServiceImplService.WSWebpayServiceImplPort.initTransaction( + { + wsInitTransactionInput: wsInitTransactionInput + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && console.log('initTransaction:error!', err); + return reject(err); + } + this.verbose && console.log('initTransaction:result:', result); + if (this._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "initTransaction: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); - } /** @@ -235,29 +268,38 @@ class WebPay { * - buyOrder Orden de compra de la tienda. */ getTransactionResult(token) { - if(!token) { + if (!token) { return Promise.reject(new Error('token missing')); } this.verbose && console.log('getTransactionResult:token:', token); return new Promise((resolve, reject) => { - this._getClient('normal').then((client) => { - client.WSWebpayServiceImplService.WSWebpayServiceImplPort.getTransactionResult({ - tokenInput: token - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('getTransactionResult:error!', err); - return reject(err); - } - this.verbose && console.log('getTransactionResult:result:', result); - if(this._verifySignature(raw)) { - result.return.detailOutput = result.return.detailOutput[0]; - resolve(result.return); - } else { - this.verbose && console.log('getTransactionResult: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this._getClient('normal') + .then(client => { + client.WSWebpayServiceImplService.WSWebpayServiceImplPort.getTransactionResult( + { + tokenInput: token + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && console.log('getTransactionResult:error!', err); + return reject(err); + } + this.verbose && + console.log('getTransactionResult:result:', result); + if (this._verifySignature(raw)) { + result.return.detailOutput = result.return.detailOutput[0]; + resolve(result.return); + } else { + this.verbose && + console.log( + "getTransactionResult: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } @@ -269,23 +311,33 @@ class WebPay { acknowledgeTransaction(token) { return new Promise((resolve, reject) => { this.verbose && console.log('acknowledgeTransaction:token:', token); - this._getClient('normal').then((client) => { - client.WSWebpayServiceImplService.WSWebpayServiceImplPort.acknowledgeTransaction({ - tokenInput: token - }, (err, result, raw, soapHeader) => { - if (err) { - this.verbose && console.log('acknowledgeTransaction:error!', err); - return reject(err); - } - this.verbose && console.log('acknowledgeTransaction:result:', result); - if (this._verifySignature(raw)) { - resolve(result); - } else { - this.verbose && console.log('acknowledgeTransaction: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this._getClient('normal') + .then(client => { + client.WSWebpayServiceImplService.WSWebpayServiceImplPort.acknowledgeTransaction( + { + tokenInput: token + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && + console.log('acknowledgeTransaction:error!', err); + return reject(err); + } + this.verbose && + console.log('acknowledgeTransaction:result:', result); + if (this._verifySignature(raw)) { + resolve(result); + } else { + this.verbose && + console.log( + "acknowledgeTransaction: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } @@ -315,7 +367,7 @@ class WebPay { * - nullifiedAmount */ nullify(props) { - if(!props) { + if (!props) { return Promise.reject(new Error('props param missing')); } @@ -324,23 +376,31 @@ class WebPay { this.verbose && console.log('nullify:parameters', props); return new Promise((resolve, reject) => { - this._getClient('nullify').then((client) => { - client.WSCommerceIntegrationServiceImplService.WSCommerceIntegrationServiceImplPort.nullify({ - nullificationInput : props - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('nullify:error!', err); - return reject(err); - } - this.verbose && console.log('nullify:result:', result); - if(this._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('nullify: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this._getClient('nullify') + .then(client => { + client.WSCommerceIntegrationServiceImplService.WSCommerceIntegrationServiceImplPort.nullify( + { + nullificationInput: props + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && console.log('nullify:error!', err); + return reject(err); + } + this.verbose && console.log('nullify:result:', result); + if (this._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "nullify: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } @@ -365,10 +425,9 @@ class WebPay { * - authorizationDate * - captureAmount */ - - - capture(props) { - if(!props) { + + capture(props) { + if (!props) { return Promise.reject(new Error('props param missing')); } @@ -377,28 +436,34 @@ class WebPay { this.verbose && console.log('capture:parameters', props); return new Promise((resolve, reject) => { - this._getClient('nullify').then((client) => { - client.WSCommerceIntegrationServiceImplService.WSCommerceIntegrationServiceImplPort.capture({ - captureInput : props - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('capture:error!', err); - return reject(err); - } - this.verbose && console.log('capture:result:', result); - if(this._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('capture: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this._getClient('nullify') + .then(client => { + client.WSCommerceIntegrationServiceImplService.WSCommerceIntegrationServiceImplPort.capture( + { + captureInput: props + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && console.log('capture:error!', err); + return reject(err); + } + this.verbose && console.log('capture:result:', result); + if (this._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "capture: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } - - - + /** * @param transaction * @param {number} transaction.amount el monto cobrado en la transaccion @@ -410,17 +475,25 @@ class WebPay { * @return {{clp: number, iva: number, total: number}} */ calcFees(transaction, noIvaLess180Clp) { - const amount = new Decimal(transaction.amount); - const feePerc = transaction.tbkTypeCode.toUpperCase() === 'VD' ? this.debitFeePerc : this.creditFeePerc; + const feePerc = + transaction.tbkTypeCode.toUpperCase() === 'VD' + ? this.debitFeePerc + : this.creditFeePerc; // el 2.95 por ciento.. es decir, amount * (2.95/100) - let feeWebpay = amount.mul(feePerc).div(100).toDecimalPlaces(0); + let feeWebpay = amount + .mul(feePerc) + .div(100) + .toDecimalPlaces(0); let iva = 0; - if((noIvaLess180Clp && feeWebpay.gte(180)) || !noIvaLess180Clp) { - iva = feeWebpay.mul(this.ivaFactor).toDecimalPlaces(0).toNumber(); + if ((noIvaLess180Clp && feeWebpay.gte(180)) || !noIvaLess180Clp) { + iva = feeWebpay + .mul(this.ivaFactor) + .toDecimalPlaces(0) + .toNumber(); } const total = feeWebpay.plus(iva); @@ -430,35 +503,55 @@ class WebPay { iva: iva, total: total.toNumber() }; - } _verifySignature(xml) { - console.log('----------------', xml, '-------------------') + console.log('----------------', xml, '-------------------'); try { let doc = new DOMParser().parseFromString(xml); - let signature = select(doc, "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0]; + let signature = select( + doc, + "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']" + )[0]; let sig = new SignedXml(); //Hack to check non-standard transbank SignedInfo node - sig.validateSignatureValue = function () { + sig.validateSignatureValue = function() { let signedInfo = select(doc, "//*[local-name(.)='SignedInfo']"); - if (signedInfo.length === 0) throw new Error("could not find SignedInfo element in the message"); - let signedInfoCanon = this.getCanonXml([this.canonicalizationAlgorithm], signedInfo[0]); - signedInfoCanon = signedInfoCanon.toString().replace("xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"", "xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""); + if (signedInfo.length === 0) + throw new Error('could not find SignedInfo element in the message'); + let signedInfoCanon = this.getCanonXml( + [this.canonicalizationAlgorithm], + signedInfo[0] + ); + signedInfoCanon = signedInfoCanon + .toString() + .replace( + 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#"', + 'xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"' + ); let signer = this.findSignatureAlgorithm(this.signatureAlgorithm); - let res = signer.verifySignature(signedInfoCanon, this.signingKey, this.signatureValue); - if (!res) this.validationErrors.push("invalid signature: the signature value " + this.signatureValue + " is incorrect"); - return res + let res = signer.verifySignature( + signedInfoCanon, + this.signingKey, + this.signatureValue + ); + if (!res) + this.validationErrors.push( + 'invalid signature: the signature value ' + + this.signatureValue + + ' is incorrect' + ); + return res; }; let webpayKey = this.webpayKey; sig.keyInfoProvider = { - getKeyInfo: function (key, prefix) { + getKeyInfo: function(key, prefix) { prefix = prefix || ''; prefix = prefix ? prefix + ':' : prefix; - return "<" + prefix + "X509Data>"; + return '<' + prefix + 'X509Data>'; }, - getKey: function (keyInfo) { - return webpayKey + getKey: function(keyInfo) { + return webpayKey; } }; sig.loadSignature(signature); @@ -468,11 +561,10 @@ class WebPay { } return res; } catch (err) { - console.log('SIGNATURE:::', err) + console.log('SIGNATURE:::', err); return false; } } - } WebPay.ENV = ENV; diff --git a/lib/WebPayOneClick.js b/lib/WebPayOneClick.js index aa6c58f..13fe512 100644 --- a/lib/WebPayOneClick.js +++ b/lib/WebPayOneClick.js @@ -27,12 +27,13 @@ const AUTHORIZE_RESULT_CODE = { '-7': 'Ha alcanzado el límite de transacciones diarias.', '-8': 'La transacción ha sido rechazada, el rubro es inválido.', '-97': 'Ha alcanzado el máximo monto diario de pagos.', - '-98': 'La transacción ha sido rechazada porque ha excedido el máximo monto de pago.', - '-99': 'La transacción ha sido rechazada porque ha excedido la máxima cantidad de pagos diarias.' + '-98': + 'La transacción ha sido rechazada porque ha excedido el máximo monto de pago.', + '-99': + 'La transacción ha sido rechazada porque ha excedido la máxima cantidad de pagos diarias.' }; class WebPayOneClick { - /** * * @param {WebPay} webpay @@ -60,33 +61,43 @@ class WebPayOneClick { */ initInscription(props) { this.verbose && console.log('oneclick.initInscription:parameters', props); - if(!props) { + if (!props) { return Promise.reject(new Error('props param missing')); } return new Promise((resolve, reject) => { - this.webpay._getClient('oneclick').then((client) => { - - client.initInscription({ - arg0: { - username: props.username, - email: props.email, - responseURL: props.responseUrl - } - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('oneclick.initInscription:error!', err); - return reject(err); - } - this.verbose && console.log('oneclick.initInscription:result:', result); - if(this.webpay._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('oneclick.initInscription: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } + this.webpay + ._getClient('oneclick') + .then(client => { + client.initInscription( + { + arg0: { + username: props.username, + email: props.email, + responseURL: props.responseUrl + } + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && + console.log('oneclick.initInscription:error!', err); + return reject(err); + } + this.verbose && + console.log('oneclick.initInscription:result:', result); + if (this.webpay._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "oneclick.initInscription: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); }) - }).catch(reject); + .catch(reject); }); } @@ -110,31 +121,41 @@ class WebPayOneClick { */ finishInscription(token) { this.verbose && console.log('oneclick.finishInscription:parameters', token); - if(!token) { + if (!token) { return Promise.reject(new Error('props param missing')); } return new Promise((resolve, reject) => { - this.webpay._getClient('oneclick').then((client) => { - - client.finishInscription({ - arg0: { - token: token - } - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('oneclick.finishInscription:error!', err); - return reject(err); - } - this.verbose && console.log('oneclick.finishInscription:result:', result); - if(this.webpay._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('oneclick.finishInscription: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } + this.webpay + ._getClient('oneclick') + .then(client => { + client.finishInscription( + { + arg0: { + token: token + } + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && + console.log('oneclick.finishInscription:error!', err); + return reject(err); + } + this.verbose && + console.log('oneclick.finishInscription:result:', result); + if (this.webpay._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "oneclick.finishInscription: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); }) - }).catch(reject); + .catch(reject); }); } @@ -152,32 +173,41 @@ class WebPayOneClick { */ removeUser(props) { this.verbose && console.log('oneclick.removeUser:parameters', props); - if(!props) { + if (!props) { return Promise.reject(new Error('props param missing')); } return new Promise((resolve, reject) => { - this.webpay._getClient('oneclick').then((client) => { - - client.removeUser({ - arg0: { - tbkUser: props.tbkUser, - username: props.username - } - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('oneclick.removeUser:error!', err); - return reject(err); - } - this.verbose && console.log('oneclick.removeUser:result:', result); - if(this.webpay._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('oneclick.removeUser: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this.webpay + ._getClient('oneclick') + .then(client => { + client.removeUser( + { + arg0: { + tbkUser: props.tbkUser, + username: props.username + } + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && console.log('oneclick.removeUser:error!', err); + return reject(err); + } + this.verbose && + console.log('oneclick.removeUser:result:', result); + if (this.webpay._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "oneclick.removeUser: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } @@ -218,35 +248,44 @@ class WebPayOneClick { */ authorize(props) { this.verbose && console.log('oneclick.authorize:parameters', props); - if(!props) { + if (!props) { return Promise.reject(new Error('props param missing')); } return new Promise((resolve, reject) => { - this.webpay._getClient('oneclick').then((client) => { - - client.authorize({ - arg0: { - amount: props.amount, - tbkUser: props.tbkUser, - username: props.username, - buyOrder: props.buyOrder - } - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('oneclick.authorize:error!', err); - return reject(err); - } - this.verbose && console.log('oneclick.authorize:result:', result); - if(this.webpay._verifySignature(raw)) { - result.return.responseCodeLocaleSpanish = AUTHORIZE_RESULT_CODE[result.return.responseCode]; - resolve(result.return); - } else { - this.verbose && console.log('oneclick.authorize: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this.webpay + ._getClient('oneclick') + .then(client => { + client.authorize( + { + arg0: { + amount: props.amount, + tbkUser: props.tbkUser, + username: props.username, + buyOrder: props.buyOrder + } + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && console.log('oneclick.authorize:error!', err); + return reject(err); + } + this.verbose && console.log('oneclick.authorize:result:', result); + if (this.webpay._verifySignature(raw)) { + result.return.responseCodeLocaleSpanish = + AUTHORIZE_RESULT_CODE[result.return.responseCode]; + resolve(result.return); + } else { + this.verbose && + console.log( + "oneclick.authorize: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } @@ -268,35 +307,103 @@ class WebPayOneClick { * reversa: true si se hizo, false si no se hizo */ codeReverseOneClick(buyOrder) { - this.verbose && console.log('oneclick.codeReverseOneClick:parameters', buyOrder); - if(!buyOrder) { + this.verbose && + console.log('oneclick.codeReverseOneClick:parameters', buyOrder); + if (!buyOrder) { return Promise.reject(new Error('props param missing')); } return new Promise((resolve, reject) => { - this.webpay._getClient('oneclick').then((client) => { - - client.codeReverseOneClick({ - arg0: { - buyorder: buyOrder - } - }, (err, result, raw, soapHeader) => { - if(err) { - this.verbose && console.log('oneclick.codeReverseOneClick:error!', err); - return reject(err); - } - this.verbose && console.log('oneclick.codeReverseOneClick:result:', result); - if(this.webpay._verifySignature(raw)) { - resolve(result.return); - } else { - this.verbose && console.log('oneclick.codeReverseOneClick: result doesn\'t have a valid signature!'); - reject(new Error('Invalid signature response')); - } - }); - }).catch(reject); + this.webpay + ._getClient('oneclick') + .then(client => { + client.codeReverseOneClick( + { + arg0: { + buyorder: buyOrder + } + }, + (err, result, raw, soapHeader) => { + if (err) { + this.verbose && + console.log('oneclick.codeReverseOneClick:error!', err); + return reject(err); + } + this.verbose && + console.log('oneclick.codeReverseOneClick:result:', result); + if (this.webpay._verifySignature(raw)) { + resolve(result.return); + } else { + this.verbose && + console.log( + "oneclick.codeReverseOneClick: result doesn't have a valid signature!" + ); + reject(new Error('Invalid signature response')); + } + } + ); + }) + .catch(reject); }); } + /** + * {@link https://www.transbankdevelopers.cl/referencia/webpay#anular-un-pago-webpay-oneclick } + * + * Para anular un cargo hecho en distinto día contable, se puede utilizar el método nullify de Webpay normal + * + * @param {Object} props The arguments that will be passed to the underlying soap request + * @param {string} props.authorizationCode Código de autorización de la transacción que se requiere anular. Para el caso + * que se esté anulando una transacción de captura en línea, este código + * corresponde al código de autorización de la captura. (Máx 6 carácteres) + * @param {number} props.authorizedAmount Monto autorizado de la transacción que se requiere anular. Para el caso que + * se esté anulando una transacción de captura en línea, este monto corresponde + * al monto de la captura. + * @param {string} props.buyOrder Orden de compra de la transacción que se requiere anular + * @param {string?} props.commerceId ódigo de comercio o tienda mall que realizó la transacción. Si se ignora se + * usará el codigo de comercio según se indicó en el constructor (transacción + * normal). + * @param {number} props.nullifyAmount Monto que se desea anular de la transacción + * @param {Object} options clientOptions Options for the soapClient. Defaults to an empty object + * @return {Promise} A promise that resolves to an object with keys + * - Token + * - authorizationCode + * - authorizationDate + * - Balance + * - nullifiedAmount + * + * If the request fails or the signature is invalid, the promise will resolve to an error + */ + nullify(props, options = {}) { + if (!props) { + return Promise.reject(new Error('props param missing')); + } + + props.commerceId = props.commerceId || this.webpay.commerceCode; + + this.verbose && console.log('nullify:parameters', props); + + return this.webpay + ._getClient('nullify', options) + .then(client => { + return client.nullifyAsync({ + nullificationInput: props + }); + }) + .then(([soapResult, rawResponse, soapHeader, rawRequest]) => { + this.verbose && console.log('nullify:result:', soapResult); + if (this.webpay._verifySignature(rawResponse)) { + return Promise.resolve(soapResult.return); + } else { + this.verbose && + console.log("nullify: result doesn't have a valid signature!"); + return Promise.reject(new Error('Invalid signature response')); + } + }) + .catch(err => { + return Promise.reject(err); + }); + } } -module.exports = WebPayOneClick; \ No newline at end of file +module.exports = WebPayOneClick;