From 8fdeafb1531dc72e3000b121b51965cbed833d2f Mon Sep 17 00:00:00 2001 From: dansanti Date: Mon, 12 Jun 2017 08:26:13 -0400 Subject: [PATCH] =?UTF-8?q?[IMP]v=209.0.5.0=20,=20Recepci=C3=B3n=20de=20da?= =?UTF-8?q?tos=20Desde=20Webpay=20-=20Proceso=20Solamente=20estado=20acept?= =?UTF-8?q?ado=20-=20@TODO=20estados=20de=20Rehazo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __openerp__.py | 3 +- controllers/main.py | 81 +++++++++++++++++++++++++++--- models/webpay.py | 94 ++++++++++++++++++++++++++++------- views/payment_transaction.xml | 19 +++++++ views/webpay.xml | 2 +- 5 files changed, 172 insertions(+), 27 deletions(-) create mode 100644 views/payment_transaction.xml diff --git a/__openerp__.py b/__openerp__.py index 86b60cb..a98d93b 100644 --- a/__openerp__.py +++ b/__openerp__.py @@ -6,7 +6,7 @@ 'author': 'Daniel Santibáñez Polanco', 'summary': 'Payment Acquirer: Webpay Implementation', 'website': 'https://odoocoop.cl', - 'version': "9.0.2.0", + 'version': "9.0.5.0", 'description': """Webpay Payment Acquirer""", 'depends': ['payment'], 'python-depends':[ @@ -20,6 +20,7 @@ 'data': [ 'views/webpay.xml', 'views/payment_acquirer.xml', + 'views/payment_transaction.xml', 'data/webpay.xml', ], 'installable': True, diff --git a/controllers/main.py b/controllers/main.py index 6d382e7..48e8fb6 100644 --- a/controllers/main.py +++ b/controllers/main.py @@ -17,18 +17,83 @@ class WebpayController(http.Controller): _exception_url = '/payment/webpay/test/exception' _cancel_url = '/payment/webpay/test/cancel' + def _webpay_form_get_tx_from_data(self, cr, uid, data, context=None): + reference, txn_id = data.get('item_number'), data.get('txn_id') + if not reference or not txn_id: + error_msg = _('Paypal: received data with missing reference (%s) or txn_id (%s)') % (reference, txn_id) + _logger.info(error_msg) + raise ValidationError(error_msg) + + # find tx -> @TDENOTE use txn_id ? + tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) + if not tx_ids or len(tx_ids) > 1: + error_msg = 'Paypal: received data for reference %s' % (reference) + if not tx_ids: + error_msg += '; no order found' + else: + error_msg += '; multiple order found' + _logger.info(error_msg) + raise ValidationError(error_msg) + return self.browse(cr, uid, tx_ids[0], context=context) + + def _webpay_form_validate(self, cr, uid, tx, data, context=None): + status = data.get('payment_status') + res = { + 'acquirer_reference': data.get('txn_id'), + 'paypal_txn_type': data.get('payment_type'), + } + if status in ['Completed', 'Processed']: + _logger.info('Validated Paypal payment for tx %s: set as done' % (tx.reference)) + res.update(state='done', date_validate=data.get('payment_date', fields.datetime.now())) + return tx.write(res) + elif status in ['Pending', 'Expired']: + _logger.info('Received notification for Paypal payment %s: set as pending' % (tx.reference)) + res.update(state='pending', state_message=data.get('pending_reason', '')) + return tx.write(res) + else: + error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (tx.reference, status) + _logger.info(error) + res.update(state='error', state_message=error) + return tx.write(res) + @http.route([ - '/payment/webpay/accept', '/payment/webpay/test/accept', - '/payment/webpay/decline', '/payment/webpay/test/decline', - '/payment/webpay/exception', '/payment/webpay/test/exception', - '/payment/webpay/cancel', '/payment/webpay/test/cancel', - ], type='http', auth='none') - def webpay_form_feedback(self, **post): + '/payment/webpay/return/', + '/payment/webpay/test/return', + ], type='http', auth='public', csrf=False, website=True) + def webpay_form_feedback(self, acquirer_id=None, **post): """ Webpay contacts using GET, at least for accept """ _logger.info('Webpay: entering form_feedback with post data %s', pprint.pformat(post)) # debug cr, uid, context = request.cr, SUPERUSER_ID, request.context - request.registry['payment.transaction'].form_feedback(cr, uid, post, 'webpay', context=context) - return werkzeug.utils.redirect(post.pop('return_url', '/')) + resp = request.registry['payment.transaction'].getTransaction(cr, uid, [], acquirer_id, post['token_ws'], context=context) + _logger.info(resp) + ''' + TSY: Autenticación exitosa + TSN: Autenticación fallida. + TO6: Tiempo máximo excedido para autenticación. + ABO: Autenticación abortada por tarjetahabiente. + U3: Error interno en la autenticación. + Puede ser vacío si la transacción no se autenticó. + ''' + if resp.VCI in ['TSY']: + request.registry['payment.transaction'].form_feedback(cr, uid, resp, 'webpay', context=context) + urequest = urllib2.Request(resp.urlRedirection, werkzeug.url_encode({'token_ws': post['token_ws'], })) + uopen = urllib2.urlopen(urequest) + resp = uopen.read() + values={ + 'webpay_redirect': resp, + } + return request.website.render('payment_webpay.webpay_redirect', values) + + + @http.route([ + '/payment/webpay/final', + '/payment/webpay/test/final', + ], type='http', auth='public', csrf=False, website=True) + def final(self, **post): + """ Webpay contacts using GET, at least for accept """ + _logger.info('Webpay: entering End with post data %s', pprint.pformat(post)) # debug + cr, uid, context = request.cr, SUPERUSER_ID, request.context + return werkzeug.utils.redirect('/shop/payment/validate') @http.route(['/payment/webpay/s2s/create_json'], type='json', auth='public', csrf=False) diff --git a/models/webpay.py b/models/webpay.py index 7c2104b..aea85ee 100644 --- a/models/webpay.py +++ b/models/webpay.py @@ -68,9 +68,9 @@ def _get_webpay_urls(self): @api.multi def webpay_form_generate_values(self, values): + _logger.info(values) base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') values.update({ - 'cmd': '_xclick', 'business': self.company_id.name, 'item_name': '%s: %s' % (self.company_id.name, values['reference']), 'item_number': values['reference'], @@ -84,7 +84,7 @@ def webpay_form_generate_values(self, values): 'zip_code': values.get('partner_zip'), 'first_name': values.get('partner_first_name'), 'last_name': values.get('partner_last_name'), - 'return_url': base_url + "/my/transaction/" + str(self.id) + 'return_url': base_url + '/payment/webpay/final' }) return values @@ -125,8 +125,9 @@ def get_client(self,): Permite inicializar una transaccion en Webpay. Como respuesta a la invocacion se genera un token que representa en forma unica una transaccion. """ - def initTransaction(self, post, buyOrder=1123, sessionId=2): - + def initTransaction(self, post): + _logger.info(post) + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') client = self.get_client() client.options.cache.clear() init = client.factory.create('wsInitTransactionInput') @@ -135,16 +136,16 @@ def initTransaction(self, post, buyOrder=1123, sessionId=2): init.commerceId = self.webpay_commer_code - init.buyOrder = buyOrder - init.sessionId = sessionId - init.returnURL = post['return_url'] - init.finalURL = post['return_url'] + init.buyOrder = post['item_number'] + init.sessionId = self.company_id.id + init.returnURL = base_url + '/payment/webpay/return/'+str(self.id) + init.finalURL = post['return_url'] detail = client.factory.create('wsTransactionDetail') detail.amount = post['amount'] detail.commerceCode = self.webpay_commer_code - detail.buyOrder = buyOrder + detail.buyOrder = post['item_number'] init.transactionDetails.append(detail) init.wPMDetail=client.factory.create('wpmDetailInput') @@ -158,19 +159,29 @@ def initTransaction(self, post, buyOrder=1123, sessionId=2): class PaymentTxWebpay(models.Model): _inherit = 'payment.transaction' + webpay_txn_type = fields.Selection([ + ('VD','Venta Debito'), + ('VN','Venta Normal'), + ('VC','Venta en cuotas'), + ('SI','3 cuotas sin interés'), + ('S2','cuotas sin interés'), + ('NC','N Cuotas sin interés'), + ], + string="Webpay Tipo Transacción") + """ getTransaction Permite obtener el resultado de la transaccion una vez que Webpay ha resuelto su autorizacion financiera. """ - def getTransaction(self, token): - - client = WebpayNormal.get_client(url, config.getPrivateKey(), config.getPublicCert(), config.getWebPayCert()) + @api.multi + def getTransaction(self, acquirer_id, token): + client = acquirer_id.get_client() client.options.cache.clear() transactionResultOutput = client.service.getTransactionResult(token) - acknowledge = WebpayNormal.acknowledgeTransaction(token) + acknowledge = self.acknowledgeTransaction(acquirer_id, token) return transactionResultOutput @@ -179,13 +190,62 @@ def getTransaction(self, token): acknowledgeTransaction Indica a Webpay que se ha recibido conforme el resultado de la transaccion """ - def acknowledgeTransaction(self, token): - client = WebpayNormal.get_client(url, config.getPrivateKey(), config.getPublicCert(), config.getWebPayCert()) + def acknowledgeTransaction(self, acquirer_id, token): + client = acquirer_id.get_client() client.options.cache.clear() - acknowledge = client.service.acknowledgeTransaction(token) - return acknowledge + def _webpay_form_get_tx_from_data(self, cr, uid, data, context=None): + reference, txn_id = data.buyOrder, data.sessionId + if not reference or not txn_id: + error_msg = _('Webpay: received data with missing reference (%s) or txn_id (%s)') % (reference, txn_id) + _logger.info(error_msg) + raise ValidationError(error_msg) + + # find tx -> @TDENOTE use txn_id ? + tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) + if not tx_ids or len(tx_ids) > 1: + error_msg = 'Webpay: received data for reference %s' % (reference) + if not tx_ids: + error_msg += '; no order found' + else: + error_msg += '; multiple order found' + _logger.info(error_msg) + raise ValidationError(error_msg) + return self.browse(cr, uid, tx_ids[0], context=context) + + def _webpay_form_validate(self, cr, uid, tx, data, context=None): + ''' + codes = 0 Transacción aprobada. + -1 Rechazo de transacción. + -2 Transacción debe reintentarse. + -3 Error en transacción. + -4 Rechazo de transacción. + -5 Rechazo por error de tasa. + -6 Excede cupo máximo mensual. + -7 Excede límite diario por transacción. + -8 Rubro no autorizado. + ''' + status = str(data.detailOutput[0].responseCode) + res = { + 'acquirer_reference': data.sessionId, + 'webpay_txn_type': data.detailOutput[0].paymentTypeCode, + } + if status in ['0']: + _logger.info('Validated webpay payment for tx %s: set as done' % (tx.reference)) + + res.update(state='done', date_validate=data.transactionDate) + return tx.write(res) + elif status in ['-6', '-7']: + _logger.info('Received notification for webpay payment %s: set as pending' % (tx.reference)) + res.update(state='pending', state_message=data.get('pending_reason', '')) + return tx.write(res) + else: + error = 'Received unrecognized status for webpay payment %s: %s, set as error' % (tx.reference, status) + _logger.info(error) + res.update(state='error', state_message=error) + return tx.write(res) + class PaymentMethod(models.Model): _inherit = 'payment.method' diff --git a/views/payment_transaction.xml b/views/payment_transaction.xml new file mode 100644 index 0000000..a8e74ef --- /dev/null +++ b/views/payment_transaction.xml @@ -0,0 +1,19 @@ + + + + + transaction.form.webpay + payment.transaction + + + + + + + + + + + + + diff --git a/views/webpay.xml b/views/webpay.xml index 4866e4d..424d95e 100644 --- a/views/webpay.xml +++ b/views/webpay.xml @@ -3,7 +3,7 @@