diff options
| author | Thibault Delavallée <tde@openerp.com> | 2014-01-22 18:57:02 +0100 |
|---|---|---|
| committer | Thibault Delavallée <tde@openerp.com> | 2014-01-22 18:57:02 +0100 |
| commit | 0b69bad9968ce2650f6dffd7df703cd33e7f38af (patch) | |
| tree | 947ae3933f8b4f382bf090031d1ea15e53e88155 /addons/payment | |
| parent | f70e54255641f4d3d61777501b20b0f8c7a1fb77 (diff) | |
[RENAME] payment_acquirer_* -> payment_ *
bzr revid: tde@openerp.com-20140122175702-1h1e51z4njt4s70w
Diffstat (limited to 'addons/payment')
| -rw-r--r-- | addons/payment/__init__.py | 22 | ||||
| -rw-r--r-- | addons/payment/__openerp__.py | 16 | ||||
| -rw-r--r-- | addons/payment/doc/changelog.rst | 9 | ||||
| -rw-r--r-- | addons/payment/doc/index.rst | 14 | ||||
| -rw-r--r-- | addons/payment/models/__init__.py | 3 | ||||
| -rw-r--r-- | addons/payment/models/payment_acquirer.py | 470 | ||||
| -rw-r--r-- | addons/payment/security/ir.model.access.csv | 7 | ||||
| -rw-r--r-- | addons/payment/static/description/icon.png | bin | 0 -> 13148 bytes | |||
| -rw-r--r-- | addons/payment/tests/__init__.py | 3 | ||||
| -rw-r--r-- | addons/payment/tests/common.py | 49 | ||||
| -rw-r--r-- | addons/payment/views/payment_acquirer.xml | 178 |
11 files changed, 771 insertions, 0 deletions
diff --git a/addons/payment/__init__.py b/addons/payment/__init__.py new file mode 100644 index 00000000000..d95d47860af --- /dev/null +++ b/addons/payment/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +import models diff --git a/addons/payment/__openerp__.py b/addons/payment/__openerp__.py new file mode 100644 index 00000000000..4102c4fe276 --- /dev/null +++ b/addons/payment/__openerp__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +{ + 'name': 'Payment Acquirer', + 'category': 'Hidden', + 'summary': 'Payment Acquirer Base Module', + 'version': '1.0', + 'description': """Payment Acquirer Base Module""", + 'author': 'OpenERP SA', + 'depends': ['mail'], + 'data': [ + 'views/payment_acquirer.xml', + 'security/ir.model.access.csv', + ], + 'installable': True, +} diff --git a/addons/payment/doc/changelog.rst b/addons/payment/doc/changelog.rst new file mode 100644 index 00000000000..d0c24af384d --- /dev/null +++ b/addons/payment/doc/changelog.rst @@ -0,0 +1,9 @@ +.. _changelog: + +Changelog +========= + +`trunk (saas-3)` +---------------- + +- Module creation
\ No newline at end of file diff --git a/addons/payment/doc/index.rst b/addons/payment/doc/index.rst new file mode 100644 index 00000000000..85028ed0d3e --- /dev/null +++ b/addons/payment/doc/index.rst @@ -0,0 +1,14 @@ +Payment module documentation +============================ + +Payment documentation topics +'''''''''''''''''''''''''''' + + +Changelog +''''''''' + +.. toctree:: + :maxdepth: 1 + + changelog.rst diff --git a/addons/payment/models/__init__.py b/addons/payment/models/__init__.py new file mode 100644 index 00000000000..da51c9c1854 --- /dev/null +++ b/addons/payment/models/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import payment_acquirer diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py new file mode 100644 index 00000000000..1a7afc3031d --- /dev/null +++ b/addons/payment/models/payment_acquirer.py @@ -0,0 +1,470 @@ +# -*- coding: utf-'8' "-*-" + +import logging + +from openerp.osv import osv, fields +from openerp.tools import float_round + +_logger = logging.getLogger(__name__) + + +def _partner_format_address(address1=False, address2=False): + return ' '.join((address1 or '', address2 or '')).strip() + + +def _partner_split_name(partner_name): + return [' '.join(partner_name.split()[-1:]), ' '.join(partner_name.split()[:-1])] + + +class ValidationError(ValueError): + """ Used for value error when validating transaction data coming from acquirers. """ + pass + + +class PaymentAcquirer(osv.Model): + """ Acquirer Model. Each specific acquirer can extend the model by adding + its own fields, using the acquirer_name as a prefix for the new fields. + Using the required_if_provider='<name>' attribute on fields it is possible + to have required fields that depend on a specific acquirer. + + Each acquirer has a link to an ir.ui.view record that is a template of + a button used to display the payment form. See examples in ``payment_ogone`` + and ``payment_paypal`` modules. + + Methods that should be added in an acquirer-specific implementation: + + - ``<name>_form_generate_values(self, cr, uid, id, reference, amount, currency, + partner_id=False, partner_values=None, tx_custom_values=None, context=None)``: + method that generates the values used to render the form button template. + - ``<name>_get_form_action_url(self, cr, uid, id, context=None):``: method + that returns the url of the button form. It is used for example in + ecommerce application, if you want to post some data to the acquirer. + - ``<name>_compute_fees(self, cr, uid, id, amount, currency_id, country_id, + context=None)``: computed the fees of the acquirer, using generic fields + defined on the acquirer model (see fields definition). + + Each acquirer should also define controllers to handle communication between + OpenERP and the acquirer. It generally consists in return urls given to the + button form and that the acquirer uses to send the customer back after the + transaction, with transaction details given as a POST request. + """ + _name = 'payment.acquirer' + _description = 'Payment Acquirer' + + _columns = { + 'name': fields.char('Name', required=True), + 'company_id': fields.many2one('res.company', 'Company', required=True), + 'message': fields.html('Message', help='Message displayed to help payment and validation'), + 'view_template_id': fields.many2one('ir.ui.view', 'Form Button Template', required=True), + 'env': fields.selection( + [('test', 'Test'), ('prod', 'Production')], + string='Environment'), + 'portal_published': fields.boolean( + 'Visible in Portal', + help="Make this payment acquirer available (Customer invoices, etc.)"), + # Fees + 'fees_active': fields.boolean('Compute fees'), + 'fees_dom_fixed': fields.float('Fixed domestic fees'), + 'fees_dom_var': fields.float('Variable domestic fees (in percents)'), + 'fees_int_fixed': fields.float('Fixed international fees'), + 'fees_int_var': fields.float('Variable international fees (in percents)'), + } + + _defaults = { + 'company_id': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(cr, uid, uid).company_id.id, + 'env': 'test', + 'portal_published': True, + } + + def _check_required_if_provider(self, cr, uid, ids, context=None): + """ If the field has 'required_if_provider="<name>"' attribute, then it + required if record.name is <name>. """ + for acquirer in self.browse(cr, uid, ids, context=context): + if any(c for c, f in self._all_columns.items() if getattr(f.column, 'required_if_provider', None) == acquirer.name and not acquirer[c]): + return False + return True + + _constraints = [ + (_check_required_if_provider, 'Required fields not filled', ['required for this provider']), + ] + + def get_form_action_url(self, cr, uid, id, context=None): + """ Returns the form action URL, for form-based acquirer implementations. """ + acquirer = self.browse(cr, uid, id, context=context) + if hasattr(self, '%s_get_form_action_url' % acquirer.name): + return getattr(self, '%s_get_form_action_url' % acquirer.name)(cr, uid, id, context=context) + return False + + def form_preprocess_values(self, cr, uid, id, reference, amount, currency_id, tx_id, partner_id, partner_values, tx_values, context=None): + """ Pre process values before giving them to the acquirer-specific render + methods. Those methods will receive: + + - partner_values: will contain name, lang, email, zip, address, city, + country_id (int or False), country (browse or False), phone, reference + - tx_values: will contain refernece, amount, currency_id (int or False), + currency (browse or False), partner (browse or False) + """ + acquirer = self.browse(cr, uid, id, context=context) + + if tx_id: + tx = self.pool.get('payment.transaction').browse(cr, uid, tx_id, context=context) + tx_data = { + 'reference': tx.reference, + 'amount': tx.amount, + 'currency_id': tx.currency_id.id, + 'currency': tx.currency_id, + 'partner': tx.partner_id, + } + partner_data = { + 'name': tx.partner_name, + 'lang': tx.partner_lang, + 'email': tx.partner_email, + 'zip': tx.partner_zip, + 'address': tx.partner_address, + 'city': tx.partner_city, + 'country_id': tx.partner_country_id.id, + 'country': tx.partner_country_id, + 'phone': tx.partner_phone, + 'reference': tx.partner_reference, + } + else: + if partner_id: + partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) + partner_data = { + 'name': partner.name, + 'lang': partner.lang, + 'email': partner.email, + 'zip': partner.zip, + 'city': partner.city, + 'address': _partner_format_address(partner.street, partner.street2), + 'country_id': partner.country_id.id, + 'country': partner.country_id, + 'phone': partner.phone, + } + else: + partner, partner_data = False, {} + partner_data.update(partner_values) + + if currency_id: + currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context) + else: + currency = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id + tx_data = { + 'reference': reference, + 'amount': amount, + 'currency_id': currency.id, + 'currency': currency, + 'partner': partner, + } + + # update tx values + tx_data.update(tx_values) + + # update partner values + if not partner_data.get('address'): + partner_data['address'] = _partner_format_address(partner_data.get('street', ''), partner_data.get('street2', '')) + if not partner_data.get('country') and partner_data.get('country_id'): + partner_data['country'] = self.pool['res.country'].browse(cr, uid, partner_data.get('country_id'), context=context) + partner_data.update({ + 'first_name': _partner_split_name(partner_data['name'])[0], + 'last_name': _partner_split_name(partner_data['name'])[1], + }) + + # compute fees + fees_method_name = '%s_compute_fees' % acquirer.name + if hasattr(self, fees_method_name): + fees = getattr(self, fees_method_name)( + cr, uid, id, tx_data['amount'], tx_data['currency_id'], partner_data['country_id'], context=None) + tx_data['fees'] = float_round(fees, 2) + + return (partner_data, tx_data) + + def render(self, cr, uid, id, reference, amount, currency_id, tx_id=None, partner_id=False, partner_values=None, tx_values=None, context=None): + """ Renders the form template of the given acquirer as a qWeb template. + All templates will receive: + + - acquirer: the payment.acquirer browse record + - user: the current user browse record + - currency: currency browse record + - amount: amount of the transaction + - reference: reference of the transaction + - partner: the current partner browse record, if any (not necessarily set) + - partner_values: a dictionary of partner-related values + - tx_values: a dictionary of transaction related values that depends on + the acquirer. Some specific keys should be managed in each + provider, depending on the features it offers: + + - 'feedback_url': feedback URL, controler that manage answer of the acquirer + (without base url) -> FIXME + - 'return_url': URL for coming back after payment validation (wihout + base url) -> FIXME + - 'cancel_url': URL if the client cancels the payment -> FIXME + - 'error_url': URL if there is an issue with the payment -> FIXME + + - context: OpenERP context dictionary + + :param string reference: the transaction reference + :param float amount: the amount the buyer has to pay + :param res.currency browse record currency: currency + :param int tx_id: id of a transaction; if set, bypasses all other given + values and only render the already-stored transaction + :param res.partner browse record partner_id: the buyer + :param dict partner_values: a dictionary of values for the buyer (see above) + :param dict tx_custom_values: a dictionary of values for the transction + that is given to the acquirer-specific method + generating the form values + :param dict context: OpenERP context + """ + if context is None: + context = {} + if tx_values is None: + tx_values = {} + if partner_values is None: + partner_values = {} + acquirer = self.browse(cr, uid, id, context=context) + + # pre-process values + amount = float_round(amount, 2) + partner_values, tx_values = self.form_preprocess_values( + cr, uid, id, reference, amount, currency_id, tx_id, partner_id, + partner_values, tx_values, context=context) + + # call <name>_form_generate_values to update the tx dict with acqurier specific values + cust_method_name = '%s_form_generate_values' % (acquirer.name) + if hasattr(self, cust_method_name): + method = getattr(self, cust_method_name) + partner_values, tx_values = method(cr, uid, id, partner_values, tx_values, context=context) + + qweb_context = { + 'tx_url': context.get('tx_url', self.get_form_action_url(cr, uid, id, context=context)), + 'submit_class': context.get('submit_class', 'btn btn-link'), + 'submit_txt': context.get('submit_txt'), + 'acquirer': acquirer, + 'user': self.pool.get("res.users").browse(cr, uid, uid, context=context), + 'reference': tx_values['reference'], + 'amount': tx_values['amount'], + 'currency': tx_values['currency'], + 'partner': tx_values.get('partner'), + 'partner_values': partner_values, + 'tx_values': tx_values, + 'context': context, + } + + # because render accepts view ids but not qweb -> need to use the xml_id + return self.pool['ir.ui.view'].render(cr, uid, acquirer.view_template_id.xml_id, qweb_context, engine='ir.qweb', context=context) + + +class PaymentTransaction(osv.Model): + """ Transaction Model. Each specific acquirer can extend the model by adding + its own fields. + + Methods that can be added in an acquirer-specific implementation: + + - ``<name>_create``: method receiving values used when creating a new + transaction and that returns a dictionary that will update those values. + This method can be used to tweak some transaction values. + + Methods defined for convention, depending on your controllers: + + - ``<name>_form_feedback(self, cr, uid, data, context=None)``: method that + handles the data coming from the acquirer after the transaction. It will + generally receives data posted by the acquirer after the transaction. + """ + _name = 'payment.transaction' + _description = 'Payment Transaction' + _inherit = ['mail.thread'] + _order = 'id desc' + _rec_name = 'reference' + + _columns = { + 'date_create': fields.datetime('Creation Date', readonly=True, required=True), + 'date_validate': fields.datetime('Validation Date'), + 'acquirer_id': fields.many2one( + 'payment.acquirer', 'Acquirer', + required=True, + ), + 'type': fields.selection( + [('server2server', 'Server To Server'), ('form', 'Form')], + string='Type', required=True), + 'state': fields.selection( + [('draft', 'Draft'), ('pending', 'Pending'), + ('done', 'Done'), ('error', 'Error'), + ('cancel', 'Canceled') + ], 'Status', required=True, + track_visiblity='onchange'), + 'state_message': fields.text('Message', + help='Field used to store error and/or validation messages for information'), + # payment + 'amount': fields.float('Amount', required=True, + digits=(16, 2), + track_visibility='always', + help='Amount in cents'), + 'fees': fields.float('Fees', + digits=(16, 2), + track_visibility='always', + help='Fees amount; set by the system because depends on the acquirer'), + 'currency_id': fields.many2one('res.currency', 'Currency', required=True), + 'reference': fields.char('Order Reference', required=True), + 'acquirer_reference': fields.char('Acquirer Order Reference', + help='Reference of the TX as stored in the acquirer database'), + # duplicate partner / transaction data to store the values at transaction time + 'partner_id': fields.many2one('res.partner', 'Partner', track_visibility='onchange',), + 'partner_name': fields.char('Partner Name'), + 'partner_lang': fields.char('Lang'), + 'partner_email': fields.char('Email'), + 'partner_zip': fields.char('Zip'), + 'partner_address': fields.char('Address'), + 'partner_city': fields.char('City'), + 'partner_country_id': fields.many2one('res.country', 'Country', required=True), + 'partner_phone': fields.char('Phone'), + 'partner_reference': fields.char('Partner Reference', + help='Reference of the customer in the acquirer database'), + } + + _sql_constraints = [ + ('reference_uniq', 'UNIQUE(reference)', 'The payment transaction reference must be unique!'), + ] + + _defaults = { + 'date_create': fields.datetime.now, + 'type': 'form', + 'state': 'draft', + 'partner_lang': 'en_US', + } + + def create(self, cr, uid, values, context=None): + Acquirer = self.pool['payment.acquirer'] + + if values.get('partner_id'): # @TDENOTE: not sure + values.update(self.on_change_partner_id(cr, uid, None, values.get('partner_id'), context=context)['values']) + + # call custom create method if defined (i.e. ogone_create for ogone) + if values.get('acquirer_id'): + acquirer = self.pool['payment.acquirer'].browse(cr, uid, values.get('acquirer_id'), context=context) + + # compute fees + custom_method_name = '%s_compute_fees' % acquirer.name + if hasattr(Acquirer, custom_method_name): + fees = getattr(Acquirer, custom_method_name)( + cr, uid, acquirer.id, values.get('amount', 0.0), values.get('currency_id'), values.get('country_id'), context=None) + values['fees'] = float_round(fees, 2) + + # custom create + custom_method_name = '%s_create' % acquirer.name + if hasattr(self, custom_method_name): + values.update(getattr(self, custom_method_name)(cr, uid, values, context=context)) + + return super(PaymentTransaction, self).create(cr, uid, values, context=context) + + def on_change_partner_id(self, cr, uid, ids, partner_id, context=None): + partner = None + if partner_id: + partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) + return {'values': { + 'partner_name': partner and partner.name or False, + 'partner_lang': partner and partner.lang or 'en_US', + 'partner_email': partner and partner.email or False, + 'partner_zip': partner and partner.zip or False, + 'partner_address': _partner_format_address(partner and partner.street or '', partner and partner.street2 or ''), + 'partner_city': partner and partner.city or False, + 'partner_country_id': partner and partner.country_id.id or False, + 'partner_phone': partner and partner.phone or False, + }} + + # -------------------------------------------------- + # FORM RELATED METHODS + # -------------------------------------------------- + + def form_feedback(self, cr, uid, data, acquirer_name, context=None): + invalid_parameters, tx = None, None + + tx_find_method_name = '_%s_form_get_tx_from_data' % acquirer_name + if hasattr(self, tx_find_method_name): + tx = getattr(self, tx_find_method_name)(cr, uid, data, context=context) + + invalid_param_method_name = '_%s_form_get_invalid_parameters' % acquirer_name + if hasattr(self, invalid_param_method_name): + invalid_parameters = getattr(self, invalid_param_method_name)(cr, uid, tx, data, context=context) + + if invalid_parameters: + _error_message = '%s: incorrect tx data:\n' % (acquirer_name) + for item in invalid_parameters: + _error_message += '\t%s: received %s instead of %s\n' % (item[0], item[1], item[2]) + _logger.error(_error_message) + return False + + feedback_method_name = '_%s_form_validate' % acquirer_name + if hasattr(self, feedback_method_name): + return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) + + return True + + # -------------------------------------------------- + # SERVER2SERVER RELATED METHODS + # -------------------------------------------------- + + def s2s_create(self, cr, uid, values, cc_values, context=None): + tx_id, tx_result = self.s2s_send(cr, uid, values, cc_values, context=context) + self.s2s_feedback(cr, uid, tx_id, tx_result, context=context) + return tx_id + + def s2s_send(self, cr, uid, values, cc_values, context=None): + """ Create and send server-to-server transaction. + + :param dict values: transaction values + :param dict cc_values: credit card values that are not stored into the + payment.transaction object. Acquirers should + handle receiving void or incorrect cc values. + Should contain : + + - holder_name + - number + - cvc + - expiry_date + - brand + - expiry_date_yy + - expiry_date_mm + """ + tx_id, result = None, None + + if values.get('acquirer_id'): + acquirer = self.pool['payment.acquirer'].browse(cr, uid, values.get('acquirer_id'), context=context) + custom_method_name = '_%s_s2s_send' % acquirer.name + if hasattr(self, custom_method_name): + tx_id, result = getattr(self, custom_method_name)(cr, uid, values, cc_values, context=context) + + if tx_id is None and result is None: + tx_id = super(PaymentTransaction, self).create(cr, uid, values, context=context) + return (tx_id, result) + + def s2s_feedback(self, cr, uid, tx_id, data, context=None): + """ Handle the feedback of a server-to-server transaction. """ + tx = self.browse(cr, uid, tx_id, context=context) + invalid_parameters = None + + invalid_param_method_name = '_%s_s2s_get_invalid_parameters' % tx.acquirer_id.name + if hasattr(self, invalid_param_method_name): + invalid_parameters = getattr(self, invalid_param_method_name)(cr, uid, tx, data, context=context) + + if invalid_parameters: + _error_message = '%s: incorrect tx data:\n' % (tx.acquirer_id.name) + for item in invalid_parameters: + _error_message += '\t%s: received %s instead of %s\n' % (item[0], item[1], item[2]) + _logger.error(_error_message) + return False + + feedback_method_name = '_%s_s2s_validate' % tx.acquirer_id.name + if hasattr(self, feedback_method_name): + return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) + + return True + + def s2s_get_tx_status(self, cr, uid, tx_id, context=None): + """ Get the tx status. """ + tx = self.browse(cr, uid, tx_id, context=context) + + invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.name + if hasattr(self, invalid_param_method_name): + return getattr(self, invalid_param_method_name)(cr, uid, tx, context=context) + + return True diff --git a/addons/payment/security/ir.model.access.csv b/addons/payment/security/ir.model.access.csv new file mode 100644 index 00000000000..18f98939472 --- /dev/null +++ b/addons/payment/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +payment_acquirer_all,payment.acquirer.all,model_payment_acquirer,,1,0,0,0 +payment_acquirer_user,payment.acquirer.user,model_payment_acquirer,base.group_user,1,1,1,0 +payment_acquirer_system,payment.acquirer.system,model_payment_acquirer,base.group_system,1,1,1,1 +payment_transaction_all,payment.transaction.all,model_payment_transaction,,1,1,1,0 +payment_transaction_user,payment.transaction.user,model_payment_transaction,base.group_user,1,1,1,0 +payment_transaction_system,payment.transaction.system,model_payment_transaction,base.group_system,1,1,1,1
\ No newline at end of file diff --git a/addons/payment/static/description/icon.png b/addons/payment/static/description/icon.png Binary files differnew file mode 100644 index 00000000000..51e33ac6ddf --- /dev/null +++ b/addons/payment/static/description/icon.png diff --git a/addons/payment/tests/__init__.py b/addons/payment/tests/__init__.py new file mode 100644 index 00000000000..5c193a07c8d --- /dev/null +++ b/addons/payment/tests/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +import common diff --git a/addons/payment/tests/common.py b/addons/payment/tests/common.py new file mode 100644 index 00000000000..93a1820a447 --- /dev/null +++ b/addons/payment/tests/common.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- + +from openerp.tests import common + + +class PaymentAcquirerCommon(common.TransactionCase): + + def setUp(self): + super(PaymentAcquirerCommon, self).setUp() + self.payment_acquirer = self.registry('payment.acquirer') + self.payment_transaction = self.registry('payment.transaction') + + self.currency_euro_id = self.registry('res.currency').search( + self.cr, self.uid, [('name', '=', 'EUR')], limit=1)[0] + self.currency_euro = self.registry('res.currency').browse( + self.cr, self.uid, self.currency_euro_id) + self.country_belgium_id = self.registry('res.country').search( + self.cr, self.uid, [('code', 'like', 'BE')], limit=1)[0] + self.country_france_id = self.registry('res.country').search( + self.cr, self.uid, [('code', 'like', 'FR')], limit=1)[0] + + # dict partner values + self.buyer_values = { + 'name': 'Norbert Buyer', + 'lang': 'en_US', + 'email': 'norbert.buyer@example.com', + 'street': 'Huge Street', + 'street2': '2/543', + 'phone': '0032 12 34 56 78', + 'city': 'Sin City', + 'zip': '1000', + 'country_id': self.country_belgium_id, + 'country_name': 'Belgium', + } + + # test partner + self.buyer_id = self.registry('res.partner').create( + self.cr, self.uid, { + 'name': 'Norbert Buyer', + 'lang': 'en_US', + 'email': 'norbert.buyer@example.com', + 'street': 'Huge Street', + 'street2': '2/543', + 'phone': '0032 12 34 56 78', + 'city': 'Sin City', + 'zip': '1000', + 'country_id': self.country_belgium_id, + } + ) diff --git a/addons/payment/views/payment_acquirer.xml b/addons/payment/views/payment_acquirer.xml new file mode 100644 index 00000000000..9f7429d3f22 --- /dev/null +++ b/addons/payment/views/payment_acquirer.xml @@ -0,0 +1,178 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> + <data> + + <menuitem + name='Payments' + id='root_payment_menu' + parent='base.menu_administration'/> + + <record id="acquirer_form" model="ir.ui.view"> + <field name="name">acquirer.form</field> + <field name="model">payment.acquirer</field> + <field name="arch" type="xml"> + <form string="Payment Acquirer" version="7.0"> + <sheet> + <group name="acquirer_base"> + <group> + <field name="name"/> + <field name="company_id"/> + <field name="portal_published"/> + <field name="env"/> + </group> + <group> + <field name="fees_active"/> + <field name="fees_dom_fixed" + attrs="{'invisible': [('fees_active', '=', False)]}"/> + <field name="fees_dom_var" + attrs="{'invisible': [('fees_active', '=', False)]}"/> + <field name="fees_int_fixed" + attrs="{'invisible': [('fees_active', '=', False)]}"/> + <field name="fees_int_var" + attrs="{'invisible': [('fees_active', '=', False)]}"/> + </group> + </group> + <group name="acquirer_display"> + <field name="message"/> + <label for="view_template_id"/> + <div> + <field name="view_template_id" nolabel="1"/> + <div> + This template renders the acquirer button with all necessary values. + It is be rendered with qWeb with the following evaluation context: + <ul> + <li>tx_url: transaction URL to post the form</li> + <li>acquirer: payment.acquirer browse record</li> + <li>user: current user browse record</li> + <li>reference: the transaction reference number</li> + <li>currency: the transaction currency browse record</li> + <li>amount: the transaction amount, a float</li> + <li>partner: the buyer partner browse record, not necessarily set</li> + <li>partner_values: specific values about the buyer, for example coming from a shipping form</li> + <li>tx_values: transaction values</li> + <li>context: the current context dictionary</li> + </ul> + </div> + </div> + </group> + </sheet> + </form> + </field> + </record> + + <record id="acquirer_list" model="ir.ui.view"> + <field name="model">payment.acquirer</field> + <field name="arch" type="xml"> + <tree string="Payment Acquirers"> + <field name="name"/> + <field name="portal_published"/> + <field name="env"/> + </tree> + </field> + </record> + + <record id="acquirer_search" model="ir.ui.view"> + <field name="model">payment.acquirer</field> + <field name="arch" type="xml"> + <search> + <field name="name"/> + </search> + </field> + </record> + + <record id="action_payment_acquirer" model="ir.actions.act_window"> + <field name="name">Payment Acquirers</field> + <field name="res_model">payment.acquirer</field> + <field name='view_type'>form</field> + <field name='view_mode'>tree,form</field> + </record> + + <menuitem + action='action_payment_acquirer' + id='payment_acquirer_menu' + parent='root_payment_menu' + sequence='10' /> + + <record id="transaction_form" model="ir.ui.view"> + <field name="model">payment.transaction</field> + <field name="arch" type="xml"> + <form string="Payment Transactions" version="7.0"> + <sheet> + <group col="6"> + <group> + <field name="reference"/> + <field name="amount"/> + <field name="date_create"/> + <field name="fees"/> + <field name="currency_id"/> + <field name="partner_id"/> + <field name="partner_reference"/> + </group> + <group> + <field name="acquirer_id"/> + <field name="acquirer_reference"/> + <field name="date_validate"/> + <field name="state"/> + <field name="state_message"/> + </group> + <group> + <field name="partner_name"/> + <field name="partner_address"/> + <field name="partner_email"/> + <field name="partner_lang"/> + <field name="partner_zip"/> + <field name="partner_city"/> + <field name="partner_country_id"/> + </group> + </group> + <notebook> + </notebook> + </sheet> + <div class="oe_chatter"> + <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/> + <field name="message_ids" widget="mail_thread" options='{"thread_level": 1}' placeholder="Send a message to the group"/> + </div> + </form> + </field> + </record> + + <record id="transaction_list" model="ir.ui.view"> + <field name="model">payment.transaction</field> + <field name="arch" type="xml"> + <tree string="Payment Transactions"> + <field name="reference"/> + <field name="acquirer_id"/> + <field name="partner_id"/> + <field name="partner_name"/> + <field name="state"/> + </tree> + </field> + </record> + + <record id="transaction" model="ir.ui.view"> + <field name="model">payment.transaction</field> + <field name="arch" type="xml"> + <search> + <field name="reference"/> + <field name="acquirer_id"/> + <field name="partner_id"/> + <field name="partner_name"/> + </search> + </field> + </record> + + <record id="action_payment_transaction" model="ir.actions.act_window"> + <field name="name">Payment Transactions</field> + <field name="res_model">payment.transaction</field> + <field name='view_type'>form</field> + <field name='view_mode'>tree,form</field> + </record> + + <menuitem + action='action_payment_transaction' + id='payment_transaction_menu' + parent='root_payment_menu' + sequence='20' /> + + </data> +</openerp> |
