summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikunj Ladava <nla@odoo.com>2018-05-10 06:36:43 +0000
committerYannick Tivisse <yti@odoo.com>2019-02-11 11:36:14 +0000
commit0e71f91fa1ea8df0111d034069dcb92e27c5f0a3 (patch)
tree46c36f55a861068d79ac46d6860ce822348b8c06
parent890e47ea7f35c63d9ba880457b5ed6f543d4f7a7 (diff)
[ADD] payment_payulatam: Add new payment acquirer for Latin America
TaskID 1826303 closes odoo/odoo#24802
-rw-r--r--addons/payment/data/payment_acquirer_data.xml22
-rw-r--r--addons/payment/data/payment_icon_data.xml5
-rw-r--r--addons/payment/static/img/codensa_easy_credit.pngbin0 -> 2947 bytes
-rw-r--r--addons/payment_payulatam/__init__.py6
-rw-r--r--addons/payment_payulatam/__manifest__.py16
-rw-r--r--addons/payment_payulatam/controllers/__init__.py4
-rw-r--r--addons/payment_payulatam/controllers/main.py22
-rw-r--r--addons/payment_payulatam/data/payment_acquirer_data.xml17
-rw-r--r--addons/payment_payulatam/models/__init__.py4
-rw-r--r--addons/payment_payulatam/models/payment.py144
-rw-r--r--addons/payment_payulatam/static/src/img/payulatam_icon.pngbin0 -> 47464 bytes
-rw-r--r--addons/payment_payulatam/tests/__init__.py4
-rw-r--r--addons/payment_payulatam/tests/test_payulatam.py148
-rw-r--r--addons/payment_payulatam/views/payment_payulatam_templates.xml20
-rw-r--r--addons/payment_payulatam/views/payment_views.xml17
15 files changed, 429 insertions, 0 deletions
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")])]'/>
</record>
+ <record id="payment_acquirer_payulatam" model="payment.acquirer">
+ <field name="name">PayUlatam</field>
+ <field name="image" type="base64" file="payment_payulatam/static/src/img/payulatam_icon.png"/>
+ <field name="view_template_id" ref="default_acquirer_button"/>
+ <field name="module_id" ref="base.module_payment_payulatam"/>
+ <field name="description" type="html">
+ <p>
+ 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.
+ </p>
+ <ul class="list-inline">
+ <li><i class="fa fa-check"/>Online Payment</li>
+ <li><i class="fa fa-check"/>Payment Status Tracking</li>
+ </ul>
+ </field>
+ <!-- https://www.payulatam.com/medios-de-pago/ -->
+ <field name="payment_icon_ids" eval='[(6, 0, [ref("payment.payment_icon_cc_diners_club_intl"),
+ ref("payment.payment_icon_cc_mastercard"),
+ ref("payment.payment_icon_cc_american_express"),
+ ref("payment.payment_icon_cc_visa"),
+ ref("payment.payment_icon_cc_codensa_easy_credit")])]'/>
+ </record>
+
</odoo>
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 @@
<field name="name">Bancontact</field>
<field name="image" type="base64" file="payment/static/img/bancontact.png"/>
</record>
+
+ <record id="payment_icon_cc_codensa_easy_credit" model="payment.icon">
+ <field name="name">Codensa Easy Credit</field>
+ <field name="image" type="base64" file="payment/static/img/codensa_easy_credit.png"/>
+ </record>
</odoo> \ 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 00000000000..7f5d48750b4
--- /dev/null
+++ b/addons/payment/static/img/codensa_easy_credit.png
Binary files differ
diff --git a/addons/payment_payulatam/__init__.py b/addons/payment_payulatam/__init__.py
new file mode 100644
index 00000000000..e52ad6f83e3
--- /dev/null
+++ b/addons/payment_payulatam/__init__.py
@@ -0,0 +1,6 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import controllers
+from . import models
+from odoo.addons.payment.models.payment_acquirer import create_missing_journal_for_acquirers
diff --git a/addons/payment_payulatam/__manifest__.py b/addons/payment_payulatam/__manifest__.py
new file mode 100644
index 00000000000..3cb48a950ea
--- /dev/null
+++ b/addons/payment_payulatam/__manifest__.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'PayuLatam Payment Acquirer',
+ 'category': 'Payment Acquirer',
+ 'summary': 'Payment Acquirer: PayuLatam Implementation',
+ 'description': """Payulatam payment acquirer""",
+ 'depends': ['payment'],
+ 'data': [
+ 'views/payment_views.xml',
+ 'views/payment_payulatam_templates.xml',
+ 'data/payment_acquirer_data.xml',
+ ],
+ 'post_init_hook': 'create_missing_journal_for_acquirers',
+}
diff --git a/addons/payment_payulatam/controllers/__init__.py b/addons/payment_payulatam/controllers/__init__.py
new file mode 100644
index 00000000000..5d4b25db9c0
--- /dev/null
+++ b/addons/payment_payulatam/controllers/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import main
diff --git a/addons/payment_payulatam/controllers/main.py b/addons/payment_payulatam/controllers/main.py
new file mode 100644
index 00000000000..9ada53e5395
--- /dev/null
+++ b/addons/payment_payulatam/controllers/main.py
@@ -0,0 +1,22 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import logging
+import pprint
+import werkzeug
+
+from odoo import http
+from odoo.http import request
+
+_logger = logging.getLogger(__name__)
+
+
+class PayuLatamController(http.Controller):
+
+ @http.route('/payment/payulatam/response', type='http', auth='public', csrf=False)
+ def payulatam_response(self, **post):
+ """ PayUlatam."""
+ _logger.info('PayUlatam: entering form_feedback with post response data %s', pprint.pformat(post))
+ if post:
+ request.env['payment.transaction'].sudo().form_feedback(post, 'payulatam')
+ return werkzeug.utils.redirect('/payment/process')
diff --git a/addons/payment_payulatam/data/payment_acquirer_data.xml b/addons/payment_payulatam/data/payment_acquirer_data.xml
new file mode 100644
index 00000000000..fcb831bd509
--- /dev/null
+++ b/addons/payment_payulatam/data/payment_acquirer_data.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <data noupdate="1">
+ <record id="payment.payment_acquirer_payulatam" model="payment.acquirer">
+ <field name="provider">payulatam</field>
+ <field name="company_id" ref="base.main_company"/>
+ <field name="view_template_id" ref="payulatam_form"/>
+ <field name="environment">test</field>
+ <field name="pre_msg" type="html">
+ <p>You will be redirected to the PayUlatam website after clicking on the payment button.</p>
+ </field>
+ <field name="payulatam_account_id">dummy</field>
+ <field name="payulatam_merchant_id">dummy</field>
+ <field name="payulatam_api_key">dummy</field>
+ </record>
+ </data>
+</odoo>
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 00000000000..dfaf42f9dec
--- /dev/null
+++ b/addons/payment_payulatam/static/src/img/payulatam_icon.png
Binary files differ
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <template id="payulatam_form">
+ <div>
+ <input type="hidden" name="data_set" t-att-data-action-url="tx_url" data-remove-me=""/>
+ <input type="hidden" name="merchantId" t-att-value='merchantId'/>
+ <input type="hidden" name="accountId" t-att-value='accountId'/>
+ <input type="hidden" name="description" t-att-value='description'/>
+ <input type="hidden" name="referenceCode" t-att-value='referenceCode'/>
+ <input type="hidden" name="amount" t-att-value='amount'/>
+ <input type="hidden" name="currency" t-att-value='currency'/>
+ <input type="hidden" name="signature" t-att-value='signature'/>
+ <input type="hidden" name="tax" t-att-value='tax'/>
+ <input type="hidden" name="taxReturnBase" t-att-value="taxReturnBase"/>
+ <input type="hidden" name="buyerEmail" t-att-value='buyerEmail'/>
+ <input type="hidden" name="responseUrl" t-att-value='responseUrl'/>
+ <input type="hidden" name="extra1" t-att-value="extra1"/>
+ </div>
+ </template>
+</odoo>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<odoo>
+ <record id="payment_acquirer_form_inherit_payment_payulatam" model="ir.ui.view">
+ <field name="name">payment.acquirer.form.inherit.payment.payulatam</field>
+ <field name="model">payment.acquirer</field>
+ <field name="inherit_id" ref="payment.acquirer_form"/>
+ <field name="arch" type="xml">
+ <xpath expr='//group[@name="acquirer"]' position='after'>
+ <group attrs="{'invisible': [('provider', '!=', 'payulatam')]}">
+ <field name="payulatam_account_id"/>
+ <field name="payulatam_merchant_id"/>
+ <field name="payulatam_api_key"/>
+ </group>
+ </xpath>
+ </field>
+ </record>
+</odoo>