From 0e71f91fa1ea8df0111d034069dcb92e27c5f0a3 Mon Sep 17 00:00:00 2001 From: Nikunj Ladava Date: Thu, 10 May 2018 06:36:43 +0000 Subject: [PATCH] [ADD] payment_payulatam: Add new payment acquirer for Latin America TaskID 1826303 closes odoo/odoo#24802 --- addons/payment/data/payment_acquirer_data.xml | 22 +++ addons/payment/data/payment_icon_data.xml | 5 + .../static/img/codensa_easy_credit.png | Bin 0 -> 2947 bytes addons/payment_payulatam/__init__.py | 6 + addons/payment_payulatam/__manifest__.py | 16 ++ .../payment_payulatam/controllers/__init__.py | 4 + addons/payment_payulatam/controllers/main.py | 22 +++ .../data/payment_acquirer_data.xml | 17 ++ addons/payment_payulatam/models/__init__.py | 4 + addons/payment_payulatam/models/payment.py | 144 +++++++++++++++++ .../static/src/img/payulatam_icon.png | Bin 0 -> 47464 bytes addons/payment_payulatam/tests/__init__.py | 4 + .../payment_payulatam/tests/test_payulatam.py | 148 ++++++++++++++++++ .../views/payment_payulatam_templates.xml | 20 +++ .../payment_payulatam/views/payment_views.xml | 17 ++ 15 files changed, 429 insertions(+) create mode 100644 addons/payment/static/img/codensa_easy_credit.png create mode 100644 addons/payment_payulatam/__init__.py create mode 100644 addons/payment_payulatam/__manifest__.py create mode 100644 addons/payment_payulatam/controllers/__init__.py create mode 100644 addons/payment_payulatam/controllers/main.py create mode 100644 addons/payment_payulatam/data/payment_acquirer_data.xml create mode 100644 addons/payment_payulatam/models/__init__.py create mode 100644 addons/payment_payulatam/models/payment.py create mode 100644 addons/payment_payulatam/static/src/img/payulatam_icon.png create mode 100644 addons/payment_payulatam/tests/__init__.py create mode 100644 addons/payment_payulatam/tests/test_payulatam.py create mode 100644 addons/payment_payulatam/views/payment_payulatam_templates.xml create mode 100644 addons/payment_payulatam/views/payment_views.xml diff --git a/addons/payment/data/payment_acquirer_data.xml b/addons/payment/data/payment_acquirer_data.xml index 8c8ea1b84a5..27d27ea4258 100644 --- a/addons/payment/data/payment_acquirer_data.xml +++ b/addons/payment/data/payment_acquirer_data.xml @@ -243,4 +243,26 @@ ref("payment.payment_icon_cc_visa")])]'/> + + PayUlatam + + + + +

+ PayU is a leading financial services provider in Colombia, Argentina, Brazil, Chile, Mexico, Panama, and Peru. It allows merchant to accept local payments with just one account and integration. +

+
    +
  • Online Payment
  • +
  • Payment Status Tracking
  • +
