diff options
| author | Damien Bouvy <dbo@odoo.com> | 2015-05-18 14:34:25 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2015-06-15 14:57:14 +0200 |
| commit | dbd3efef1f0d0566265e31d6f89618ce6beec6cd (patch) | |
| tree | 2428191d9df3728b8efb5d82558fc5b1e780c4c5 | |
| parent | 46477787588089b213c5065978e1660f0dbf181e (diff) | |
[IMP] payment: add support for server2server payments
This commit adds a new model, Payment Method, which stores
a reference to the payment acquirer's database and a reference to
a partner. Each payment module must have its own implementation.
The implementation is completely abstract but may not suit every
provider's way of implementing recurring payments.
| -rw-r--r-- | addons/payment/__openerp__.py | 1 | ||||
| -rw-r--r-- | addons/payment/models/__init__.py | 1 | ||||
| -rw-r--r-- | addons/payment/models/payment_acquirer.py | 128 | ||||
| -rw-r--r-- | addons/payment/models/res_partner.py | 9 | ||||
| -rw-r--r-- | addons/payment/security/ir.model.access.csv | 6 | ||||
| -rw-r--r-- | addons/payment/security/payment_security.xml | 13 | ||||
| -rw-r--r-- | addons/payment/views/payment_acquirer.xml | 29 | ||||
| -rw-r--r-- | addons/payment/views/res_partner_view.xml | 25 |
8 files changed, 157 insertions, 55 deletions
diff --git a/addons/payment/__openerp__.py b/addons/payment/__openerp__.py index a3843a872c1..071218f7b5d 100644 --- a/addons/payment/__openerp__.py +++ b/addons/payment/__openerp__.py @@ -11,6 +11,7 @@ 'data': [ 'views/payment_acquirer.xml', 'views/res_config_view.xml', + 'views/res_partner_view.xml', 'security/ir.model.access.csv', 'security/payment_security.xml', ], diff --git a/addons/payment/models/__init__.py b/addons/payment/models/__init__.py index cd7858767fc..02ea486041a 100644 --- a/addons/payment/models/__init__.py +++ b/addons/payment/models/__init__.py @@ -2,3 +2,4 @@ import payment_acquirer import res_config +import res_partner diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index d7e7e79e14e..33ce5482568 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -1,5 +1,4 @@ # -*- coding: utf-'8' "-*-" - import logging from openerp.osv import osv, fields @@ -64,13 +63,16 @@ class PaymentAcquirer(osv.Model): 'provider': fields.selection(_provider_selection, string='Provider', required=True), 'company_id': fields.many2one('res.company', 'Company', required=True), 'pre_msg': fields.html('Message', translate=True, - help='Message displayed to explain and help the payment process.'), + help='Message displayed to explain and help the payment process.'), 'post_msg': fields.html('Thanks Message', help='Message displayed after having done the payment process.'), 'validation': fields.selection( [('manual', 'Manual'), ('automatic', 'Automatic')], string='Process Method', help='Static payments are payments like transfer, that require manual steps.'), 'view_template_id': fields.many2one('ir.ui.view', 'Form Button Template', required=True), + 'registration_view_template_id': fields.many2one('ir.ui.view', 'S2S Form Template', + domain=[('type', '=', 'qweb')], + help="Template for method registration"), 'environment': fields.selection( [('test', 'Test'), ('prod', 'Production')], string='Environment', oldname='env'), @@ -273,11 +275,41 @@ class PaymentAcquirer(osv.Model): 'partner_values': partner_values, 'tx_values': tx_values, 'context': context, + 'type': tx_values.get('type') or 'form', } # 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) + def _registration_render(self, cr, uid, id, partner_id, qweb_context=None, context=None): + acquirer = self.browse(cr, uid, id, context=context) + if qweb_context is None: + qweb_context = {} + qweb_context.update(id=id, partner_id=partner_id) + method_name = '_%s_registration_form_generate_values' % (acquirer.provider,) + if hasattr(self, method_name): + method = getattr(self, method_name) + qweb_context.update(method(cr, uid, id, qweb_context, context=context)) + return self.pool['ir.ui.view'].render(cr, uid, acquirer.registration_view_template_id.xml_id, qweb_context, engine='ir.qweb', context=context) + + def s2s_process(self, cr, uid, id, data, context=None): + acquirer = self.browse(cr, uid, id, context=context) + cust_method_name = '%s_s2s_form_process' % (acquirer.provider) + if not self.s2s_validate(cr, uid, id, data, context=context): + return False + if hasattr(self, cust_method_name): + method = getattr(self, cust_method_name) + return method(cr, uid, data, context=context) + return True + + def s2s_validate(self, cr, uid, id, data, context=None): + acquirer = self.browse(cr, uid, id, context=context) + cust_method_name = '%s_s2s_form_validate' % (acquirer.provider) + if hasattr(self, cust_method_name): + method = getattr(self, cust_method_name) + return method(cr, uid, id, data, context=context) + return True + def _wrap_payment_block(self, cr, uid, html_block, amount, currency_id, context=None): payment_header = _('Pay safely online') amount_str = float_repr(amount, self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')) @@ -342,7 +374,7 @@ class PaymentTransaction(osv.Model): required=True, ), 'type': fields.selection( - [('server2server', 'Server To Server'), ('form', 'Form')], + [('server2server', 'Server To Server'), ('form', 'Form'), ('form_save', 'Form with credentials storage')], string='Type', required=True), 'state': fields.selection( [('draft', 'Draft'), ('pending', 'Pending'), @@ -377,6 +409,11 @@ class PaymentTransaction(osv.Model): 'partner_phone': fields.char('Phone'), 'partner_reference': fields.char('Partner Reference', help='Reference of the customer in the acquirer database'), + 'html_3ds': fields.char('3D Secure HTML'), + + 's2s_cb_eval': fields.char('S2S Callback', help="""\ + Will be safe_eval with `self` being the current transaction. i.e.: + self.env['my.model'].payment_validated(self)"""), } def _check_reference(self, cr, uid, ids, context=None): @@ -467,62 +504,16 @@ class PaymentTransaction(osv.Model): # -------------------------------------------------- # 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.provider - 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.provider - 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.provider - if hasattr(self, feedback_method_name): - return getattr(self, feedback_method_name)(cr, uid, tx, data, context=context) - - return True + def s2s_do_transaction(self, cr, uid, id, context=None, **kwargs): + tx = self.browse(cr, uid, id, context=context) + custom_method_name = '%s_s2s_do_transaction' % tx.acquirer_id.provider + if hasattr(self, custom_method_name): + return getattr(self, custom_method_name)(cr, uid, id, context=context, **kwargs) def s2s_get_tx_status(self, cr, uid, tx_id, context=None): """ Get the tx status. """ @@ -533,3 +524,32 @@ class PaymentTransaction(osv.Model): return getattr(self, invalid_param_method_name)(cr, uid, tx, context=context) return True + + +class PaymentMethod(osv.Model): + _name = 'payment.method' + _order = 'partner_id' + + _columns = { + 'name': fields.char('Name', help='Name of the payment method'), + 'partner_id': fields.many2one('res.partner', 'Partner', required=True), + 'acquirer_id': fields.many2one('payment.acquirer', 'Acquirer Account', required=True), + 'acquirer_ref': fields.char('Acquirer Ref.', required=True), + 'active': fields.boolean('Active') + } + + _defaults = { + 'active': True + } + + def create(self, cr, uid, values, context=None): + # 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) + + # custom create + custom_method_name = '%s_create' % acquirer.provider + if hasattr(self, custom_method_name): + values.update(getattr(self, custom_method_name)(cr, uid, values, context=context)) + + return super(PaymentMethod, self).create(cr, uid, values, context=context) diff --git a/addons/payment/models/res_partner.py b/addons/payment/models/res_partner.py new file mode 100644 index 00000000000..e688b89a4dd --- /dev/null +++ b/addons/payment/models/res_partner.py @@ -0,0 +1,9 @@ +from openerp.osv import fields, osv + + +class res_partner(osv.osv): + _name = 'res.partner' + _inherit = 'res.partner' + _columns = { + 'payment_method_ids': fields.one2many('payment.method', 'partner_id', 'Payment Methods'), + } diff --git a/addons/payment/security/ir.model.access.csv b/addons/payment/security/ir.model.access.csv index f52f9a44d4e..942718807d5 100644 --- a/addons/payment/security/ir.model.access.csv +++ b/addons/payment/security/ir.model.access.csv @@ -4,4 +4,8 @@ payment_acquirer_user,payment.acquirer.user,model_payment_acquirer,base.group_us 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,0,0,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 +payment_transaction_system,payment.transaction.system,model_payment_transaction,base.group_system,1,1,1,1 +payment_method_all,payment.method.all,model_payment_method,,1,0,0,0 +payment_method_user,payment.method.user,model_payment_method,base.group_user,1,1,1,0 +payment_method_portal,payment.method.portal,model_payment_method,base.group_portal,1,1,1,0 +payment_method_system,payment.method.system,model_payment_method,base.group_system,1,1,1,1 diff --git a/addons/payment/security/payment_security.xml b/addons/payment/security/payment_security.xml index 7bae346c648..f2dedd5e6ee 100644 --- a/addons/payment/security/payment_security.xml +++ b/addons/payment/security/payment_security.xml @@ -20,5 +20,18 @@ <field name="groups" eval="[(4, ref('base.group_sale_salesman'))]"/> </record> + <record id="payment_method_user_rule" model="ir.rule"> + <field name="name">Access own payment methods only</field> + <field name="model_id" ref="payment.model_payment_method"/> + <field name="domain_force">[('partner_id','=',user.partner_id.id)]</field> + <field name="groups" eval="[(4, ref('base.group_user')), (4, ref('base.group_portal')), (4, ref('base.group_public'))]"/> + </record> + + <record id="payment_method_salesman_rule" model="ir.rule"> + <field name="name">Access every payment method</field> + <field name="model_id" ref="payment.model_payment_method"/> + <field name="groups" eval="[(4, ref('base.group_sale_salesman'))]"/> + </record> + </data> </openerp> diff --git a/addons/payment/views/payment_acquirer.xml b/addons/payment/views/payment_acquirer.xml index a83e475c1da..933a4fb6e3c 100644 --- a/addons/payment/views/payment_acquirer.xml +++ b/addons/payment/views/payment_acquirer.xml @@ -58,6 +58,7 @@ </ul> </div> </div> + <field name="registration_view_template_id"/> </group> </sheet> </form> @@ -189,5 +190,33 @@ parent='root_payment_menu' sequence='20' /> + <!-- Payment Methods --> + <record model='ir.ui.view' id='payment_method_tree_view'> + <field name='name'>payment.method.tree</field> + <field name='model'>payment.method</field> + <field name='arch' type='xml'> + <tree string='Payment Methods' create='false' editable='bottom'> + <field name="name"/> + <field name="active"/> + <field name='partner_id' /> + <field name='acquirer_id' readonly='1'/> + <field name='acquirer_ref' readonly='1'/> + </tree> + </field> + </record> + + + <record model='ir.actions.act_window' id='payment_method_act'> + <field name='name'>Saved Payment Data</field> + <field name='res_model'>payment.method</field> + <field name='view_type'>form</field> + <field name='view_mode'>tree</field> + </record> + + <menuitem + action='payment_method_act' + id='payment_method_menu' + parent='root_payment_menu' /> + </data> </openerp> diff --git a/addons/payment/views/res_partner_view.xml b/addons/payment/views/res_partner_view.xml new file mode 100644 index 00000000000..193018e74e1 --- /dev/null +++ b/addons/payment/views/res_partner_view.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<openerp> + <data> + + <!-- Add creditcard to res.partner --> + <record id="view_partners_form_payment_defaultcreditcard" model="ir.ui.view"> + <field name="name">view.res.partner.form.payment.defaultcreditcard</field> + <field name="model">res.partner</field> + <field name="inherit_id" ref="base.view_partner_form"/> + <field name="arch" type="xml"> + <xpath expr='//group[@name="purchase"]' position="after"> + <group string="Payment" colspan="2"> + <field name="payment_method_ids" groups="base.group_sale_salesman"> + <tree editable="bottom" create="false"> + <field name="name"/> + <field name="acquirer_id" readonly="1"/> + <field name="acquirer_ref" readonly="1"/> + </tree> + </field> + </group> + </xpath> + </field> + </record> + </data> +</openerp> |