+
+ + +
+ diff --git a/addons/payment/data/payment_icon_data.xml b/addons/payment/data/payment_icon_data.xml index 139066edad0..ded11d7dee9 100644 --- a/addons/payment/data/payment_icon_data.xml +++ b/addons/payment/data/payment_icon_data.xml @@ -49,4 +49,9 @@ Bancontact + + + Codensa Easy Credit + + \ No newline at end of file diff --git a/addons/payment/static/img/codensa_easy_credit.png b/addons/payment/static/img/codensa_easy_credit.png new file mode 100644 index 0000000000000000000000000000000000000000..7f5d48750b404beb5e3c0316c21f2b1390b02644 GIT binary patch literal 2947 zcmd5;XH=6*8jc_x>9B%=3P=D&u7E+{qvHZnB1I4}azP;?2$u_l55ypXV5EsOX&=HR z<|0jsST04X^eDYo!zVo?1f&Eu?2o%Y_Ut)#_t(ykdEc3NX689(-gn-IaK+m62(J_` z0)aSUZf0VOK(Ik9zm=Pv)#Ijw-B?C4;L^1KJ7150AlF~r5r(&Y-P})_-*d&f+q%2n z4)$wv2UsBD6-)a|Oh%pDiIa_u-8Dq^hkhI;0H>4n(WXM4_)uX9aqflALr~1&(Kr-TzenhHn>xUTa6!e&T2|0yx6I$%r!8$YSVgB)$j+iyUp)2cm4`~eb7kU zbYCw2t=5eGp>X6WsytQxFckSI=~I#rC<2PGp^c`@r_8wl9)Rc1<-^c&_v&w|&?MEH zUT3}D?0*;yHi$yhNF*@L^H#ot4Xk8DlTFdsr?*1wXSwhq(E z&;}}K1yqd(3WHy&d{O=&E|cUXfhsD>eoj_~oO1#}k7RMkqS4dNZgk>(U^MKyX3rgG z{Mm2J?|R{GS!h!r2ECf@Kp*4xq90ES7Uq3`}(;1Rn;YV|#ZObfo z9`xpQF*wWhMzr=#ny zuKrS!n>!FibE#;ozh>xI9pV@*TM$##sc!ET&|`c~YR$d>2@iys_0;&i{%ZV1UcPLS z#;f%Hxpe-1ai|2v@!DfY{91^%D~OAO^KD7KN0SuGjYQD}jSGWw^Qf8hnjUDi_hTdd z8TgUnq2Wd95Y@h0!-xg=u(*5B43U={dKvF?G%b2~lxwGQg$l?+KMzB zLvJki!CHf$1RRGXGL&vQRC8@xv4OZ)_~rJ*Tjx`SiiM);WFmoNcY7fXzRsmgE(m$2 z`)qNx^2b0YYCBmJ&}r^1@gAkieoq|`yVt&FIX>*(UroZyNxlZ;nD~b}XXA!;XJUSe z#C{G={d_W08A|Mv&jd%B38nPT;{x_jyyrQ6>5$;&uFiRxVjbWQ8(kN8zLp&wP=Cz2L(`bYD(LwxunUO&WSNAg+mSPXhE_yb^W!6 zCg1fGI#iWTa?EnPHPQP9>~`4D3U0@Q(ntC@5AG(w)#ZUX4wi&k+@RvKrx+Ee_FV)i zG_8-oPptA>6d)VVNO~)iQUQA6*2?{rEs?nl3nTtQqvfXw-|z4xZeCC3XF;5jOL{Vd zNR`f3m;#?nP=aqMVgz8&JRQ;aE?jAMH1;!i`4K>Ptee>1X}PG2X$&FP+m0LACy;LH zEk8xyajaTCQgytZ{t|50L3t$IrceU3214SY3XICCLs4pu_OOBwF{_}EQt?9@?LOFw zyN=gWN%5L|&r#sY;utZbG`Tde$=hKyZ#n8Ewlv|TG3j>=+C1*1I~7X;&jih1?CE>% z+}X@Y3BQhDC0fyt%Gnl5L`~4$?%fOk(>RCHu}wQmK}1K{YWcjUa6?=z6%AOSCn2^nkrm9x2qq34YkGE#{GQ^Qu!NN?=7x!{Y1BfQm(Ihw;vAz^kjF;q&Tk0{D_ zt8qKUlaVI@;v%pb0fn5$YJ1luEoNtgEslUA?Q6LV?K&e@bp^j{-76nEW=8T zJ>m-N$c)q`V@7Pmmh0_qzVtS=s|iuCbIui>sdhSeif>B1FVrVXhRrsd&EB0ymTcAM zl>R+z7pqsM(YY6V2P`P9cBfrwsT6#^%=uLhw-&$!;?iI*a!j216TS2J-KeCgnn^JT z^R2Cd@}K`u{1IpoAGV*g!@K}YZ}|a(0}F1eNxsF$zy|s(81LYV7rj^144Iu-5yGScly=65m zTsB5Q_m{Khj_xllrmdWIe2fH+&7DO_RvaTr6syP+uvsx8WSd_{ly&oI)o&aIh?cqe6`3sk!G2^(IeO9i5<9`yw;hqeqw<5R@sF`VvGcC$PVZI z{E8-4%=pkvS73f6cVN5K@r;?4kEojmG*c@LyZH$VS|ZQl6B1O_ASLq@EGw=)x{q({ zxETbxW?zEM7fTMHW6^M+kK!VBqr&=*9OR%aztBv?Wmm4yh|@gecMj;p(aN@o-$Ecp zNKIhno1%`{O6+AuB=u6foBqJ=91ny@}x)h~K?Mj2oMc(w@Ix z5>m4q@T%RvOoYTJsy6TmKG!1vn^mq*EMf|wMp202U(*gx-S@m8?b%Di4%!f~m9^&a z*`~^5XB$+K?6z@TfPT(KG!j^x?5~cGHstfmd5}F}?$Q)y(p1{hmbY%bEz3+CzmtIe z17oH+XiA&DR4#-5u)guy3v5WDwEp!X{NEJp{}(Jg_-!jx3Z8Cyq2tF7QFm`cXi^Xo znc(O+x!>1b=jfP#MCuF1CeST|m zZCVVXhU)I`ZaEV=zN-V%!?sY{r@g&WQC6-5iRfyv%xJsax3y^=Rw$oApT80EA>v?4 zT`5mLXNrehMY9aatNW)T*0sx21sf`g0eweB)=6%;)JVA2=l~@Fk4B@PuvC?A<~ + + + + payulatam + + + test + +

You will be redirected to the PayUlatam website after clicking on the payment button.

+
+ dummy + dummy + dummy +
+
+
diff --git a/addons/payment_payulatam/models/__init__.py b/addons/payment_payulatam/models/__init__.py new file mode 100644 index 00000000000..2ec5b9cd2f6 --- /dev/null +++ b/addons/payment_payulatam/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import payment diff --git a/addons/payment_payulatam/models/payment.py b/addons/payment_payulatam/models/payment.py new file mode 100644 index 00000000000..8389f6eb42e --- /dev/null +++ b/addons/payment_payulatam/models/payment.py @@ -0,0 +1,144 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import logging +import uuid + +from hashlib import md5 +from werkzeug import urls + +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.tools.float_utils import float_compare + + +_logger = logging.getLogger(__name__) + + +class PaymentAcquirerPayulatam(models.Model): + _inherit = 'payment.acquirer' + + provider = fields.Selection(selection_add=[('payulatam', 'PayUlatam')]) + payulatam_merchant_id = fields.Char(string="PayUlatam Merchant ID", required_if_provider='payulatam', groups='base.group_user') + payulatam_account_id = fields.Char(string="PayUlatam Account ID", required_if_provider='payulatam', groups='base.group_user') + payulatam_api_key = fields.Char(string="PayUlatam API Key", required_if_provider='payulatam', groups='base.group_user') + + def _get_payulatam_urls(self, environment): + """ PayUlatam URLs""" + if environment == 'prod': + return 'https://checkout.payulatam.com/ppp-web-gateway-payu/' + return 'https://sandbox.checkout.payulatam.com/ppp-web-gateway-payu/' + + def _payulatam_generate_sign(self, inout, values): + if inout not in ('in', 'out'): + raise Exception("Type must be 'in' or 'out'") + + if inout == 'in': + data_string = ('~').join((self.payulatam_api_key, self.payulatam_merchant_id, values['referenceCode'], + str(values['amount']), values['currency'])) + else: + data_string = ('~').join((self.payulatam_api_key, self.payulatam_merchant_id, values['referenceCode'], + str(float(values.get('TX_VALUE'))), values['currency'], values.get('transactionState'))) + return md5(data_string.encode('utf-8')).hexdigest() + + @api.multi + def payulatam_form_generate_values(self, values): + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + tx = self.env['payment.transaction'].search([('reference', '=', values.get('reference'))]) + # payulatam will not allow any payment twise even if payment was failed last time. + # so, replace reference code if payment is not done or pending. + if tx.state not in ['done', 'pending']: + tx.acquirer_reference = str(uuid.uuid4()) + payulatam_values = dict( + values, + merchantId=self.payulatam_merchant_id, + accountId=self.payulatam_account_id, + description=values.get('reference'), + referenceCode=tx.acquirer_reference, + amount=values['amount'], + tax='0', # This is the transaction VAT. If VAT zero is sent the system, 19% will be applied automatically. It can contain two decimals. Eg 19000.00. In the where you do not charge VAT, it should should be set as 0. + taxReturnBase='0', + currency=values['currency'].name, + buyerEmail=values['partner_email'], + responseUrl=urls.url_join(base_url, '/payment/payulatam/response'), + ) + payulatam_values['signature'] = self._payulatam_generate_sign("in", payulatam_values) + return payulatam_values + + @api.multi + def payulatam_get_form_action_url(self): + self.ensure_one() + return self._get_payulatam_urls(self.environment) + + +class PaymentTransactionPayulatam(models.Model): + _inherit = 'payment.transaction' + + @api.model + def _payulatam_form_get_tx_from_data(self, data): + """ Given a data dict coming from payulatam, verify it and find the related + transaction record. """ + reference, txnid, sign = data.get('referenceCode'), data.get('transactionId'), data.get('signature') + if not reference or not txnid or not sign: + raise ValidationError(_('PayUlatam: received data with missing reference (%s) or transaction id (%s) or sign (%s)') % (reference, txnid, sign)) + + transaction = self.search([('acquirer_reference', '=', reference)]) + + if not transaction: + error_msg = (_('PayUlatam: received data for reference %s; no order found') % (reference)) + raise ValidationError(error_msg) + elif len(transaction) > 1: + error_msg = (_('PayUlatam: received data for reference %s; multiple orders found') % (reference)) + raise ValidationError(error_msg) + + # verify shasign + sign_check = transaction.acquirer_id._payulatam_generate_sign('out', data) + if sign_check.upper() != sign.upper(): + raise ValidationError(('PayUlatam: invalid sign, received %s, computed %s, for data %s') % (sign, sign_check, data)) + return transaction + + @api.multi + def _payulatam_form_get_invalid_parameters(self, data): + invalid_parameters = [] + + if self.acquirer_reference and data.get('referenceCode') != self.acquirer_reference: + invalid_parameters.append(('Reference code', data.get('referenceCode'), self.acquirer_reference)) + if float_compare(float(data.get('TX_VALUE', '0.0')), self.amount, 2) != 0: + invalid_parameters.append(('Amount', data.get('TX_VALUE'), '%.2f' % self.amount)) + if data.get('merchantId') != self.acquirer_id.payulatam_merchant_id: + invalid_parameters.append(('Merchant Id', data.get('merchantId'), self.acquirer_id.payulatam_merchant_id)) + return invalid_parameters + + @api.multi + def _payulatam_form_validate(self, data): + self.ensure_one() + + status = data.get('lapTransactionState') or data.find('transactionResponse').find('state').text + res = { + 'acquirer_reference': data.get('transactionId') or data.find('transactionResponse').find('transactionId').text, + 'state_message': data.get('message') or "" + } + + if status == 'APPROVED': + _logger.info('Validated PayUlatam payment for tx %s: set as done' % (self.reference)) + res.update(state='done', date=fields.Datetime.now()) + self._set_transaction_done() + self.write(res) + self.execute_callback() + return True + elif status == 'PENDING': + _logger.info('Received notification for PayUlatam payment %s: set as pending' % (self.reference)) + res.update(state='pending') + self._set_transaction_pending() + return self.write(res) + elif status in ['EXPIRED', 'DECLINED']: + _logger.info('Received notification for PayUlatam payment %s: set as Cancel' % (self.reference)) + res.update(state='cancel') + self._set_transaction_cancel() + return self.write(res) + else: + error = 'Received unrecognized status for PayUlatam payment %s: %s, set as error' % (self.reference, status) + _logger.info(error) + res.update(state='cancel', state_message=error) + self._set_transaction_cancel() + return self.write(res) diff --git a/addons/payment_payulatam/static/src/img/payulatam_icon.png b/addons/payment_payulatam/static/src/img/payulatam_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaf42f9decd98154525e5c0b0cf6db250321bff GIT binary patch literal 47464 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 literal 0 HcmV?d00001 diff --git a/addons/payment_payulatam/tests/__init__.py b/addons/payment_payulatam/tests/__init__.py new file mode 100644 index 00000000000..09671a17b96 --- /dev/null +++ b/addons/payment_payulatam/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_payulatam diff --git a/addons/payment_payulatam/tests/test_payulatam.py b/addons/payment_payulatam/tests/test_payulatam.py new file mode 100644 index 00000000000..2bec371b81a --- /dev/null +++ b/addons/payment_payulatam/tests/test_payulatam.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +from lxml import objectify +from werkzeug import urls + +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.tests import tagged + + +class PayUlatamCommon(PaymentAcquirerCommon): + + def setUp(self): + super(PayUlatamCommon, self).setUp() + self.payulatam = self.env.ref('payment.payment_acquirer_payulatam') + + +@tagged('post_install', '-at_install', 'external', '-standard') +class PayUlatamForm(PayUlatamCommon): + + def test_10_payulatam_form_render(self): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') + self.assertEqual(self.payulatam.environment, 'test', 'test without test environment') + self.payulatam.write({ + 'payulatam_merchant_id': 'dummy', + 'payulatam_account_id': 'dummy', + 'payulatam_api_key': 'dummy', + }) + + # ---------------------------------------- + # Test: button direct rendering + # ---------------------------------------- + self.env['payment.transaction'].create({ + 'reference': 'test_ref0', + 'amount': 0.001, + 'currency_id': self.currency_euro.id, + 'acquirer_id': self.payulatam.id, + 'partner_id': self.buyer_id + }) + + # render the button + res = self.payulatam.render( + 'test_ref0', 0.01, self.currency_euro.id, + values=self.buyer_values) + + form_values = { + 'merchantId': 'dummy', + 'accountId': 'dummy', + 'description': 'test_ref0', + 'referenceCode': 'test', + 'amount': '0.01', + 'currency': 'EUR', + 'tax': '0', + 'taxReturnBase': '0', + 'buyerEmail': 'norbert.buyer@example.com', + 'responseUrl': urls.url_join(base_url, '/payment/payulatam/response'), + 'extra1': None + } + # check form result + tree = objectify.fromstring(res) + + data_set = tree.xpath("//input[@name='data_set']") + self.assertEqual(len(data_set), 1, 'payulatam: Found %d "data_set" input instead of 1' % len(data_set)) + self.assertEqual(data_set[0].get('data-action-url'), 'https://sandbox.checkout.payulatam.com/ppp-web-gateway-payu/', 'payulatam: wrong form POST url') + for form_input in tree.input: + if form_input.get('name') in ['submit', 'data_set', 'signature', 'referenceCode']: + continue + self.assertEqual( + form_input.get('value'), + form_values[form_input.get('name')], + 'payulatam: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')]) + ) + + def test_20_payulatam_form_management(self): + self.assertEqual(self.payulatam.environment, 'test', 'test without test environment') + + # typical data posted by payulatam after client has successfully paid + payulatam_post_data = { + 'installmentsNumber': '1', + 'lapPaymentMethod': 'VISA', + 'description': 'test_ref0', + 'currency': 'EUR', + 'extra2': '', + 'lng': 'es', + 'transactionState': '7', + 'polPaymentMethod': '211', + 'pseCycle': '', + 'pseBank': '', + 'referenceCode': 'test_ref_10', + 'reference_pol': '844164756', + 'signature': '88f11d693d3551419f86850948d731ba', + 'pseReference3': '', + 'buyerEmail': 'admin@yourcompany.example.com', + 'lapResponseCode': 'PENDING_TRANSACTION_CONFIRMATION', + 'pseReference2': '', + 'cus': '', + 'orderLanguage': 'es', + 'TX_VALUE': '0.01', + 'risk': '', + 'trazabilityCode': '', + 'extra3': '', + 'pseReference1': '', + 'polTransactionState': '14', + 'polResponseCode': '25', + 'merchant_name': 'Test PayU Test comercio', + 'merchant_url': 'http://pruebaslapv.xtrweb.com', + 'extra1': '/shop/payment/validate', + 'message': 'PENDING', + 'lapPaymentMethodType': 'CARD', + 'polPaymentMethodType': '7', + 'telephone': '7512354', + 'merchantId': 'dummy', + 'transactionId': 'b232989a-4aa8-42d1-bace-153236eee791', + 'authorizationCode': '', + 'lapTransactionState': 'PENDING', + 'TX_TAX': '.00', + 'merchant_address': 'Av 123 Calle 12' + } + + # create tx + tx = self.env['payment.transaction'].create({ + 'amount': 0.01, + 'acquirer_id': self.payulatam.id, + 'currency_id': self.currency_euro.id, + 'reference': 'test_ref_2', + 'partner_name': 'Norbert Buyer', + 'partner_country_id': self.country_france.id, + 'acquirer_reference': 'test_ref_10', + 'partner_id': self.buyer_id}) + + # validate transaction + tx.form_feedback(payulatam_post_data, 'payulatam') + # check + self.assertEqual(tx.state, 'pending', 'Payulatam: wrong state after receiving a valid pending notification') + self.assertEqual(tx.state_message, 'PENDING', 'Payulatam: wrong state message after receiving a valid pending notification') + self.assertEqual(tx.acquirer_reference, 'b232989a-4aa8-42d1-bace-153236eee791', 'PayUlatam: wrong txn_id after receiving a valid pending notification') + + # update transaction + tx.write({ + 'state': 'draft', + 'acquirer_reference': False}) + + # update notification from payulatam + payulatam_post_data['lapTransactionState'] = 'APPROVED' + # validate transaction + tx.form_feedback(payulatam_post_data, 'payulatam') + # check transaction + self.assertEqual(tx.state, 'done', 'payulatam: wrong state after receiving a valid pending notification') + self.assertEqual(tx.acquirer_reference, 'b232989a-4aa8-42d1-bace-153236eee791', 'payulatam: wrong txn_id after receiving a valid pending notification') diff --git a/addons/payment_payulatam/views/payment_payulatam_templates.xml b/addons/payment_payulatam/views/payment_payulatam_templates.xml new file mode 100644 index 00000000000..793b1e0e38d --- /dev/null +++ b/addons/payment_payulatam/views/payment_payulatam_templates.xml @@ -0,0 +1,20 @@ + + + + diff --git a/addons/payment_payulatam/views/payment_views.xml b/addons/payment_payulatam/views/payment_views.xml new file mode 100644 index 00000000000..b4092fb98a0 --- /dev/null +++ b/addons/payment_payulatam/views/payment_views.xml @@ -0,0 +1,17 @@ + + + + payment.acquirer.form.inherit.payment.payulatam + payment.acquirer + + + + + + + + + + + +