From 88126f95d3e23d78e5ad1a6d6006f9d09493fbd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 10:29:10 +0200 Subject: [PATCH 01/22] [REF] payment_*: method signatures Methods with signature - cr, uid, id - cr, uid, have been refactored to be future multi ensure one methods. --- addons/payment/models/payment_acquirer.py | 40 +++++++++---------- addons/payment_adyen/models/adyen.py | 14 ++++--- addons/payment_authorize/models/authorize.py | 24 +++++------ addons/payment_buckaroo/models/buckaroo.py | 15 +++---- addons/payment_ogone/models/ogone.py | 29 ++++++++------ addons/payment_paypal/models/paypal.py | 20 +++++----- .../models/payment_transaction.py | 18 ++++----- addons/payment_sips/models/sips.py | 36 ++++++++--------- .../models/payment_transaction.py | 14 +++---- .../models/payment_acquirer.py | 8 ++-- addons/website_payment/controllers/main.py | 2 +- addons/website_sale/controllers/main.py | 29 +++++++------- 12 files changed, 131 insertions(+), 118 deletions(-) diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index a2ea8f69f65..678d3602773 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -154,14 +154,14 @@ class PaymentAcquirer(osv.Model): image_resize_images(vals) return super(PaymentAcquirer, self).write(vals) - def get_form_action_url(self, cr, uid, id, context=None): + def get_form_action_url(self, cr, uid, ids, context=None): """ Returns the form action URL, for form-based acquirer implementations. """ - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] if hasattr(self, '%s_get_form_action_url' % acquirer.provider): return getattr(self, '%s_get_form_action_url' % acquirer.provider)(cr, uid, id, context=context) return False - def render(self, cr, uid, id, reference, amount, currency_id, partner_id=False, values=None, context=None): + def render(self, cr, uid, ids, reference, amount, currency_id, partner_id=False, values=None, context=None): """ Renders the form template of the given acquirer as a qWeb template. :param string reference: the transaction reference :param float amount: the amount the buyer has to pay @@ -191,7 +191,7 @@ class PaymentAcquirer(osv.Model): context = {} if values is None: values = {} - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] # reference and amount values.setdefault('reference', reference) @@ -288,8 +288,8 @@ class PaymentAcquirer(osv.Model): return acquirer.view_template_id.render(values, engine='ir.qweb') - def _registration_render(self, cr, uid, id, partner_id, qweb_context=None, context=None): - acquirer = self.browse(cr, uid, id, context=context) + def _registration_render(self, cr, uid, ids, partner_id, qweb_context=None, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] if qweb_context is None: qweb_context = {} qweb_context.update(id=id, partner_id=partner_id) @@ -299,8 +299,8 @@ class PaymentAcquirer(osv.Model): qweb_context.update(method(cr, uid, id, qweb_context, context=context)) return acquirer.registration_view_template_id.render(qweb_context, engine='ir.qweb') - def s2s_process(self, cr, uid, id, data, context=None): - acquirer = self.browse(cr, uid, id, context=context) + def s2s_process(self, cr, uid, ids, data, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] cust_method_name = '%s_s2s_form_process' % (acquirer.provider) if not self.s2s_validate(cr, uid, id, data, context=context): return False @@ -309,8 +309,8 @@ class PaymentAcquirer(osv.Model): 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) + def s2s_validate(self, cr, uid, ids, data, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] cust_method_name = '%s_s2s_form_validate' % (acquirer.provider) if hasattr(self, cust_method_name): method = getattr(self, cust_method_name) @@ -517,8 +517,8 @@ class PaymentTransaction(osv.Model): # FORM RELATED METHODS # -------------------------------------------------- - def render(self, cr, uid, id, context=None): - tx = self.browse(cr, uid, id, context=context) + def render(self, cr, uid, ids, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] values = { 'reference': tx.reference, 'amount': tx.amount, @@ -547,7 +547,7 @@ class PaymentTransaction(osv.Model): 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) + invalid_parameters = getattr(self, invalid_param_method_name)(cr, uid, [tx.id], data, context=context) if invalid_parameters: _error_message = '%s: incorrect tx data:\n' % (acquirer_name) @@ -558,7 +558,7 @@ class PaymentTransaction(osv.Model): 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 getattr(self, feedback_method_name)(cr, uid, [tx.id], data, context=context) return True @@ -570,19 +570,19 @@ class PaymentTransaction(osv.Model): self.s2s_feedback(cr, uid, tx_id, tx_result, context=context) return tx_id - def s2s_do_transaction(self, cr, uid, id, context=None, **kwargs): - tx = self.browse(cr, uid, id, context=context) + def s2s_do_transaction(self, cr, uid, ids, context=None, **kwargs): + tx = self.browse(cr, uid, ids, context=context)[0] 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) + return getattr(self, custom_method_name)(cr, uid, ids, context=context, **kwargs) - def s2s_get_tx_status(self, cr, uid, tx_id, context=None): + def s2s_get_tx_status(self, cr, uid, ids, context=None): """ Get the tx status. """ - tx = self.browse(cr, uid, tx_id, context=context) + tx = self.browse(cr, uid, ids, context=context)[0] invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.provider if hasattr(self, invalid_param_method_name): - return getattr(self, invalid_param_method_name)(cr, uid, tx, context=context) + return getattr(self, invalid_param_method_name)(cr, uid, ids, context=context) return True diff --git a/addons/payment_adyen/models/adyen.py b/addons/payment_adyen/models/adyen.py index f9f17126a13..c06ae797b0b 100644 --- a/addons/payment_adyen/models/adyen.py +++ b/addons/payment_adyen/models/adyen.py @@ -119,9 +119,9 @@ class AcquirerAdyen(osv.Model): key = acquirer.adyen_skin_hmac_key.encode('ascii') return base64.b64encode(hmac.new(key, sign, hashlib.sha1).digest()) - def adyen_form_generate_values(self, cr, uid, id, values, context=None): + def adyen_form_generate_values(self, cr, uid, ids, values, context=None): base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] # tmp import datetime from dateutil import relativedelta @@ -163,8 +163,8 @@ class AcquirerAdyen(osv.Model): return values - def adyen_get_form_action_url(self, cr, uid, id, context=None): - acquirer = self.browse(cr, uid, id, context=context) + def adyen_get_form_action_url(self, cr, uid, ids, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] return self._get_adyen_urls(cr, uid, acquirer.environment, context=context)['adyen_form_url'] @@ -206,7 +206,8 @@ class TxAdyen(osv.Model): return tx - def _adyen_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): + def _adyen_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] invalid_parameters = [] # reference at acquirer: pspReference @@ -221,7 +222,8 @@ class TxAdyen(osv.Model): return invalid_parameters - def _adyen_form_validate(self, cr, uid, tx, data, context=None): + def _adyen_form_validate(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] status = data.get('authResult', 'PENDING') if status == 'AUTHORISED': tx.write({ diff --git a/addons/payment_authorize/models/authorize.py b/addons/payment_authorize/models/authorize.py index 828fd614ded..b9a16ee37fb 100644 --- a/addons/payment_authorize/models/authorize.py +++ b/addons/payment_authorize/models/authorize.py @@ -122,37 +122,37 @@ class TxAuthorize(models.Model): raise ValidationError(error_msg) return tx[0] - @api.model - def _authorize_form_get_invalid_parameters(self, tx, data): + @api.multi + def _authorize_form_get_invalid_parameters(self, data): invalid_parameters = [] if self.acquirer_reference and data.get('x_trans_id') != self.acquirer_reference: invalid_parameters.append(('Transaction Id', data.get('x_trans_id'), self.acquirer_reference)) # check what is buyed - if float_compare(float(data.get('x_amount', '0.0')), tx.amount, 2) != 0: - invalid_parameters.append(('Amount', data.get('x_amount'), '%.2f' % tx.amount)) + if float_compare(float(data.get('x_amount', '0.0')), self.amount, 2) != 0: + invalid_parameters.append(('Amount', data.get('x_amount'), '%.2f' % self.amount)) return invalid_parameters - @api.model - def _authorize_form_validate(self, tx, data): - if tx.state == 'done': - _logger.warning('Authorize: trying to validate an already validated tx (ref %s)' % tx.reference) + @api.multi + def _authorize_form_validate(self, data): + if self.state == 'done': + _logger.warning('Authorize: trying to validate an already validated tx (ref %s)' % self.reference) return True status_code = int(data.get('x_response_code', '0')) if status_code == self._authorize_valid_tx_status: - tx.write({ + self.write({ 'state': 'done', 'acquirer_reference': data.get('x_trans_id'), }) return True elif status_code == self._authorize_pending_tx_status: - tx.write({ + self.write({ 'state': 'pending', 'acquirer_reference': data.get('x_trans_id'), }) return True elif status_code == self._authorize_cancel_tx_status: - tx.write({ + self.write({ 'state': 'cancel', 'acquirer_reference': data.get('x_trans_id'), }) @@ -160,7 +160,7 @@ class TxAuthorize(models.Model): else: error = data.get('x_response_reason_text') _logger.info(error) - tx.write({ + self.write({ 'state': 'error', 'state_message': error, 'acquirer_reference': data.get('x_trans_id'), diff --git a/addons/payment_buckaroo/models/buckaroo.py b/addons/payment_buckaroo/models/buckaroo.py index 80cfbc2ddfb..cb9914ee222 100644 --- a/addons/payment_buckaroo/models/buckaroo.py +++ b/addons/payment_buckaroo/models/buckaroo.py @@ -90,10 +90,9 @@ class AcquirerBuckaroo(osv.Model): shasign = sha1(sign.encode('utf-8')).hexdigest() return shasign - - def buckaroo_form_generate_values(self, cr, uid, id, values, context=None): + def buckaroo_form_generate_values(self, cr, uid, ids, values, context=None): base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] buckaroo_tx_values = dict(values) buckaroo_tx_values.update({ 'Brq_websitekey': acquirer.brq_websitekey, @@ -111,8 +110,8 @@ class AcquirerBuckaroo(osv.Model): buckaroo_tx_values['Brq_signature'] = self._buckaroo_generate_digital_sign(acquirer, 'in', buckaroo_tx_values) return buckaroo_tx_values - def buckaroo_get_form_action_url(self, cr, uid, id, context=None): - acquirer = self.browse(cr, uid, id, context=context) + def buckaroo_get_form_action_url(self, cr, uid, ids, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] return self._get_buckaroo_urls(cr, uid, acquirer.environment, context=context)['buckaroo_form_url'] class TxBuckaroo(osv.Model): @@ -161,7 +160,8 @@ class TxBuckaroo(osv.Model): return tx - def _buckaroo_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): + def _buckaroo_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] invalid_parameters = [] data = normalize_keys_upper(data) if tx.acquirer_reference and data.get('BRQ_TRANSACTIONS') != tx.acquirer_reference: @@ -174,7 +174,8 @@ class TxBuckaroo(osv.Model): return invalid_parameters - def _buckaroo_form_validate(self, cr, uid, tx, data, context=None): + def _buckaroo_form_validate(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] data = normalize_keys_upper(data) status_code = int(data.get('BRQ_STATUSCODE','0')) if status_code in self._buckaroo_valid_tx_status: diff --git a/addons/payment_ogone/models/ogone.py b/addons/payment_ogone/models/ogone.py index b11b6f25969..54aee7f7f70 100644 --- a/addons/payment_ogone/models/ogone.py +++ b/addons/payment_ogone/models/ogone.py @@ -147,9 +147,9 @@ class PaymentAcquirerOgone(osv.Model): shasign = sha1(sign).hexdigest() return shasign - def ogone_form_generate_values(self, cr, uid, id, values, context=None): + def ogone_form_generate_values(self, cr, uid, ids, values, context=None): base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] ogone_tx_values = dict(values) temp_ogone_tx_values = { 'PSPID': acquirer.ogone_pspid, @@ -180,11 +180,11 @@ class PaymentAcquirerOgone(osv.Model): ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values - def ogone_get_form_action_url(self, cr, uid, id, context=None): - acquirer = self.browse(cr, uid, id, context=context) + def ogone_get_form_action_url(self, cr, uid, ids, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] return self._get_ogone_urls(cr, uid, acquirer.environment, context=context)['ogone_standard_order_url'] - def ogone_s2s_form_validate(self, cr, uid, id, data, context=None): + def ogone_s2s_form_validate(self, cr, uid, ids, data, context=None): error = dict() error_message = [] @@ -269,7 +269,8 @@ class PaymentTxOgone(osv.Model): return tx - def _ogone_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): + def _ogone_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] invalid_parameters = [] # TODO: txn_id: should be false at draft, set afterwards, and verified with txn details @@ -283,7 +284,8 @@ class PaymentTxOgone(osv.Model): return invalid_parameters - def _ogone_form_validate(self, cr, uid, tx, data, context=None): + def _ogone_form_validate(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] if tx.state == 'done': _logger.info('Ogone: trying to validate an already validated tx (ref %s)', tx.reference) return True @@ -334,9 +336,9 @@ class PaymentTxOgone(osv.Model): # -------------------------------------------------- # S2S RELATED METHODS # -------------------------------------------------- - def ogone_s2s_do_transaction(self, cr, uid, id, context=None, **kwargs): + def ogone_s2s_do_transaction(self, cr, uid, ids, context=None, **kwargs): # TODO: create tx with s2s type - tx = self.browse(cr, uid, id, context=context) + tx = self.browse(cr, uid, ids, context=context)[0] account = tx.acquirer_id reference = tx.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%y%m%d_%H%M%S'), tx.partner_id.id) @@ -384,11 +386,13 @@ class PaymentTxOgone(osv.Model): return self._ogone_s2s_validate_tree(tx, tree) - def _ogone_s2s_validate(self, tx): + def _ogone_s2s_validate(self, cr, uid, ids, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] tree = self._ogone_s2s_get_tx_status(tx) return self._ogone_s2s_validate_tree(tx, tree) - def _ogone_s2s_validate_tree(self, tx, tree, tries=2): + def _ogone_s2s_validate_tree(self, cr, uid, ids, tree, tries=2, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] if tx.state not in ('draft', 'pending'): _logger.info('Ogone: trying to validate an already validated tx (ref %s)', tx.reference) return True @@ -441,7 +445,8 @@ class PaymentTxOgone(osv.Model): }) return False - def _ogone_s2s_get_tx_status(self, tx): + def _ogone_s2s_get_tx_status(self, cr, uid, ids, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] account = tx.acquirer_id #reference = tx.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%Y%m%d_%H%M%S'), tx.partner_id.id) diff --git a/addons/payment_paypal/models/paypal.py b/addons/payment_paypal/models/paypal.py index a92086c49c9..0876c93e88a 100644 --- a/addons/payment_paypal/models/paypal.py +++ b/addons/payment_paypal/models/paypal.py @@ -62,7 +62,7 @@ class AcquirerPaypal(osv.Model): 'paypal_api_enabled': False, } - def paypal_compute_fees(self, cr, uid, id, amount, currency_id, country_id, context=None): + def paypal_compute_fees(self, cr, uid, ids, amount, currency_id, country_id, context=None): """ Compute paypal fees. :param float amount: the amount to pay @@ -71,7 +71,7 @@ class AcquirerPaypal(osv.Model): the acquirer company country. :return float fees: computed fees """ - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] if not acquirer.fees_active: return 0.0 country = self.pool['res.country'].browse(cr, uid, country_id, context=context) @@ -81,12 +81,12 @@ class AcquirerPaypal(osv.Model): else: percentage = acquirer.fees_int_var fixed = acquirer.fees_int_fixed - fees = (percentage / 100.0 * amount + fixed ) / (1 - percentage / 100.0) + fees = (percentage / 100.0 * amount + fixed) / (1 - percentage / 100.0) return fees - def paypal_form_generate_values(self, cr, uid, id, values, context=None): + def paypal_form_generate_values(self, cr, uid, ids, values, context=None): base_url = self.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, 'web.base.url') - acquirer = self.browse(cr, uid, id, context=context) + acquirer = self.browse(cr, uid, ids, context=context)[0] paypal_tx_values = dict(values) paypal_tx_values.update({ @@ -112,8 +112,8 @@ class AcquirerPaypal(osv.Model): }) return paypal_tx_values - def paypal_get_form_action_url(self, cr, uid, id, context=None): - acquirer = self.browse(cr, uid, id, context=context) + def paypal_get_form_action_url(self, cr, uid, ids, context=None): + acquirer = self.browse(cr, uid, ids, context=context)[0] return self._get_paypal_urls(cr, uid, acquirer.environment, context=context)['paypal_form_url'] def _paypal_s2s_get_access_token(self, cr, uid, ids, context=None): @@ -177,7 +177,8 @@ class TxPaypal(osv.Model): raise ValidationError(error_msg) return self.browse(cr, uid, tx_ids[0], context=context) - def _paypal_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): + def _paypal_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] invalid_parameters = [] _logger.info('Received a notification from Paypal with IPN version %s', data.get('notify_version')) if data.get('test_ipn'): @@ -213,7 +214,8 @@ class TxPaypal(osv.Model): return invalid_parameters - def _paypal_form_validate(self, cr, uid, tx, data, context=None): + def _paypal_form_validate(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] status = data.get('payment_status') res = { 'acquirer_reference': data.get('txn_id'), diff --git a/addons/payment_payumoney/models/payment_transaction.py b/addons/payment_payumoney/models/payment_transaction.py index b502307b467..e89a95511ec 100644 --- a/addons/payment_payumoney/models/payment_transaction.py +++ b/addons/payment_payumoney/models/payment_transaction.py @@ -39,22 +39,22 @@ class PaymentTransactionPayumoney(models.Model): raise ValidationError(_('PayUmoney: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data)) return transaction - @api.model - def _payumoney_form_get_invalid_parameters(self, transaction, data): + @api.multi + def _payumoney_form_get_invalid_parameters(self, data): invalid_parameters = [] - if transaction.acquirer_reference and data.get('mihpayid') != transaction.acquirer_reference: + if self.acquirer_reference and data.get('mihpayid') != self.acquirer_reference: invalid_parameters.append( - ('Transaction Id', data.get('mihpayid'), transaction.acquirer_reference)) + ('Transaction Id', data.get('mihpayid'), self.acquirer_reference)) #check what is buyed - if float_compare(float(data.get('amount', '0.0')), transaction.amount, 2) != 0: + if float_compare(float(data.get('amount', '0.0')), self.amount, 2) != 0: invalid_parameters.append( - ('Amount', data.get('amount'), '%.2f' % transaction.amount)) + ('Amount', data.get('amount'), '%.2f' % self.amount)) return invalid_parameters - @api.model - def _payumoney_form_validate(self, transaction, data): + @api.multi + def _payumoney_form_validate(self, data): status = data.get('status') transaction_status = { 'success': { @@ -83,4 +83,4 @@ class PaymentTransactionPayumoney(models.Model): if not vals: vals = transaction_status['error'] _logger.info(vals['state_message']) - return transaction.write(vals) + return self.write(vals) diff --git a/addons/payment_sips/models/sips.py b/addons/payment_sips/models/sips.py index df669fd3804..e194cb281e5 100644 --- a/addons/payment_sips/models/sips.py +++ b/addons/payment_sips/models/sips.py @@ -165,25 +165,25 @@ class TxSips(models.Model): raise ValidationError(error_msg) return payment_tx - @api.model - def _sips_form_get_invalid_parameters(self, tx, data): + @api.multi + def _sips_form_get_invalid_parameters(self, data): invalid_parameters = [] data = self._sips_data_to_object(data.get('Data')) # TODO: txn_id: should be false at draft, set afterwards, and verified with txn details - if tx.acquirer_reference and data.get('transactionReference') != tx.acquirer_reference: - invalid_parameters.append(('transactionReference', data.get('transactionReference'), tx.acquirer_reference)) + if self.acquirer_reference and data.get('transactionReference') != self.acquirer_reference: + invalid_parameters.append(('transactionReference', data.get('transactionReference'), self.acquirer_reference)) # check what is bought - if float_compare(float(data.get('amount', '0.0')) / 100, tx.amount, 2) != 0: - invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) - if tx.partner_reference and data.get('customerId') != tx.partner_reference: - invalid_parameters.append(('customerId', data.get('customerId'), tx.partner_reference)) + if float_compare(float(data.get('amount', '0.0')) / 100, self.amount, 2) != 0: + invalid_parameters.append(('amount', data.get('amount'), '%.2f' % self.amount)) + if self.partner_reference and data.get('customerId') != self.partner_reference: + invalid_parameters.append(('customerId', data.get('customerId'), self.partner_reference)) return invalid_parameters - @api.model - def _sips_form_validate(self, tx, data): + @api.multi + def _sips_form_validate(self, data): data = self._sips_data_to_object(data.get('Data')) status = data.get('responseCode') data = { @@ -195,35 +195,35 @@ class TxSips(models.Model): res = False if status in self._sips_valid_tx_status: msg = 'Payment for tx ref: %s, got response [%s], set as done.' % \ - (tx.reference, status) + (self.reference, status) _logger.info(msg) data.update(state='done', state_message=msg) res = True elif status in self._sips_error_tx_status: msg = 'Payment for tx ref: %s, got response [%s], set as ' \ - 'error.' % (tx.reference, status) + 'error.' % (self.reference, status) data.update(state='error', state_message=msg) elif status in self._sips_wait_tx_status: msg = 'Received wait status for payment ref: %s, got response ' \ - '[%s], set as error.' % (tx.reference, status) + '[%s], set as error.' % (self.reference, status) data.update(state='error', state_message=msg) elif status in self._sips_refused_tx_status: msg = 'Received refused status for payment ref: %s, got response' \ - ' [%s], set as error.' % (tx.reference, status) + ' [%s], set as error.' % (self.reference, status) data.update(state='error', state_message=msg) elif status in self._sips_pending_tx_status: msg = 'Payment ref: %s, got response [%s] set as pending.' \ - % (tx.reference, status) + % (self.reference, status) data.update(state='pending', state_message=msg) elif status in self._sips_cancel_tx_status: msg = 'Received notification for payment ref: %s, got response ' \ - '[%s], set as cancel.' % (tx.reference, status) + '[%s], set as cancel.' % (self.reference, status) data.update(state='cancel', state_message=msg) else: msg = 'Received unrecognized status for payment ref: %s, got ' \ - 'response [%s], set as error.' % (tx.reference, status) + 'response [%s], set as error.' % (self.reference, status) data.update(state='error', state_message=msg) _logger.info(msg) - tx.write(data) + self.write(data) return res diff --git a/addons/payment_stripe/models/payment_transaction.py b/addons/payment_stripe/models/payment_transaction.py index 5682123d71d..c1e3e5608af 100644 --- a/addons/payment_stripe/models/payment_transaction.py +++ b/addons/payment_stripe/models/payment_transaction.py @@ -88,14 +88,14 @@ class PaymentTransactionStripe(models.Model): }) return False - @api.model - def _stripe_form_get_invalid_parameters(self, tx, data): + @api.multi + def _stripe_form_get_invalid_parameters(self, data): invalid_parameters = [] reference = data['metadata']['reference'] - if reference != tx.reference: - invalid_parameters.append(('Reference', reference, tx.reference)) + if reference != self.reference: + invalid_parameters.append(('Reference', reference, self.reference)) return invalid_parameters - @api.model - def _stripe_form_validate(self, tx, data): - return tx._stripe_s2s_validate_tree(data) + @api.multi + def _stripe_form_validate(self, data): + return self._stripe_s2s_validate_tree(data) diff --git a/addons/payment_transfer/models/payment_acquirer.py b/addons/payment_transfer/models/payment_acquirer.py index a8d47098c6c..126329e8a6f 100644 --- a/addons/payment_transfer/models/payment_acquirer.py +++ b/addons/payment_transfer/models/payment_acquirer.py @@ -19,7 +19,7 @@ class TransferPaymentAcquirer(osv.Model): providers.append(['transfer', _('Wire Transfer')]) return providers - def transfer_get_form_action_url(self, cr, uid, id, context=None): + def transfer_get_form_action_url(self, cr, uid, ids, context=None): return '/payment/transfer/feedback' def _format_transfer_data(self, cr, uid, context=None): @@ -71,7 +71,8 @@ class TransferPaymentTransaction(osv.Model): return self.browse(cr, uid, tx_ids[0], context=context) - def _transfer_form_get_invalid_parameters(self, cr, uid, tx, data, context=None): + def _transfer_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] invalid_parameters = [] if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: @@ -81,6 +82,7 @@ class TransferPaymentTransaction(osv.Model): return invalid_parameters - def _transfer_form_validate(self, cr, uid, tx, data, context=None): + def _transfer_form_validate(self, cr, uid, ids, data, context=None): + tx = self.browse(cr, uid, ids, context=context)[0] _logger.info('Validated transfer payment for tx %s: set as pending' % (tx.reference)) return tx.write({'state': 'pending'}) diff --git a/addons/website_payment/controllers/main.py b/addons/website_payment/controllers/main.py index d2d86734c3a..a3487e5052d 100644 --- a/addons/website_payment/controllers/main.py +++ b/addons/website_payment/controllers/main.py @@ -46,7 +46,7 @@ class website_payment(http.Controller): partner_id = user.partner_id.id if user.partner_id.id != request.website.partner_id.id else False - payment_form = acquirer.render(reference, float(amount), currency.id, values={'return_url': '/website_payment/confirm', 'partner_id': partner_id})[0] + payment_form = acquirer.render(reference, float(amount), currency.id, values={'return_url': '/website_payment/confirm', 'partner_id': partner_id}) values = { 'reference': reference, 'acquirer': acquirer, diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 991105f8774..25770f915a5 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -703,19 +703,20 @@ class WebsiteSale(http.Controller): acquirers = request.env['payment.acquirer'].search( [('website_published', '=', True), ('company_id', '=', order.company_id.id)] ) - values['acquirers'] = list(acquirers) - acquirer_buttons = acquirers.with_context(submit_class='btn btn-primary', submit_txt=_('Pay Now')).sudo().render( - '/', - order.amount_total, - order.pricelist_id.currency_id.id, - values={ - 'return_url': '/shop/payment/validate', - 'partner_id': shipping_partner_id, - 'billing_partner_id': order.partner_invoice_id.id, - } - ) - for index, button in enumerate(acquirer_buttons): - values['acquirers'][index].button = button + values['acquirers'] = [] + for acquirer in acquirers: + acquirer_button = acquirer.with_context(submit_class='btn btn-primary', submit_txt=_('Pay Now')).sudo().render( + '/', + order.amount_total, + order.pricelist_id.currency_id.id, + values={ + 'return_url': '/shop/payment/validate', + 'partner_id': shipping_partner_id, + 'billing_partner_id': order.partner_invoice_id.id, + } + ) + acquirer.button = acquirer_button + values['acquirers'].append(acquirer) return request.website.render("website_sale.payment", values) @@ -772,7 +773,7 @@ class WebsiteSale(http.Controller): 'partner_id': order.partner_shipping_id.id or order.partner_invoice_id.id, 'billing_partner_id': order.partner_invoice_id.id, }, - )[0] + ) @http.route('/shop/payment/get_status/', type='json', auth="public", website=True) def payment_get_status(self, sale_order_id, **post): From 82d68747c36609fec5bef909efe7ac8bbf736144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 11:33:36 +0200 Subject: [PATCH 02/22] [CLN] payment_*: dead code removal Old s2s prototype code has been removed. It is not used anywhere and not supported. Moreover ogone s2s implementation use its own set of methods. In a near future a neat implementation of s2s for paypal will be added. --- addons/payment/models/payment_acquirer.py | 4 - addons/payment_paypal/models/paypal.py | 189 ---------------------- 2 files changed, 193 deletions(-) diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index 678d3602773..44e340d7ce5 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -565,10 +565,6 @@ 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_do_transaction(self, cr, uid, ids, context=None, **kwargs): tx = self.browse(cr, uid, ids, context=context)[0] diff --git a/addons/payment_paypal/models/paypal.py b/addons/payment_paypal/models/paypal.py index 0876c93e88a..62e307a5ae9 100644 --- a/addons/payment_paypal/models/paypal.py +++ b/addons/payment_paypal/models/paypal.py @@ -116,36 +116,6 @@ class AcquirerPaypal(osv.Model): acquirer = self.browse(cr, uid, ids, context=context)[0] return self._get_paypal_urls(cr, uid, acquirer.environment, context=context)['paypal_form_url'] - def _paypal_s2s_get_access_token(self, cr, uid, ids, context=None): - """ - Note: see # see http://stackoverflow.com/questions/2407126/python-urllib2-basic-auth-problem - for explanation why we use Authorization header instead of urllib2 - password manager - """ - res = dict.fromkeys(ids, False) - parameters = werkzeug.url_encode({'grant_type': 'client_credentials'}) - - for acquirer in self.browse(cr, uid, ids, context=context): - tx_url = self._get_paypal_urls(cr, uid, acquirer.environment)['paypal_rest_url'] - request = urllib2.Request(tx_url, parameters) - - # add other headers (https://developer.paypal.com/webapps/developer/docs/integration/direct/make-your-first-call/) - request.add_header('Accept', 'application/json') - request.add_header('Accept-Language', 'en_US') - - # add authorization header - base64string = base64.encodestring('%s:%s' % ( - acquirer.paypal_api_username, - acquirer.paypal_api_password) - ).replace('\n', '') - request.add_header("Authorization", "Basic %s" % base64string) - - request = urllib2.urlopen(request) - result = request.read() - res[acquirer.id] = json.loads(result).get('access_token') - request.close() - return res - class TxPaypal(osv.Model): _inherit = 'payment.transaction' @@ -234,162 +204,3 @@ class TxPaypal(osv.Model): _logger.info(error) res.update(state='error', state_message=error) return tx.write(res) - - # -------------------------------------------------- - # SERVER2SERVER RELATED METHODS - # -------------------------------------------------- - - def _paypal_try_url(self, request, tries=3, context=None): - """ Try to contact Paypal. Due to some issues, internal service errors - seem to be quite frequent. Several tries are done before considering - the communication as failed. - - .. versionadded:: pre-v8 saas-3 - .. warning:: - - Experimental code. You should not use it before OpenERP v8 official - release. - """ - done, res = False, None - while (not done and tries): - try: - res = urllib2.urlopen(request) - done = True - except urllib2.HTTPError as e: - res = e.read() - e.close() - if tries and res and json.loads(res)['name'] == 'INTERNAL_SERVICE_ERROR': - _logger.warning('Failed contacting Paypal, retrying (%s remaining)' % tries) - tries = tries - 1 - if not res: - pass - # raise openerp.exceptions. - result = res.read() - res.close() - return result - - def _paypal_s2s_send(self, cr, uid, values, cc_values, context=None): - """ - .. versionadded:: pre-v8 saas-3 - .. warning:: - - Experimental code. You should not use it before OpenERP v8 official - release. - """ - tx_id = self.create(cr, uid, values, context=context) - tx = self.browse(cr, uid, tx_id, context=context) - - headers = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer %s' % tx.acquirer_id._paypal_s2s_get_access_token()[tx.acquirer_id.id], - } - data = { - 'intent': 'sale', - 'transactions': [{ - 'amount': { - 'total': '%.2f' % tx.amount, - 'currency': tx.currency_id.name, - }, - 'description': tx.reference, - }] - } - if cc_values: - data['payer'] = { - 'payment_method': 'credit_card', - 'funding_instruments': [{ - 'credit_card': { - 'number': cc_values['number'], - 'type': cc_values['brand'], - 'expire_month': cc_values['expiry_mm'], - 'expire_year': cc_values['expiry_yy'], - 'cvv2': cc_values['cvc'], - 'first_name': tx.partner_name, - 'last_name': tx.partner_name, - 'billing_address': { - 'line1': tx.partner_address, - 'city': tx.partner_city, - 'country_code': tx.partner_country_id.code, - 'postal_code': tx.partner_zip, - } - } - }] - } - else: - # TODO: complete redirect URLs - data['redirect_urls'] = { - # 'return_url': 'http://example.com/your_redirect_url/', - # 'cancel_url': 'http://example.com/your_cancel_url/', - }, - data['payer'] = { - 'payment_method': 'paypal', - } - data = json.dumps(data) - - request = urllib2.Request('https://api.sandbox.paypal.com/v1/payments/payment', data, headers) - result = self._paypal_try_url(request, tries=3, context=context) - return (tx_id, result) - - def _paypal_s2s_get_invalid_parameters(self, cr, uid, tx, data, context=None): - """ - .. versionadded:: pre-v8 saas-3 - .. warning:: - - Experimental code. You should not use it before OpenERP v8 official - release. - """ - invalid_parameters = [] - return invalid_parameters - - def _paypal_s2s_validate(self, cr, uid, tx, data, context=None): - """ - .. versionadded:: pre-v8 saas-3 - .. warning:: - - Experimental code. You should not use it before OpenERP v8 official - release. - """ - values = json.loads(data) - status = values.get('state') - if status in ['approved']: - _logger.info('Validated Paypal s2s payment for tx %s: set as done' % (tx.reference)) - tx.write({ - 'state': 'done', - 'date_validate': values.get('udpate_time', fields.datetime.now()), - 'paypal_txn_id': values['id'], - }) - return True - elif status in ['pending', 'expired']: - _logger.info('Received notification for Paypal s2s payment %s: set as pending' % (tx.reference)) - tx.write({ - 'state': 'pending', - # 'state_message': data.get('pending_reason', ''), - 'paypal_txn_id': values['id'], - }) - return True - else: - error = 'Received unrecognized status for Paypal s2s payment %s: %s, set as error' % (tx.reference, status) - _logger.info(error) - tx.write({ - 'state': 'error', - # 'state_message': error, - 'paypal_txn_id': values['id'], - }) - return False - - def _paypal_s2s_get_tx_status(self, cr, uid, tx, context=None): - """ - .. versionadded:: pre-v8 saas-3 - .. warning:: - - Experimental code. You should not use it before OpenERP v8 official - release. - """ - # TDETODO: check tx.paypal_txn_id is set - headers = { - 'Content-Type': 'application/json', - 'Authorization': 'Bearer %s' % tx.acquirer_id._paypal_s2s_get_access_token()[tx.acquirer_id.id], - } - url = 'https://api.sandbox.paypal.com/v1/payments/payment/%s' % (tx.paypal_txn_id) - request = urllib2.Request(url, headers=headers) - data = self._paypal_try_url(request, tries=3, context=context) - return self.s2s_feedback(cr, uid, tx.id, data, context=context) From c3758a959abf98ad59a8eeb196f3443971d809df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 1 Jul 2016 15:54:51 +0200 Subject: [PATCH 03/22] [MOV] payment: file organization --- addons/payment/__openerp__.py | 14 +++++++------- .../payment/data/{account.xml => account_data.xml} | 0 ...ment_acquirer.xml => payment_acquirer_data.xml} | 0 ..._view.xml => account_config_settings_views.xml} | 0 ...count_payment.xml => account_payment_views.xml} | 0 .../views/{assets.xml => payment_templates.xml} | 0 .../{payment_acquirer.xml => payment_views.xml} | 0 ...{res_partner_view.xml => res_partner_views.xml} | 0 8 files changed, 7 insertions(+), 7 deletions(-) rename addons/payment/data/{account.xml => account_data.xml} (100%) rename addons/payment/data/{payment_acquirer.xml => payment_acquirer_data.xml} (100%) rename addons/payment/views/{res_config_view.xml => account_config_settings_views.xml} (100%) rename addons/payment/views/{account_payment.xml => account_payment_views.xml} (100%) rename addons/payment/views/{assets.xml => payment_templates.xml} (100%) rename addons/payment/views/{payment_acquirer.xml => payment_views.xml} (100%) rename addons/payment/views/{res_partner_view.xml => res_partner_views.xml} (100%) diff --git a/addons/payment/__openerp__.py b/addons/payment/__openerp__.py index d5409ca301f..a9b40aa8534 100644 --- a/addons/payment/__openerp__.py +++ b/addons/payment/__openerp__.py @@ -8,13 +8,13 @@ 'description': """Payment Acquirer Base Module""", 'depends': ['account'], 'data': [ - 'data/payment_acquirer.xml', - 'data/account.xml', - 'views/payment_acquirer.xml', - 'views/assets.xml', - 'views/res_config_view.xml', - 'views/res_partner_view.xml', - 'views/account_payment.xml', + 'data/account_data.xml', + 'data/payment_acquirer_data.xml', + 'views/payment_views.xml', + 'views/account_config_settings_views.xml', + 'views/account_payment_views.xml', + 'views/payment_templates.xml', + 'views/res_partner_views.xml', 'security/ir.model.access.csv', 'security/payment_security.xml', ], diff --git a/addons/payment/data/account.xml b/addons/payment/data/account_data.xml similarity index 100% rename from addons/payment/data/account.xml rename to addons/payment/data/account_data.xml diff --git a/addons/payment/data/payment_acquirer.xml b/addons/payment/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment/data/payment_acquirer.xml rename to addons/payment/data/payment_acquirer_data.xml diff --git a/addons/payment/views/res_config_view.xml b/addons/payment/views/account_config_settings_views.xml similarity index 100% rename from addons/payment/views/res_config_view.xml rename to addons/payment/views/account_config_settings_views.xml diff --git a/addons/payment/views/account_payment.xml b/addons/payment/views/account_payment_views.xml similarity index 100% rename from addons/payment/views/account_payment.xml rename to addons/payment/views/account_payment_views.xml diff --git a/addons/payment/views/assets.xml b/addons/payment/views/payment_templates.xml similarity index 100% rename from addons/payment/views/assets.xml rename to addons/payment/views/payment_templates.xml diff --git a/addons/payment/views/payment_acquirer.xml b/addons/payment/views/payment_views.xml similarity index 100% rename from addons/payment/views/payment_acquirer.xml rename to addons/payment/views/payment_views.xml diff --git a/addons/payment/views/res_partner_view.xml b/addons/payment/views/res_partner_views.xml similarity index 100% rename from addons/payment/views/res_partner_view.xml rename to addons/payment/views/res_partner_views.xml From a969931f9cce7191313edbe12a11708bb1b05cbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Fri, 1 Jul 2016 15:59:16 +0200 Subject: [PATCH 04/22] [MIG] payment: new API No functional change. --- addons/payment/models/account_payment.py | 39 +- addons/payment/models/payment_acquirer.py | 624 +++++++++--------- addons/payment/models/res_partner.py | 28 +- addons/payment/security/payment_security.xml | 4 +- addons/payment/tests/common.py | 47 +- .../views/account_config_settings_views.xml | 4 +- addons/payment/views/payment_views.xml | 4 +- addons/payment/views/res_partner_views.xml | 4 +- 8 files changed, 363 insertions(+), 391 deletions(-) diff --git a/addons/payment/models/account_payment.py b/addons/payment/models/account_payment.py index 2b825b922e4..c2449129215 100644 --- a/addons/payment/models/account_payment.py +++ b/addons/payment/models/account_payment.py @@ -1,14 +1,21 @@ # coding: utf-8 import datetime + from odoo import _, api, fields, models from odoo.exceptions import ValidationError + class AccountPayment(models.Model): _inherit = 'account.payment' + payment_transaction_id = fields.Many2one('payment.transaction', string="Payment Transaction") + payment_token_id = fields.Many2one('payment.token', string="Saved payment token") + payment_type = fields.Selection(selection_add=[('electronic', 'Electronically receive money')]) + payment_method_id_code = fields.Char(related='payment_method_id.code') + @api.onchange('partner_id') - def onchange_partner_id(self): + def _onchange_partner_id(self): res = {} if self.partner_id: res['domain'] = {'payment_token_id': [('partner_id', '=', self.partner_id.id)]} @@ -16,22 +23,23 @@ class AccountPayment(models.Model): return res @api.onchange('payment_method_id', 'journal_id') - def _clear_electronic_payment_token(self): + def _onchange_payment_method(self): if self.payment_method_id.code == 'electronic': self.payment_token_id = self.env['payment.token'].search([('partner_id', '=', self.partner_id.id)], limit=1) else: self.payment_token_id = False - payment_transaction_id = fields.Many2one('payment.transaction', string="Payment Transaction") - payment_token_id = fields.Many2one('payment.token', string="Saved payment token") - payment_type = fields.Selection(selection_add=[('electronic', 'Electronically receive money')]) - payment_method_id_code = fields.Char(related='payment_method_id.code') + @api.model + def create(self, vals): + account_payment = super(AccountPayment, self).create(vals) + + if account_payment.payment_token_id: + account_payment._do_payment() + return account_payment def _do_payment(self): - tx_obj = self.env['payment.transaction'] reference = "PAYMENT-%s-%s" % (self.id, datetime.datetime.now().strftime('%y%m%d_%H%M%S')) - - tx_values = { + tx = self.env['payment.transaction'].create({ 'amount': self.amount, 'acquirer_id': self.payment_token_id.acquirer_id.id, 'type': 'server2server', @@ -40,9 +48,7 @@ class AccountPayment(models.Model): 'payment_token_id': self.payment_token_id.id, 'partner_id': self.partner_id.id, 'partner_country_id': self.partner_id.country_id.id, - } - - tx = tx_obj.create(tx_values) + }) s2s_result = tx.s2s_do_transaction() @@ -50,12 +56,3 @@ class AccountPayment(models.Model): raise ValidationError(_("Payment transaction failed (%s)") % tx.state_message) self.payment_transaction_id = tx - - @api.model - def create(self, vals): - res = super(AccountPayment, self).create(vals) - - if res.payment_token_id: - res._do_payment() - - return res diff --git a/addons/payment/models/payment_acquirer.py b/addons/payment/models/payment_acquirer.py index 44e340d7ce5..f614bf3306f 100644 --- a/addons/payment/models/payment_acquirer.py +++ b/addons/payment/models/payment_acquirer.py @@ -1,10 +1,9 @@ # coding: utf-8 import logging -import openerp -from openerp.osv import osv, fields -from openerp.tools import float_round, float_repr, image_resize_images -from openerp.tools.translate import _ +from odoo import api, exceptions, fields, models, _ +from odoo.tools import float_round, image_resize_images +from odoo.addons.base.module import module _logger = logging.getLogger(__name__) @@ -22,7 +21,7 @@ class ValidationError(ValueError): pass -class PaymentAcquirer(osv.Model): +class PaymentAcquirer(models.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='' attribute on fields it is possible @@ -34,15 +33,15 @@ class PaymentAcquirer(osv.Model): Methods that should be added in an acquirer-specific implementation: - - ``_form_generate_values(self, cr, uid, id, reference, amount, currency, - partner_id=False, partner_values=None, tx_custom_values=None, context=None)``: + - ``_form_generate_values(self, reference, amount, currency, + partner_id=False, partner_values=None, tx_custom_values=None)``: method that generates the values used to render the form button template. - - ``_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. - - ``_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). + - ``_get_form_action_url(self):``: 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. + - ``_compute_fees(self, amount, currency_id, country_id)``: computes + 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 @@ -53,89 +52,93 @@ class PaymentAcquirer(osv.Model): _description = 'Payment Acquirer' _order = 'sequence' - def _get_providers(self, cr, uid, context=None): - return [('manual', 'Manual Configuration')] + name = fields.Char('Name', required=True, translate=True) + description = fields.Html('Description') + sequence = fields.Integer('Sequence', help="Determine the display order") + provider = fields.Selection( + selection=[('manual', 'Manual Configuration')], string='Provider', + default='manual', required=True) + company_id = fields.Many2one( + 'res.company', 'Company', + default=lambda self: self.env.user.company_id.id, required=True) + 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', + default='test', oldname='env', required=True) + website_published = fields.Boolean( + 'Visible in Portal / Website', copy=False, + help="Make this payment acquirer available (Customer invoices, etc.)") + auto_confirm = fields.Selection([ + ('none', 'No automatic confirmation'), + ('confirm_so', 'Confirm the SO on acquirer confirmation'), + ('generate_and_pay_invoice', 'On acquirer confirmation, confirm the SO, generate the invoice and pay it')], + string='Order Confirmation', default='confirm_so', required=True) + journal_id = fields.Many2one( + 'account.journal', 'Accounting Journal', + help="Account journal used for automatic payment reconciliation.") - def _compute_fees_implemented(self, cr, uid, ids, field_names, arg, context=None): - acquirer_model = self.pool['payment.acquirer'] - res = {} + pre_msg = fields.Html( + 'Help Message', translate=True, + help='Message displayed to explain and help the payment process.') + post_msg = fields.Html( + 'Thanks Message', translate=True, + help='Message displayed after having done the payment process.') + pending_msg = fields.Html( + 'Pending Message', translate=True, + default='Pending, Your online payment has been successfully processed. But your order is not validated yet.', + help='Message displayed, if order is in pending state after having done the payment process.') + done_msg = fields.Html( + 'Done Message', translate=True, + default='Done, Your online payment has been successfully processed. Thank you for your order.', + help='Message displayed, if order is done successfully after having done the payment process.') + cancel_msg = fields.Html( + 'Cancel Message', translate=True, + default='Cancel, Your payment has been cancelled.', + help='Message displayed, if order is cancel during the payment process.') + error_msg = fields.Html( + 'Error Message', translate=True, + default='Error, Please be aware that an error occurred during the transaction. The order has been confirmed but will not be paid. Do not hesitate to contact us if you have any questions on the status of your order.', + help='Message displayed, if error is occur during the payment process.') - for acquirer in acquirer_model.browse(cr, uid, ids, context=context): - custom_method_name = '%s_compute_fees' % acquirer.provider - res[acquirer.id] = hasattr(acquirer_model, custom_method_name) + fees_implemented = fields.Boolean('Fees Computation Supported', compute='_compute_fees_implemented') + fees_active = fields.Boolean('Add Extra 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)') - return res + # TDE FIXME: remove that brol + module_id = fields.Many2one('ir.module.module', string='Corresponding Module') + module_state = fields.Selection(selection=module.STATES, string='Installation State', related='module_id.state') - # indirection to ease inheritance - _provider_selection = lambda self, *args, **kwargs: self._get_providers(*args, **kwargs) - - _columns = { - 'name': fields.char('Name', required=True, translate=True), - 'provider': fields.selection(_provider_selection, string='Provider', required=True, default='manual'), - 'company_id': fields.many2one('res.company', 'Company', required=True), - 'pre_msg': fields.html('Help Message', translate=True, - help='Message displayed to explain and help the payment process.'), - 'post_msg': fields.html('Thanks Message', translate=True, - help='Message displayed after having done the payment process.'), - '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', required=True, oldname='env'), - 'website_published': fields.boolean( - 'Visible in Portal / Website', copy=False, - help="Make this payment acquirer available (Customer invoices, etc.)"), - 'auto_confirm': fields.selection( - [('none', 'No automatic confirmation'), - ('confirm_so', 'Confirm the SO on acquirer confirmation'), - ('generate_and_pay_invoice', 'On acquirer confirmation, confirm the SO, generate the invoice and pay it')], - string='Order Confirmation', required=True), - 'pending_msg': fields.html('Pending Message', translate=True, help='Message displayed, if order is in pending state after having done the payment process.'), - 'done_msg': fields.html('Done Message', translate=True, help='Message displayed, if order is done successfully after having done the payment process.'), - 'cancel_msg': fields.html('Cancel Message', translate=True, help='Message displayed, if order is cancel during the payment process.'), - 'error_msg': fields.html('Error Message', translate=True, help='Message displayed, if error is occur during the payment process.'), - # Fees - 'fees_implemented': fields.function(_compute_fees_implemented, type="boolean"), - 'fees_active': fields.boolean('Add Extra 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)'), - 'sequence': fields.integer('Sequence', help="Determine the display order"), - 'module_id': fields.many2one('ir.module.module', string='Corresponding Module'), - 'module_state': fields.related('module_id', 'state', type='char', string='Installation State'), - 'description': fields.html('Description'), - 'journal_id': fields.many2one('account.journal', 'Accounting Journal', help="Account journal used for automatic payment reconciliation."), - } - - image = openerp.fields.Binary("Image", attachment=True, + image = fields.Binary( + "Image", attachment=True, help="This field holds the image used for this provider, limited to 1024x1024px") - image_medium = openerp.fields.Binary("Medium-sized image", attachment=True, - help="Medium-sized image of this provider. It is automatically "\ - "resized as a 128x128px image, with aspect ratio preserved. "\ + image_medium = fields.Binary( + "Medium-sized image", attachment=True, + help="Medium-sized image of this provider. It is automatically " + "resized as a 128x128px image, with aspect ratio preserved. " "Use this field in form views or some kanban views.") - image_small = openerp.fields.Binary("Small-sized image", attachment=True, - help="Small-sized image of this provider. It is automatically "\ - "resized as a 64x64px image, with aspect ratio preserved. "\ + image_small = fields.Binary( + "Small-sized image", attachment=True, + help="Small-sized image of this provider. It is automatically " + "resized as a 64x64px image, with aspect ratio preserved. " "Use this field anywhere a small image is required.") - _defaults = { - 'company_id': lambda self, cr, uid, obj, ctx=None: self.pool['res.users'].browse(cr, uid, uid).company_id.id, - 'environment': 'test', - 'website_published': False, - 'auto_confirm': 'confirm_so', - 'pending_msg': 'Pending, Your online payment has been successfully processed. But your order is not validated yet.', - 'done_msg': 'Done, Your online payment has been successfully processed. Thank you for your order.', - 'cancel_msg': 'Cancel, Your payment has been cancelled.', - 'error_msg': "Error, Please be aware that an error occurred during the transaction. The order has been confirmed but won't be paid. Don't hesitate to contact us if you have any questions on the status of your order." - } + @api.one + def _compute_fees_implemented(self): + self.fees_implemented = hasattr(self, '%s_compute_fees' % self.provider) - def _check_required_if_provider(self, cr, uid, ids, context=None): + @api.multi + def _check_required_if_provider(self): """ If the field has 'required_if_provider=""' attribute, then it required if record.provider is . """ - for acquirer in self.browse(cr, uid, ids, context=context): + for acquirer in self: if any(getattr(f, 'required_if_provider', None) == acquirer.provider and not acquirer[k] for k, f in self._fields.items()): return False return True @@ -144,24 +147,25 @@ class PaymentAcquirer(osv.Model): (_check_required_if_provider, 'Required fields not filled', []), ] - @openerp.api.model + @api.model def create(self, vals): image_resize_images(vals) return super(PaymentAcquirer, self).create(vals) - @openerp.api.multi + @api.multi def write(self, vals): image_resize_images(vals) return super(PaymentAcquirer, self).write(vals) - def get_form_action_url(self, cr, uid, ids, context=None): + @api.multi + def get_form_action_url(self): """ Returns the form action URL, for form-based acquirer implementations. """ - acquirer = self.browse(cr, uid, ids, context=context)[0] - if hasattr(self, '%s_get_form_action_url' % acquirer.provider): - return getattr(self, '%s_get_form_action_url' % acquirer.provider)(cr, uid, id, context=context) + if hasattr(self, '%s_get_form_action_url' % self.provider): + return getattr(self, '%s_get_form_action_url' % self.provider)() return False - def render(self, cr, uid, ids, reference, amount, currency_id, partner_id=False, values=None, context=None): + @api.multi + def render(self, reference, amount, currency_id, partner_id=False, values=None): """ Renders the form template of the given acquirer as a qWeb template. :param string reference: the transaction reference :param float amount: the amount the buyer has to pay @@ -169,7 +173,6 @@ class PaymentAcquirer(osv.Model): :param dict partner_id: optional partner_id to fill values :param dict 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 All templates will receive: @@ -184,14 +187,11 @@ class PaymentAcquirer(osv.Model): - '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 + - context: Odoo context """ - if context is None: - context = {} if values is None: values = {} - acquirer = self.browse(cr, uid, ids, context=context)[0] # reference and amount values.setdefault('reference', reference) @@ -201,18 +201,18 @@ class PaymentAcquirer(osv.Model): # currency id currency_id = values.setdefault('currency_id', currency_id) if currency_id: - currency = self.pool['res.currency'].browse(cr, uid, currency_id, context=context) + currency = self.env['res.currency'].browse(currency_id) else: - currency = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.currency_id + currency = self.env.user.company_id.currency_id values['currency'] = currency - # Fill partner_* using values['partner_id'] or partner_id arguement + # Fill partner_* using values['partner_id'] or partner_id argument partner_id = values.get('partner_id', partner_id) billing_partner_id = values.get('billing_partner_id', partner_id) if partner_id: - partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) + partner = self.env['res.partner'].browse(partner_id) if partner_id != billing_partner_id: - billing_partner = self.pool['res.partner'].browse(cr, uid, billing_partner_id, context=context) + billing_partner = self.env['res.partner'].browse(billing_partner_id) else: billing_partner = partner values.update({ @@ -256,90 +256,89 @@ class PaymentAcquirer(osv.Model): if not values.get('partner_address'): values['address'] = _partner_format_address(values.get('partner_street', ''), values.get('partner_street2', '')) if not values.get('partner_country') and values.get('partner_country_id'): - values['country'] = self.pool['res.country'].browse(cr, uid, values.get('partner_country_id'), context=context) + values['country'] = self.env['res.country'].browse(values.get('partner_country_id')) if not values.get('billing_partner_address'): values['billing_address'] = _partner_format_address(values.get('billing_partner_street', ''), values.get('billing_partner_street2', '')) if not values.get('billing_partner_country') and values.get('billing_partner_country_id'): - values['billing_country'] = self.pool['res.country'].browse(cr, uid, values.get('billing_partner_country_id'), context=context) - + values['billing_country'] = self.env['res.country'].browse(values.get('billing_partner_country_id')) # compute fees - fees_method_name = '%s_compute_fees' % acquirer.provider + fees_method_name = '%s_compute_fees' % self.provider if hasattr(self, fees_method_name): - fees = getattr(self, fees_method_name)(cr, uid, id, values['amount'], values['currency_id'], values.get('partner_country_id'), context=None) + fees = getattr(self, fees_method_name)(values['amount'], values['currency_id'], values.get('partner_country_id')) values['fees'] = float_round(fees, 2) # call _form_generate_values to update the tx dict with acqurier specific values - cust_method_name = '%s_form_generate_values' % (acquirer.provider) + cust_method_name = '%s_form_generate_values' % (self.provider) if hasattr(self, cust_method_name): method = getattr(self, cust_method_name) - values = method(cr, uid, id, values, context=context) + values = method(values) values.update({ - '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), - 'context': context, + 'tx_url': self._context.get('tx_url', self.get_form_action_url()), + 'submit_class': self._context.get('submit_class', 'btn btn-link'), + 'submit_txt': self._context.get('submit_txt'), + 'acquirer': self, + 'user': self.env.user, + 'context': self._context, 'type': values.get('type') or 'form', }) values.setdefault('return_url', False) - return acquirer.view_template_id.render(values, engine='ir.qweb') + return self.view_template_id.render(values, engine='ir.qweb') - def _registration_render(self, cr, uid, ids, partner_id, qweb_context=None, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def _registration_render(self, partner_id, qweb_context=None): 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,) + qweb_context.update(id=self.ids[0], partner_id=partner_id) + method_name = '_%s_registration_form_generate_values' % (self.provider,) if hasattr(self, method_name): method = getattr(self, method_name) - qweb_context.update(method(cr, uid, id, qweb_context, context=context)) - return acquirer.registration_view_template_id.render(qweb_context, engine='ir.qweb') + qweb_context.update(method(qweb_context)) + return self.registration_view_template_id.render(qweb_context, engine='ir.qweb') - def s2s_process(self, cr, uid, ids, data, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - cust_method_name = '%s_s2s_form_process' % (acquirer.provider) - if not self.s2s_validate(cr, uid, id, data, context=context): + @api.multi + def s2s_process(self, data): + cust_method_name = '%s_s2s_form_process' % (self.provider) + if not self.s2s_validate(data): return False if hasattr(self, cust_method_name): method = getattr(self, cust_method_name) - return method(cr, uid, data, context=context) + return method(data) return True - def s2s_validate(self, cr, uid, ids, data, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - cust_method_name = '%s_s2s_form_validate' % (acquirer.provider) + @api.multi + def s2s_validate(self, data): + cust_method_name = '%s_s2s_form_validate' % (self.provider) if hasattr(self, cust_method_name): method = getattr(self, cust_method_name) - return method(cr, uid, id, data, context=context) + return method(data) return True - def toggle_enviroment_value(self, cr, uid, ids, context=None): - acquirers = self.browse(cr, uid, ids, context=context) - prod_ids = [acquirer.id for acquirer in acquirers if acquirer.environment == 'prod'] - test_ids = [acquirer.id for acquirer in acquirers if acquirer.environment == 'test'] - self.write(cr, uid, prod_ids, {'environment': 'test'}, context=context) - self.write(cr, uid, test_ids, {'environment': 'prod'}, context=context) + @api.multi + def toggle_enviroment_value(self): + prod = self.filtered(lambda acquirer: acquirer.environment == 'prod') + prod.write({'environment': 'test'}) + (self-prod).write({'environment': 'prod'}) - def button_immediate_install(self, cr, uid, ids, context=None): - acquirer_id = self.browse(cr, uid, ids, context=context) - if acquirer_id.module_id and acquirer_id.module_state != 'installed': - acquirer_id.module_id.button_immediate_install() - context['active_id'] = ids[0] + @api.multi + def button_immediate_install(self): + # TDE FIXME: remove that brol + if self.module_id and self.module_state != 'installed': + self.module_id.button_immediate_install() + context = dict(self._context, active_id=self.ids[0]) return { 'view_type': 'form', 'view_mode': 'form', 'res_model': 'payment.acquirer', 'type': 'ir.actions.act_window', - 'res_id': ids[0], + 'res_id': self.ids[0], 'context': context, } -class PaymentTransaction(osv.Model): +class PaymentTransaction(models.Model): """ Transaction Model. Each specific acquirer can extend the model by adding its own fields. @@ -360,139 +359,69 @@ class PaymentTransaction(osv.Model): _order = 'id desc' _rec_name = 'reference' - def _lang_get(self, cr, uid, context=None): - return self.pool['res.lang'].get_installed(cr, uid, context=context) + @api.model + def _lang_get(self): + return self.env['res.lang'].get_installed() - def _default_partner_country_id(self, cr, uid, context=None): - comp = self.pool['res.company'].browse(cr, uid, context.get('company_id', 1), context=context) - return comp.country_id.id + @api.model + def _get_default_partner_country_id(self): + return self.env['res.company']._company_default_get('payment.transaction').country_id.id - _columns = { - 'create_date': fields.datetime('Creation Date', readonly=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'), ('form_save', 'Form with credentials storage')], - string='Type', required=True), - 'state': fields.selection( - [('draft', 'Draft'), ('pending', 'Pending'), - ('done', 'Done'), ('error', 'Error'), - ('cancel', 'Canceled') - ], 'Status', required=True, - track_visibility='onchange', copy=False), - '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'), - '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('Reference', required=True, help='Internal reference of the TX'), - 'acquirer_reference': fields.char('Acquirer 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.selection(_lang_get, 'Language'), - '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'), - 'html_3ds': fields.char('3D Secure HTML'), + create_date = fields.Datetime('Creation Date', readonly=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'), + ('form_save', 'Form with credentials storage')], 'Type', + default='form', required=True) + state = fields.Selection([ + ('draft', 'Draft'), + ('pending', 'Pending'), + ('done', 'Done'), + ('error', 'Error'), + ('cancel', 'Canceled')], 'Status', + copy=False, default='draft', required=True, track_visibility='onchange') + state_message = fields.Text('Message', help='Field used to store error and/or validation messages for information') + # payment + amount = fields.Float( + 'Amount', digits=(16, 2), required=True, track_visibility='always', + help='Amount') + 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( + 'Reference', default=lambda self: self.env['ir.sequence'].next_by_code('payment.transaction'), + required=True, help='Internal reference of the TX') + acquirer_reference = fields.Char('Acquirer 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.Selection(_lang_get, 'Language', default='en_US') + 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', default=_get_default_partner_country_id, required=True) + partner_phone = fields.Char('Phone') + html_3ds = fields.Char('3D Secure HTML') - 'callback_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)""", oldname="s2s_cb_eval"), - 'payment_token_id': fields.many2one('payment.token', 'Payment Token', domain="[('acquirer_id', '=', acquirer_id)]"), - } + callback_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)""", oldname="s2s_cb_eval") + payment_token_id = fields.Many2one('payment.token', 'Payment Token', domain="[('acquirer_id', '=', acquirer_id)]") - def _check_reference(self, cr, uid, ids, context=None): - transaction = self.browse(cr, uid, ids[0], context=context) - if transaction.state not in ['cancel', 'error']: - if self.search(cr, uid, [('reference', '=', transaction.reference), ('id', '!=', transaction.id)], context=context, count=True): - return False - return True + @api.onchange('partner_id') + def _onchange_partner_id(self): + onchange_vals = self.on_change_partner_id(self.partner_id.id).get('value', {}) + self.write(onchange_vals) - _constraints = [ - (_check_reference, 'The payment transaction reference must be unique!', ['reference', 'state']), - ] - - _defaults = { - 'type': 'form', - 'state': 'draft', - 'partner_lang': 'en_US', - 'partner_country_id': _default_partner_country_id, - 'reference': lambda s, c, u, ctx=None: s.pool['ir.sequence'].next_by_code(c, u, 'payment.transaction', context=ctx), - } - - 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)['value']) - - # 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.provider - 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('partner_country_id'), context=None) - values['fees'] = float_round(fees, 2) - - # 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)) - - # Default value of reference is - tx_id = super(PaymentTransaction, self).create(cr, uid, values, context=context) - if not values.get('reference'): - self.write(cr, uid, [tx_id], {'reference': str(tx_id)}, context=context) - return tx_id - - def write(self, cr, uid, ids, values, context=None): - Acquirer = self.pool['payment.acquirer'] - if ('acquirer_id' in values or 'amount' in values) and 'fees' not in values: - # The acquirer or the amount has changed, and the fees are not explicitely forced. Fees must be recomputed. - if isinstance(ids, (int, long)): - ids = [ids] - for txn_id in ids: - vals = dict(values) - vals['fees'] = 0.0 - transaction = self.browse(cr, uid, txn_id, context=context) - if 'acquirer_id' in values: - acquirer = Acquirer.browse(cr, uid, values['acquirer_id'], context=context) if values['acquirer_id'] else None - else: - acquirer = transaction.acquirer_id - if acquirer: - custom_method_name = '%s_compute_fees' % acquirer.provider - if hasattr(Acquirer, custom_method_name): - amount = (values['amount'] if 'amount' in values else transaction.amount) or 0.0 - currency_id = values.get('currency_id') or transaction.currency_id.id - country_id = values.get('partner_country_id') or transaction.partner_country_id.id - fees = getattr(Acquirer, custom_method_name)(cr, uid, acquirer.id, amount, currency_id, country_id, context=None) - vals['fees'] = float_round(fees, 2) - res = super(PaymentTransaction, self).write(cr, uid, txn_id, vals, context=context) - return res - return super(PaymentTransaction, self).write(cr, uid, ids, values, context=context) - - def on_change_partner_id(self, cr, uid, ids, partner_id, context=None): + @api.multi + def on_change_partner_id(self, partner_id): partner = None if partner_id: - partner = self.pool['res.partner'].browse(cr, uid, partner_id, context=context) + partner = self.env['res.partner'].browse(partner_id) return {'value': { 'partner_name': partner and partner.name or False, 'partner_lang': partner and partner.lang or 'en_US', @@ -500,15 +429,73 @@ class PaymentTransaction(osv.Model): '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 self._default_partner_country_id(cr, uid, context=context), + 'partner_country_id': partner and partner.country_id.id or self._default_partner_country_id(), 'partner_phone': partner and partner.phone or False, }} return {} - def get_next_reference(self, cr, uid, reference, context=None): + @api.constrains('reference', 'state') + def _check_reference(self): + for transaction in self.filtered(lambda tx: tx.state not in ('cancel', 'error')): + if self.search_count([('reference', '=', transaction.reference)]) != 1: + raise exceptions.ValidationError(_('The payment transaction reference must be unique!')) + return True + + @api.model + def create(self, values): + if values.get('partner_id'): # @TDENOTE: not sure + values.update(self.on_change_partner_id(values['partner_id'])['value']) + + # call custom create method if defined (i.e. ogone_create for ogone) + if values.get('acquirer_id'): + acquirer = self.env['payment.acquirer'].browse(values['acquirer_id']) + + # compute fees + custom_method_name = '%s_compute_fees' % acquirer.provider + if hasattr(acquirer, custom_method_name): + fees = getattr(acquirer, custom_method_name)( + values.get('amount', 0.0), values.get('currency_id'), values.get('partner_country_id')) + values['fees'] = float_round(fees, 2) + + # custom create + custom_method_name = '%s_create' % acquirer.provider + if hasattr(acquirer, custom_method_name): + values.update(getattr(self, custom_method_name)(values)) + + # Default value of reference is + tx = super(PaymentTransaction, self).create(values) + if not values.get('reference'): + tx.write({'reference': str(tx.id)}) + return tx + + @api.multi + def write(self, values): + if ('acquirer_id' in values or 'amount' in values) and 'fees' not in values: + # The acquirer or the amount has changed, and the fees are not explicitly forced. Fees must be recomputed. + acquirer = None + if values.get('acquirer_id'): + acquirer = self.env['payment.acquirer'].browse(values['acquirer_id']) + for tx in self: + vals = dict(values, fees=0.0) + if not acquirer: + acquirer = tx.acquirer_id + custom_method_name = '%s_compute_fees' % acquirer.provider + # TDE FIXME: shouldn't we use fee_implemented ? + if hasattr(acquirer, custom_method_name): + fees = getattr(acquirer, custom_method_name)( + (values['amount'] if 'amount' in values else tx.amount) or 0.0, + values.get('currency_id') or tx.currency_id.id, + values.get('partner_country_id') or tx.partner_country_id.id) + vals['fees'] = float_round(fees, 2) + res = super(PaymentTransaction, tx).write(vals) + return res + return super(PaymentTransaction, self).write(values) + + @api.model + def get_next_reference(self, reference): ref_suffix = 1 init_ref = reference - while self.pool['payment.transaction'].search_count(cr, openerp.SUPERUSER_ID, [('reference', '=', reference)], context=context): + while self.env['payment.transaction'].sudo().search_count([('reference', '=', reference)]): reference = init_ref + '-' + str(ref_suffix) ref_suffix += 1 return reference @@ -517,37 +504,39 @@ class PaymentTransaction(osv.Model): # FORM RELATED METHODS # -------------------------------------------------- - def render(self, cr, uid, ids, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def render(self): values = { - 'reference': tx.reference, - 'amount': tx.amount, - 'currency_id': tx.currency_id.id, - 'currency': tx.currency_id, - 'partner': tx.partner_id, - 'partner_name': tx.partner_name, - 'partner_lang': tx.partner_lang, - 'partner_email': tx.partner_email, - 'partner_zip': tx.partner_zip, - 'partner_address': tx.partner_address, - 'partner_city': tx.partner_city, - 'partner_country_id': tx.partner_country_id.id, - 'partner_country': tx.partner_country_id, - 'partner_phone': tx.partner_phone, + 'reference': self.reference, + 'amount': self.amount, + 'currency_id': self.currency_id.id, + 'currency': self.currency_id, + 'partner': self.partner_id, + 'partner_name': self.partner_name, + 'partner_lang': self.partner_lang, + 'partner_email': self.partner_email, + 'partner_zip': self.partner_zip, + 'partner_address': self.partner_address, + 'partner_city': self.partner_city, + 'partner_country_id': self.partner_country_id.id, + 'partner_country': self.partner_country_id, + 'partner_phone': self.partner_phone, 'partner_state': None, } - return tx.acquirer_id.render(None, None, None, values=values) + return self.acquirer_id.render(None, None, None, values=values) - def form_feedback(self, cr, uid, data, acquirer_name, context=None): + @api.model + def form_feedback(self, data, acquirer_name): 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) + tx = getattr(self, tx_find_method_name)(data) + # TDE TODO: form_get_invalid_parameters from model to multi 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.id], data, context=context) + invalid_parameters = getattr(tx, invalid_param_method_name)(data) if invalid_parameters: _error_message = '%s: incorrect tx data:\n' % (acquirer_name) @@ -556,9 +545,10 @@ class PaymentTransaction(osv.Model): _logger.error(_error_message) return False + # TDE TODO: form_validate from model to multi feedback_method_name = '_%s_form_validate' % acquirer_name if hasattr(self, feedback_method_name): - return getattr(self, feedback_method_name)(cr, uid, [tx.id], data, context=context) + return getattr(tx, feedback_method_name)(data) return True @@ -566,48 +556,42 @@ class PaymentTransaction(osv.Model): # SERVER2SERVER RELATED METHODS # -------------------------------------------------- - def s2s_do_transaction(self, cr, uid, ids, context=None, **kwargs): - tx = self.browse(cr, uid, ids, context=context)[0] - custom_method_name = '%s_s2s_do_transaction' % tx.acquirer_id.provider + @api.multi + def s2s_do_transaction(self, **kwargs): + custom_method_name = '%s_s2s_do_transaction' % self.acquirer_id.provider if hasattr(self, custom_method_name): - return getattr(self, custom_method_name)(cr, uid, ids, context=context, **kwargs) + return getattr(self, custom_method_name)(**kwargs) - def s2s_get_tx_status(self, cr, uid, ids, context=None): + @api.multi + def s2s_get_tx_status(self): """ Get the tx status. """ - tx = self.browse(cr, uid, ids, context=context)[0] - - invalid_param_method_name = '_%s_s2s_get_tx_status' % tx.acquirer_id.provider + invalid_param_method_name = '_%s_s2s_get_tx_status' % self.acquirer_id.provider if hasattr(self, invalid_param_method_name): - return getattr(self, invalid_param_method_name)(cr, uid, ids, context=context) + return getattr(self, invalid_param_method_name)() return True -class PaymentToken(osv.Model): +class PaymentToken(models.Model): _name = 'payment.token' _order = 'partner_id' - _columns = { - 'name': fields.char('Name', help='Name of the payment token'), - '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'), - 'payment_ids': fields.one2many('payment.transaction', 'payment_token_id', 'Payment Transactions'), - } + name = fields.Char('Name', help='Name of the payment token') + 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', default=True) + payment_ids = fields.One2many('payment.transaction', 'payment_token_id', 'Payment Transactions') - _defaults = { - 'active': True - } - - def create(self, cr, uid, values, context=None): + @api.model + def create(self, 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) + acquirer = self.env['payment.acquirer'].browse(values['acquirer_id']) # 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)) + values.update(getattr(self, custom_method_name)(values)) - return super(PaymentToken, self).create(cr, uid, values, context=context) + return super(PaymentToken, self).create(values) diff --git a/addons/payment/models/res_partner.py b/addons/payment/models/res_partner.py index 801415b3bcf..ef97997c267 100644 --- a/addons/payment/models/res_partner.py +++ b/addons/payment/models/res_partner.py @@ -1,20 +1,20 @@ -from openerp.osv import fields, osv +# coding: utf-8 + +from odoo import api, fields, models -class res_partner(osv.osv): +class res_partner(models.Model): _name = 'res.partner' _inherit = 'res.partner' - def _compute_payment_token_count(self, cr, uid, ids, field_names, arg, context=None): - result = {} - payment_data = self.pool['payment.token'].read_group( - cr, uid, [('partner_id', 'in', ids)], ['partner_id'], ['partner_id'], context=context) - mapped_data = dict([(payment['partner_id'][0], payment['partner_id_count']) for payment in payment_data]) - for partner in self.browse(cr, uid, ids, context=context): - result[partner.id] = mapped_data.get(partner.id, 0) - return result + payment_token_ids = fields.One2many('payment.token', 'partner_id', 'Payment Tokens') + payment_token_count = fields.Integer( + 'Count Payment Token', compute='_compute_payment_token_count') - _columns = { - 'payment_token_ids': fields.one2many('payment.token', 'partner_id', 'Payment Tokens'), - 'payment_token_count': fields.function(_compute_payment_token_count, string='Count Payment Token', type="integer"), - } + @api.depends('payment_token_ids') + def _compute_payment_token_count(self): + payment_data = self.env['payment.token'].read_group([ + ('partner_id', 'in', self.ids)], ['partner_id'], ['partner_id']) + mapped_data = dict([(payment['partner_id'][0], payment['partner_id_count']) for payment in payment_data]) + for partner in self: + partner.payment_token_count = mapped_data.get(partner.id, 0) diff --git a/addons/payment/security/payment_security.xml b/addons/payment/security/payment_security.xml index 4c1f3403f2a..c5ad3f62fe7 100644 --- a/addons/payment/security/payment_security.xml +++ b/addons/payment/security/payment_security.xml @@ -1,5 +1,5 @@ - + @@ -20,4 +20,4 @@ - + diff --git a/addons/payment/tests/common.py b/addons/payment/tests/common.py index e90bc8d47d2..4caa6206dc8 100644 --- a/addons/payment/tests/common.py +++ b/addons/payment/tests/common.py @@ -1,23 +1,16 @@ # -*- coding: utf-8 -*- -from openerp.tests import common +from odoo.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] + self.currency_euro = self.env['res.currency'].search([('name', '=', 'EUR')], limit=1) + self.country_belgium = self.env['res.country'].search([('code', 'like', 'BE')], limit=1) + self.country_france = self.env['res.country'].search([('code', 'like', 'FR')], limit=1) # dict partner values self.buyer_values = { @@ -28,8 +21,8 @@ class PaymentAcquirerCommon(common.TransactionCase): 'partner_phone': '0032 12 34 56 78', 'partner_city': 'Sin City', 'partner_zip': '1000', - 'partner_country': self.env['res.country'].browse(self.country_belgium_id), - 'partner_country_id': self.country_belgium_id, + 'partner_country': self.env['res.country'].browse(self.country_belgium.id), + 'partner_country_id': self.country_belgium.id, 'partner_country_name': 'Belgium', 'billing_partner_name': 'Norbert Buyer', 'billing_partner_lang': 'en_US', @@ -38,22 +31,20 @@ class PaymentAcquirerCommon(common.TransactionCase): 'billing_partner_phone': '0032 12 34 56 78', 'billing_partner_city': 'Sin City', 'billing_partner_zip': '1000', - 'billing_partner_country': self.env['res.country'].browse(self.country_belgium_id), - 'billing_partner_country_id': self.country_belgium_id, + 'billing_partner_country': self.env['res.country'].browse(self.country_belgium.id), + 'billing_partner_country_id': self.country_belgium.id, 'billing_partner_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, - } - ) + self.buyer = self.env['res.partner'].create({ + '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}) + self.buyer_id = self.buyer.id diff --git a/addons/payment/views/account_config_settings_views.xml b/addons/payment/views/account_config_settings_views.xml index 084238e72af..f636c732f60 100644 --- a/addons/payment/views/account_config_settings_views.xml +++ b/addons/payment/views/account_config_settings_views.xml @@ -1,5 +1,5 @@ - + @@ -15,4 +15,4 @@ - + diff --git a/addons/payment/views/payment_views.xml b/addons/payment/views/payment_views.xml index 3f295ffb31a..65077de10bd 100644 --- a/addons/payment/views/payment_views.xml +++ b/addons/payment/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -368,4 +368,4 @@ groups='base.group_no_one'/> - + diff --git a/addons/payment/views/res_partner_views.xml b/addons/payment/views/res_partner_views.xml index b0145045222..4708fec0c5e 100644 --- a/addons/payment/views/res_partner_views.xml +++ b/addons/payment/views/res_partner_views.xml @@ -1,5 +1,5 @@ - + @@ -18,4 +18,4 @@ - + From 622d0ae3fda460033943bcbb19df90079bc2f325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 11:51:10 +0200 Subject: [PATCH 05/22] [MOV] payment_adyen: file organization --- addons/payment_adyen/__openerp__.py | 6 +++--- .../data/{adyen.xml => payment_acquirer_data.xml} | 0 addons/payment_adyen/models/__init__.py | 2 +- addons/payment_adyen/models/{adyen.py => payment.py} | 0 .../views/{adyen.xml => payment_adyen_templates.xml} | 0 .../views/{payment_acquirer.xml => payment_views.xml} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename addons/payment_adyen/data/{adyen.xml => payment_acquirer_data.xml} (100%) rename addons/payment_adyen/models/{adyen.py => payment.py} (100%) rename addons/payment_adyen/views/{adyen.xml => payment_adyen_templates.xml} (100%) rename addons/payment_adyen/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_adyen/__openerp__.py b/addons/payment_adyen/__openerp__.py index 331ce8d124d..1e26a8808ca 100644 --- a/addons/payment_adyen/__openerp__.py +++ b/addons/payment_adyen/__openerp__.py @@ -8,9 +8,9 @@ 'description': """Adyen Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/adyen.xml', - 'views/payment_acquirer.xml', - 'data/adyen.xml', + 'views/payment_views.xml', + 'views/payment_adyen_templates.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, } diff --git a/addons/payment_adyen/data/adyen.xml b/addons/payment_adyen/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_adyen/data/adyen.xml rename to addons/payment_adyen/data/payment_acquirer_data.xml diff --git a/addons/payment_adyen/models/__init__.py b/addons/payment_adyen/models/__init__.py index fdc540ef04d..10b988e0c28 100644 --- a/addons/payment_adyen/models/__init__.py +++ b/addons/payment_adyen/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import adyen +import payment diff --git a/addons/payment_adyen/models/adyen.py b/addons/payment_adyen/models/payment.py similarity index 100% rename from addons/payment_adyen/models/adyen.py rename to addons/payment_adyen/models/payment.py diff --git a/addons/payment_adyen/views/adyen.xml b/addons/payment_adyen/views/payment_adyen_templates.xml similarity index 100% rename from addons/payment_adyen/views/adyen.xml rename to addons/payment_adyen/views/payment_adyen_templates.xml diff --git a/addons/payment_adyen/views/payment_acquirer.xml b/addons/payment_adyen/views/payment_views.xml similarity index 100% rename from addons/payment_adyen/views/payment_acquirer.xml rename to addons/payment_adyen/views/payment_views.xml From e05f4612ebbd758088bc31fd42d4b0ed2094d4fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 12:40:23 +0200 Subject: [PATCH 06/22] [MIG] payment_adyen: new API No functional change. --- addons/payment_adyen/controllers/main.py | 11 +- .../data/payment_acquirer_data.xml | 4 +- addons/payment_adyen/models/payment.py | 124 ++++++++---------- addons/payment_adyen/tests/test_adyen.py | 47 ++----- .../views/payment_adyen_templates.xml | 4 +- addons/payment_adyen/views/payment_views.xml | 4 +- 6 files changed, 74 insertions(+), 120 deletions(-) diff --git a/addons/payment_adyen/controllers/main.py b/addons/payment_adyen/controllers/main.py index de05f72d66b..b6b4331e578 100644 --- a/addons/payment_adyen/controllers/main.py +++ b/addons/payment_adyen/controllers/main.py @@ -5,8 +5,8 @@ import logging import pprint import werkzeug -from openerp import http, SUPERUSER_ID -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) @@ -20,7 +20,7 @@ class AdyenController(http.Controller): def adyen_return(self, **post): _logger.info('Beginning Adyen form_feedback with post data %s', pprint.pformat(post)) # debug if post.get('authResult') not in ['CANCELLED']: - request.registry['payment.transaction'].form_feedback(request.cr, SUPERUSER_ID, post, 'adyen', context=request.context) + request.env['payment.transaction'].sudo().form_feedback(post, 'adyen') return_url = post.pop('return_url', '') if not return_url: custom = json.loads(post.pop('merchantReturnData', '{}')) @@ -31,9 +31,8 @@ class AdyenController(http.Controller): '/payment/adyen/notification', ], type='http', auth='none', methods=['POST'], csrf=False) def adyen_notification(self, **post): - tx_id = post.get('merchantReference') and request.registry['payment.transaction'].search(request.cr, SUPERUSER_ID, [('reference', 'in', [post.get('merchantReference')])], limit=1, context=request.context) - if post.get('eventCode') in ['AUTHORISATION'] and tx_id: - tx = request.registry['payment.transaction'].browse(request.cr, SUPERUSER_ID, tx_id, context=request.context) + tx = post.get('merchantReference') and request.env['payment.transaction'].sudo().search([('reference', 'in', [post.get('merchantReference')])], limit=1) + if post.get('eventCode') in ['AUTHORISATION'] and tx: states = (post.get('merchantReference'), post.get('success'), tx.state) if (post.get('success') == 'true' and tx.state == 'done') or (post.get('success') == 'false' and tx.state in ['cancel', 'error']): _logger.info('Notification from Adyen for the reference %s: received %s, state is %s', states) diff --git a/addons/payment_adyen/data/payment_acquirer_data.xml b/addons/payment_adyen/data/payment_acquirer_data.xml index dbbc9bfd9bb..3d7ef2a1778 100644 --- a/addons/payment_adyen/data/payment_acquirer_data.xml +++ b/addons/payment_adyen/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -17,4 +17,4 @@ - + diff --git a/addons/payment_adyen/models/payment.py b/addons/payment_adyen/models/payment.py index c06ae797b0b..edf19953bab 100644 --- a/addons/payment_adyen/models/payment.py +++ b/addons/payment_adyen/models/payment.py @@ -9,46 +9,35 @@ import hmac import logging import urlparse -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_adyen.controllers.main import AdyenController -from openerp.osv import osv, fields -from openerp.tools import float_round -from openerp.tools.translate import _ +from odoo import api, fields, models, tools, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_adyen.controllers.main import AdyenController _logger = logging.getLogger(__name__) -class AcquirerAdyen(osv.Model): +class AcquirerAdyen(models.Model): _inherit = 'payment.acquirer' - def _get_adyen_urls(self, cr, uid, environment, context=None): - """ Adyen URLs + provider = fields.Selection(selection_add=[('adyen', 'Adyen')]) + adyen_merchant_account = fields.Char('Merchant Account', required_if_provider='adyen') + adyen_skin_code = fields.Char('Skin Code', required_if_provider='adyen') + adyen_skin_hmac_key = fields.Char('Skin HMAC Key', required_if_provider='adyen') - - yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple - """ + @api.model + def _get_adyen_urls(self, environment): + """ Adyen URLs: yhpp: hosted payment page: pay.shtml for single, select.shtml for multiple """ return { 'adyen_form_url': 'https://%s.adyen.com/hpp/pay.shtml' % ('live' if environment == 'prod' else environment), } - def _get_providers(self, cr, uid, context=None): - providers = super(AcquirerAdyen, self)._get_providers(cr, uid, context=context) - providers.append(['adyen', 'Adyen']) - return providers - - _columns = { - 'adyen_merchant_account': fields.char('Merchant Account', required_if_provider='adyen'), - 'adyen_skin_code': fields.char('Skin Code', required_if_provider='adyen'), - 'adyen_skin_hmac_key': fields.char('Skin HMAC Key', required_if_provider='adyen'), - } - - def _adyen_generate_merchant_sig_sha256(self, acquirer, inout, values): + @api.multi + def _adyen_generate_merchant_sig_sha256(self, inout, values): """ Generate the shasign for incoming or outgoing communications., when using the SHA-256 signature. - :param browse acquirer: the payment.acquirer browse record. It should - have a shakey in shaky out - :param string inout: 'in' (openerp contacting ogone) or 'out' (adyen - contacting openerp). In this last case only some + :param string inout: 'in' (odoo contacting ogone) or 'out' (adyen + contacting odoo). In this last case only some fields should be contained (see e-Commerce basic) :param dict values: transaction values :return string: shasign @@ -62,7 +51,7 @@ class AcquirerAdyen(osv.Model): return base64.b64encode(hm.digest()) assert inout in ('in', 'out') - assert acquirer.provider == 'adyen' + assert self.provider == 'adyen' if inout == 'in': # All the fields sent to Adyen must be included in the signature. ALL the fucking @@ -83,27 +72,26 @@ class AcquirerAdyen(osv.Model): 'pspReference', 'shopperLocale', 'skinCode', ] - hmac_key = binascii.a2b_hex(acquirer.adyen_skin_hmac_key.encode('ascii')) + hmac_key = binascii.a2b_hex(self.adyen_skin_hmac_key.encode('ascii')) raw_values = {k: values.get(k.encode('ascii'), '') for k in keys if k in values} raw_values_ordered = OrderedDict(sorted(raw_values.items(), key=lambda t: t[0])) return signParams(raw_values_ordered) - def _adyen_generate_merchant_sig(self, acquirer, inout, values): + @api.multi + def _adyen_generate_merchant_sig(self, inout, values): """ Generate the shasign for incoming or outgoing communications, when using the SHA-1 signature (deprecated by Adyen). - :param browse acquirer: the payment.acquirer browse record. It should - have a shakey in shaky out - :param string inout: 'in' (openerp contacting ogone) or 'out' (adyen - contacting openerp). In this last case only some + :param string inout: 'in' (odoo contacting ogone) or 'out' (adyen + contacting odoo). In this last case only some fields should be contained (see e-Commerce basic) :param dict values: transaction values :return string: shasign """ assert inout in ('in', 'out') - assert acquirer.provider == 'adyen' + assert self.provider == 'adyen' if inout == 'in': keys = "paymentAmount currencyCode shipBeforeDate merchantReference skinCode merchantAccount sessionValidity shopperEmail shopperReference recurringContract allowedMethods blockedMethods shopperStatement merchantReturnData billingAddressType deliveryAddressType offset".split() @@ -116,66 +104,67 @@ class AcquirerAdyen(osv.Model): return '' sign = ''.join('%s' % get_value(k) for k in keys).encode('ascii') - key = acquirer.adyen_skin_hmac_key.encode('ascii') + key = self.adyen_skin_hmac_key.encode('ascii') return base64.b64encode(hmac.new(key, sign, hashlib.sha1).digest()) - def adyen_form_generate_values(self, cr, uid, ids, values, context=None): - base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def adyen_form_generate_values(self, values): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') # tmp import datetime from dateutil import relativedelta - if acquirer.provider == 'adyen' and len(acquirer.adyen_skin_hmac_key) == 64: + if self.provider == 'adyen' and len(self.adyen_skin_hmac_key) == 64: tmp_date = datetime.datetime.today() + relativedelta.relativedelta(days=1) values.update({ 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), + 'paymentAmount': '%d' % int(tools.float_round(values['amount'], 2) * 100), 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date.strftime('%Y-%m-%d'), - 'skinCode': acquirer.adyen_skin_code, - 'merchantAccount': acquirer.adyen_merchant_account, + 'skinCode': self.adyen_skin_code, + 'merchantAccount': self.adyen_merchant_account, 'shopperLocale': values.get('partner_lang', ''), 'sessionValidity': tmp_date.isoformat('T')[:19] + "Z", 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url', '') else False, 'shopperEmail': values.get('partner_email', ''), }) - values['merchantSig'] = self._adyen_generate_merchant_sig_sha256(acquirer, 'in', values) + values['merchantSig'] = self._adyen_generate_merchant_sig_sha256('in', values) else: tmp_date = datetime.date.today() + relativedelta.relativedelta(days=1) values.update({ 'merchantReference': values['reference'], - 'paymentAmount': '%d' % int(float_round(values['amount'], 2) * 100), + 'paymentAmount': '%d' % int(tools.float_round(values['amount'], 2) * 100), 'currencyCode': values['currency'] and values['currency'].name or '', 'shipBeforeDate': tmp_date, - 'skinCode': acquirer.adyen_skin_code, - 'merchantAccount': acquirer.adyen_merchant_account, + 'skinCode': self.adyen_skin_code, + 'merchantAccount': self.adyen_merchant_account, 'shopperLocale': values.get('partner_lang'), 'sessionValidity': tmp_date, 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), 'merchantReturnData': json.dumps({'return_url': '%s' % values.pop('return_url')}) if values.get('return_url') else False, - 'merchantSig': self._adyen_generate_merchant_sig(acquirer, 'in', values), + 'merchantSig': self._adyen_generate_merchant_sig('in', values), }) return values - def adyen_get_form_action_url(self, cr, uid, ids, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - return self._get_adyen_urls(cr, uid, acquirer.environment, context=context)['adyen_form_url'] + @api.multi + def adyen_get_form_action_url(self): + return self._get_adyen_urls(self.environment)['adyen_form_url'] -class TxAdyen(osv.Model): +class TxAdyen(models.Model): _inherit = 'payment.transaction' # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- - def _adyen_form_get_tx_from_data(self, cr, uid, data, context=None): + @api.model + def _adyen_form_get_tx_from_data(self, data): reference, pspReference = data.get('merchantReference'), data.get('pspReference') if not reference or not pspReference: error_msg = _('Adyen: received data with missing reference (%s) or missing pspReference (%s)') % (reference, pspReference) @@ -183,22 +172,21 @@ class TxAdyen(osv.Model): raise ValidationError(error_msg) # find tx -> @TDENOTE use pspReference ? - tx_ids = self.pool['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) - if not tx_ids or len(tx_ids) > 1: + tx = self.env['payment.transaction'].search([('reference', '=', reference)]) + if not tx or len(tx) > 1: error_msg = _('Adyen: received data for reference %s') % (reference) - if not tx_ids: + if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) - tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) # verify shasign if len(tx.acquirer_id.adyen_skin_hmac_key) == 64: - shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig_sha256(tx.acquirer_id, 'out', data) + shasign_check = tx.acquirer_id._adyen_generate_merchant_sig_sha256('out', data) else: - shasign_check = self.pool['payment.acquirer']._adyen_generate_merchant_sig(tx.acquirer_id, 'out', data) + shasign_check = tx.acquirer_id._adyen_generate_merchant_sig('out', data) if shasign_check != data.get('merchantSig'): error_msg = _('Adyen: invalid merchantSig, received %s, computed %s') % (data.get('merchantSig'), shasign_check) _logger.warning(error_msg) @@ -206,27 +194,25 @@ class TxAdyen(osv.Model): return tx - def _adyen_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _adyen_form_get_invalid_parameters(self, data): invalid_parameters = [] # reference at acquirer: pspReference - if tx.acquirer_reference and data.get('pspReference') != tx.acquirer_reference: - invalid_parameters.append(('pspReference', data.get('pspReference'), tx.acquirer_reference)) + if self.acquirer_reference and data.get('pspReference') != self.acquirer_reference: + invalid_parameters.append(('pspReference', data.get('pspReference'), self.acquirer_reference)) # seller - if data.get('skinCode') != tx.acquirer_id.adyen_skin_code: - invalid_parameters.append(('skinCode', data.get('skinCode'), tx.acquirer_id.adyen_skin_code)) + if data.get('skinCode') != self.acquirer_id.adyen_skin_code: + invalid_parameters.append(('skinCode', data.get('skinCode'), self.acquirer_id.adyen_skin_code)) # result if not data.get('authResult'): invalid_parameters.append(('authResult', data.get('authResult'), 'something')) return invalid_parameters - def _adyen_form_validate(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _adyen_form_validate(self, data): status = data.get('authResult', 'PENDING') if status == 'AUTHORISED': - tx.write({ + self.write({ 'state': 'done', 'acquirer_reference': data.get('pspReference'), # 'date_validate': data.get('payment_date', fields.datetime.now()), @@ -234,7 +220,7 @@ class TxAdyen(osv.Model): }) return True elif status == 'PENDING': - tx.write({ + self.write({ 'state': 'pending', 'acquirer_reference': data.get('pspReference'), }) @@ -242,7 +228,7 @@ class TxAdyen(osv.Model): else: error = _('Adyen: feedback error') _logger.info(error) - tx.write({ + self.write({ 'state': 'error', 'state_message': error }) diff --git a/addons/payment_adyen/tests/test_adyen.py b/addons/payment_adyen/tests/test_adyen.py index 710bdf4e9e0..2015df6922e 100644 --- a/addons/payment_adyen/tests/test_adyen.py +++ b/addons/payment_adyen/tests/test_adyen.py @@ -3,21 +3,14 @@ from lxml import objectify import urlparse -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment.tests.common import PaymentAcquirerCommon -from openerp.addons.payment_adyen.controllers.main import AdyenController -from openerp.tools import mute_logger +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.addons.payment_adyen.controllers.main import AdyenController class AdyenCommon(PaymentAcquirerCommon): def setUp(self): super(AdyenCommon, self).setUp() - cr, uid = self.cr, self.uid - self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - - # get the adyen account - model, self.adyen_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment', 'payment_acquirer_adyen') # some CC (always use expiration date 06 / 2016, cvc 737, cid 7373 (amex)) self.amex = (('370000000000002', '7373')) @@ -36,40 +29,32 @@ class AdyenCommon(PaymentAcquirerCommon): self.mistercash = (('6703444444444449', None, 'user', 'password')) -class AdyenServer2Server(AdyenCommon): - - def test_00_tx_management(self): - cr, uid, context = self.cr, self.uid, {} - - class AdyenForm(AdyenCommon): def test_10_adyen_form_render(self): - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid things - adyen = self.payment_acquirer.browse(self.cr, self.uid, self.adyen_id, None) + adyen = self.env.ref('payment.payment_acquirer_adyen') self.assertEqual(adyen.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering # ---------------------------------------- + base_url = self.env['ir.config_parameter'].get_param('web.base.url') form_values = { 'merchantAccount': 'OpenERPCOM', 'merchantReference': 'test_ref0', 'skinCode': 'cbqYWvVL', 'paymentAmount': '1', 'currencyCode': 'EUR', - 'resURL': '%s' % urlparse.urljoin(self.base_url, AdyenController._return_url), + 'resURL': '%s' % urlparse.urljoin(base_url, AdyenController._return_url), } # render the button - res = self.payment_acquirer.render( - cr, uid, self.adyen_id, - 'test_ref0', 0.01, self.currency_euro_id, + res = adyen.render( + 'test_ref0', 0.01, self.currency_euro.id, partner_id=None, - partner_values=self.buyer_values, - context=context) + partner_values=self.buyer_values) # check form result tree = objectify.fromstring(res) @@ -82,19 +67,3 @@ class AdyenForm(AdyenCommon): form_values[form_input.get('name')], 'adyen: wrong value for input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')]) ) - - # @mute_logger('openerp.addons.payment_adyen.models.adyen', 'ValidationError') - # def test_20_paypal_form_management(self): - # cr, uid, context = self.cr, self.uid, {} - # # be sure not to do stupid things - # adyen = self.payment_acquirer.browse(self.cr, self.uid, self.adyen_id, None) - # self.assertEqual(adyen.env, 'test', 'test without test env') - -# {'authResult': u'AUTHORISED', -# 'merchantReference': u'SO014', -# 'merchantReturnData': u'return_url=/shop/payment/validate', -# 'merchantSig': u'GaLRO8aMHFaQX3gQ5BVP/YETzeA=', -# 'paymentMethod': u'visa', -# 'pspReference': u'8813859935907337', -# 'shopperLocale': u'en_US', -# 'skinCode': u'cbqYWvVL'} \ No newline at end of file diff --git a/addons/payment_adyen/views/payment_adyen_templates.xml b/addons/payment_adyen/views/payment_adyen_templates.xml index ff92d21dce2..4b8d178ef69 100644 --- a/addons/payment_adyen/views/payment_adyen_templates.xml +++ b/addons/payment_adyen/views/payment_adyen_templates.xml @@ -1,5 +1,5 @@ - + - + diff --git a/addons/payment_adyen/views/payment_views.xml b/addons/payment_adyen/views/payment_views.xml index fde4880a9fa..6914a28ff35 100644 --- a/addons/payment_adyen/views/payment_views.xml +++ b/addons/payment_adyen/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -19,4 +19,4 @@ - + From ad93be5df913668e46c5567b7e5d80670e09470d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 13:12:11 +0200 Subject: [PATCH 07/22] [MOV] payment_authorize: file organization --- addons/payment_authorize/__openerp__.py | 7 +++---- .../data/{authorize.xml => payment_acquirer_data.xml} | 0 addons/payment_authorize/models/__init__.py | 2 +- .../payment_authorize/models/{authorize.py => payment.py} | 0 .../views/payment_authorize_template.xml | 8 -------- .../{authorize.xml => payment_authorize_templates.xml} | 6 +++++- .../views/{payment_acquirer.xml => payment_views.xml} | 0 7 files changed, 9 insertions(+), 14 deletions(-) rename addons/payment_authorize/data/{authorize.xml => payment_acquirer_data.xml} (100%) rename addons/payment_authorize/models/{authorize.py => payment.py} (100%) delete mode 100644 addons/payment_authorize/views/payment_authorize_template.xml rename addons/payment_authorize/views/{authorize.xml => payment_authorize_templates.xml} (93%) rename addons/payment_authorize/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_authorize/__openerp__.py b/addons/payment_authorize/__openerp__.py index 8670588ce2a..4a8eafa8b73 100644 --- a/addons/payment_authorize/__openerp__.py +++ b/addons/payment_authorize/__openerp__.py @@ -8,10 +8,9 @@ 'description': """Authorize.Net Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/authorize.xml', - 'views/payment_acquirer.xml', - 'data/authorize.xml', - 'views/payment_authorize_template.xml', + 'views/payment_views.xml', + 'views/payment_authorize_templates.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, } diff --git a/addons/payment_authorize/data/authorize.xml b/addons/payment_authorize/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_authorize/data/authorize.xml rename to addons/payment_authorize/data/payment_acquirer_data.xml diff --git a/addons/payment_authorize/models/__init__.py b/addons/payment_authorize/models/__init__.py index 92e55eeff24..10b988e0c28 100644 --- a/addons/payment_authorize/models/__init__.py +++ b/addons/payment_authorize/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import authorize +import payment diff --git a/addons/payment_authorize/models/authorize.py b/addons/payment_authorize/models/payment.py similarity index 100% rename from addons/payment_authorize/models/authorize.py rename to addons/payment_authorize/models/payment.py diff --git a/addons/payment_authorize/views/payment_authorize_template.xml b/addons/payment_authorize/views/payment_authorize_template.xml deleted file mode 100644 index 18b2ab7368f..00000000000 --- a/addons/payment_authorize/views/payment_authorize_template.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/addons/payment_authorize/views/authorize.xml b/addons/payment_authorize/views/payment_authorize_templates.xml similarity index 93% rename from addons/payment_authorize/views/authorize.xml rename to addons/payment_authorize/views/payment_authorize_templates.xml index 04767c36ec1..9c39fcd1c8e 100644 --- a/addons/payment_authorize/views/authorize.xml +++ b/addons/payment_authorize/views/payment_authorize_templates.xml @@ -1,7 +1,6 @@ - + diff --git a/addons/payment_authorize/views/payment_acquirer.xml b/addons/payment_authorize/views/payment_views.xml similarity index 100% rename from addons/payment_authorize/views/payment_acquirer.xml rename to addons/payment_authorize/views/payment_views.xml From 76d124299b99dd2bfe0594b3ce9600bda7a56689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 13:13:42 +0200 Subject: [PATCH 08/22] [CLN] payment_authorize: cleaning and guidelines As this module is already in new API only small linting is performed. --- addons/payment_authorize/controllers/main.py | 4 +- addons/payment_authorize/models/payment.py | 21 +++---- addons/payment_authorize/tests/__init__.py | 3 +- .../payment_authorize/tests/test_authorize.py | 56 +++++++++---------- 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/addons/payment_authorize/controllers/main.py b/addons/payment_authorize/controllers/main.py index 93b3d105f9a..aec2aa1f777 100644 --- a/addons/payment_authorize/controllers/main.py +++ b/addons/payment_authorize/controllers/main.py @@ -3,8 +3,8 @@ import pprint import logging import urlparse -from openerp import http -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py index b9a16ee37fb..b7488937e61 100644 --- a/addons/payment_authorize/models/payment.py +++ b/addons/payment_authorize/models/payment.py @@ -6,10 +6,10 @@ import logging import time import urlparse -from openerp import api, fields, models -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_authorize.controllers.main import AuthorizeController -from openerp.tools.float_utils import float_compare +from odoo import api, fields, models +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_authorize.controllers.main import AuthorizeController +from odoo.tools.float_utils import float_compare _logger = logging.getLogger(__name__) @@ -17,6 +17,10 @@ _logger = logging.getLogger(__name__) class PaymentAcquirerAuthorize(models.Model): _inherit = 'payment.acquirer' + provider = fields.Selection(selection_add=[('authorize', 'Authorize.Net')]) + authorize_login = fields.Char(string='API Login Id', required_if_provider='authorize') + authorize_transaction_key = fields.Char(string='API Transaction Key', required_if_provider='authorize') + def _get_authorize_urls(self, environment): """ Authorize URLs """ if environment == 'prod': @@ -24,15 +28,6 @@ class PaymentAcquirerAuthorize(models.Model): else: return {'authorize_form_url': 'https://test.authorize.net/gateway/transact.dll'} - @api.model - def _get_providers(self): - providers = super(PaymentAcquirerAuthorize, self)._get_providers() - providers.append(['authorize', 'Authorize.Net']) - return providers - - authorize_login = fields.Char(string='API Login Id', required_if_provider='authorize') - authorize_transaction_key = fields.Char(string='API Transaction Key', required_if_provider='authorize') - def _authorize_generate_hashing(self, values): data = '^'.join([ values['x_login'], diff --git a/addons/payment_authorize/tests/__init__.py b/addons/payment_authorize/tests/__init__.py index 32a44646439..10e174a320e 100644 --- a/addons/payment_authorize/tests/__init__.py +++ b/addons/payment_authorize/tests/__init__.py @@ -1,4 +1,3 @@ # -*- coding: utf-8 -*- -from openerp.addons.payment_authorize.tests import test_authorize - +from . import test_authorize diff --git a/addons/payment_authorize/tests/test_authorize.py b/addons/payment_authorize/tests/test_authorize.py index fa477692f4d..464a794d481 100644 --- a/addons/payment_authorize/tests/test_authorize.py +++ b/addons/payment_authorize/tests/test_authorize.py @@ -6,28 +6,27 @@ import time import urlparse from lxml import objectify -import openerp -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment.tests.common import PaymentAcquirerCommon -from openerp.addons.payment_authorize.controllers.main import AuthorizeController -from openerp.tools import mute_logger +import odoo +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.addons.payment_authorize.controllers.main import AuthorizeController +from odoo.tools import mute_logger -@openerp.tests.common.at_install(True) -@openerp.tests.common.post_install(True) +@odoo.tests.common.at_install(True) +@odoo.tests.common.post_install(True) class AuthorizeCommon(PaymentAcquirerCommon): def setUp(self): super(AuthorizeCommon, self).setUp() - self.base_url = self.env['ir.config_parameter'].get_param('web.base.url') # authorize only support USD in test environment self.currency_usd = self.env['res.currency'].search([('name', '=', 'USD')], limit=1)[0] # get the authorize account - model, self.authorize_id = self.env['ir.model.data'].get_object_reference('payment', 'payment_acquirer_authorize') + self.authorize = self.env.ref('payment.payment_acquirer_authorize') -@openerp.tests.common.at_install(True) -@openerp.tests.common.post_install(True) +@odoo.tests.common.at_install(True) +@odoo.tests.common.post_install(True) class AuthorizeForm(AuthorizeCommon): def _authorize_generate_hashing(self, values): @@ -40,25 +39,25 @@ class AuthorizeForm(AuthorizeCommon): return hmac.new(str(values['x_trans_key']), data, hashlib.md5).hexdigest() def test_10_Authorize_form_render(self): - authorize = self.env['payment.acquirer'].browse(self.authorize_id) - self.assertEqual(authorize.environment, 'test', 'test without test environment') + self.assertEqual(self.authorize.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering # ---------------------------------------- + base_url = self.env['ir.config_parameter'].get_param('web.base.url') form_values = { - 'x_login': authorize.authorize_login, - 'x_trans_key': authorize.authorize_transaction_key, + 'x_login': self.authorize.authorize_login, + 'x_trans_key': self.authorize.authorize_transaction_key, 'x_amount': '320.0', 'x_show_form': 'PAYMENT_FORM', 'x_type': 'AUTH_CAPTURE', 'x_method': 'CC', - 'x_fp_sequence': '%s%s' % (authorize.id, int(time.time())), + 'x_fp_sequence': '%s%s' % (self.authorize.id, int(time.time())), 'x_version': '3.1', 'x_relay_response': 'TRUE', 'x_fp_timestamp': str(int(time.time())), - 'x_relay_url': '%s' % urlparse.urljoin(self.base_url, AuthorizeController._return_url), - 'x_cancel_url': '%s' % urlparse.urljoin(self.base_url, AuthorizeController._cancel_url), + 'x_relay_url': '%s' % urlparse.urljoin(base_url, AuthorizeController._return_url), + 'x_cancel_url': '%s' % urlparse.urljoin(base_url, AuthorizeController._cancel_url), 'return_url': None, 'x_currency_code': 'USD', 'x_invoice_num': 'SO004', @@ -84,10 +83,7 @@ class AuthorizeForm(AuthorizeCommon): form_values['x_fp_hash'] = self._authorize_generate_hashing(form_values) # render the button - cr, uid, context = self.env.cr, self.env.uid, {} - res = self.payment_acquirer.render( - cr, uid, self.authorize_id, 'SO004', 320.0, self.currency_usd.id, - values=self.buyer_values, context=context) + res = self.authorize.render('SO004', 320.0, self.currency_usd.id, values=self.buyer_values) # check form result tree = objectify.fromstring(res) self.assertEqual(tree.get('action'), 'https://test.authorize.net/gateway/transact.dll', 'Authorize: wrong form POST url') @@ -101,12 +97,10 @@ class AuthorizeForm(AuthorizeCommon): 'Authorize: wrong value for input %s: received %s instead of %s' % (values[1], values[2], form_values[values[1]]) ) - @mute_logger('openerp.addons.payment_authorize.models.authorize', 'ValidationError') + @mute_logger('openerp.addons.payment_authorize.models.payment', 'ValidationError') def test_20_authorize_form_management(self): - cr, uid, context = self.env.cr, self.env.uid, {} # be sure not to do stupid thing - authorize = self.env['payment.acquirer'].browse(self.authorize_id) - self.assertEqual(authorize.environment, 'test', 'test without test environment') + self.assertEqual(self.authorize.environment, 'test', 'test without test environment') # typical data posted by authorize after client has successfully paid authorize_post_data = { @@ -157,17 +151,17 @@ class AuthorizeForm(AuthorizeCommon): # should raise error about unknown tx with self.assertRaises(ValidationError): - self.payment_transaction.form_feedback(cr, uid, authorize_post_data, 'authorize', context=context) + self.env['payment.transaction'].form_feedback(authorize_post_data, 'authorize') tx = self.env['payment.transaction'].create({ 'amount': 320.0, - 'acquirer_id': self.authorize_id, + 'acquirer_id': self.authorize.id, 'currency_id': self.currency_usd.id, 'reference': 'SO004', 'partner_name': 'Norbert Buyer', - 'partner_country_id': self.country_france_id}) + 'partner_country_id': self.country_france.id}) # validate it - self.payment_transaction.form_feedback(cr, uid, authorize_post_data, 'authorize', context=context) + self.env['payment.transaction'].form_feedback(authorize_post_data, 'authorize') # check state self.assertEqual(tx.state, 'done', 'Authorize: validation did not put tx into done state') self.assertEqual(tx.acquirer_reference, authorize_post_data.get('x_trans_id'), 'Authorize: validation did not update tx payid') @@ -177,6 +171,6 @@ class AuthorizeForm(AuthorizeCommon): # simulate an error authorize_post_data['x_response_code'] = u'3' - self.payment_transaction.form_feedback(cr, uid, authorize_post_data, 'authorize', context=context) + self.env['payment.transaction'].form_feedback(authorize_post_data, 'authorize') # check state self.assertEqual(tx.state, 'error', 'Authorize: erroneous validation did not put tx into error state') From fd4b9bd74d682e8047b08361b5c13e09461b5eb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 13:16:31 +0200 Subject: [PATCH 09/22] [MOV] payment_buckaroo: file organization --- addons/payment_buckaroo/__openerp__.py | 6 +++--- .../data/{buckaroo.xml => payment_acquirer_data.xml} | 0 addons/payment_buckaroo/models/__init__.py | 2 +- addons/payment_buckaroo/models/{buckaroo.py => payment.py} | 0 .../views/{buckaroo.xml => payment_buckaroo_templates.xml} | 0 .../views/{payment_acquirer.xml => payment_views.xml} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename addons/payment_buckaroo/data/{buckaroo.xml => payment_acquirer_data.xml} (100%) rename addons/payment_buckaroo/models/{buckaroo.py => payment.py} (100%) rename addons/payment_buckaroo/views/{buckaroo.xml => payment_buckaroo_templates.xml} (100%) rename addons/payment_buckaroo/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_buckaroo/__openerp__.py b/addons/payment_buckaroo/__openerp__.py index 4fd749fe9e7..3e56a451c52 100644 --- a/addons/payment_buckaroo/__openerp__.py +++ b/addons/payment_buckaroo/__openerp__.py @@ -8,9 +8,9 @@ 'description': """Buckaroo Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/buckaroo.xml', - 'views/payment_acquirer.xml', - 'data/buckaroo.xml', + 'views/payment_views.xml', + 'views/payment_buckaroo_templates.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, } diff --git a/addons/payment_buckaroo/data/buckaroo.xml b/addons/payment_buckaroo/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_buckaroo/data/buckaroo.xml rename to addons/payment_buckaroo/data/payment_acquirer_data.xml diff --git a/addons/payment_buckaroo/models/__init__.py b/addons/payment_buckaroo/models/__init__.py index 7e1780a0059..10b988e0c28 100644 --- a/addons/payment_buckaroo/models/__init__.py +++ b/addons/payment_buckaroo/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import buckaroo +import payment diff --git a/addons/payment_buckaroo/models/buckaroo.py b/addons/payment_buckaroo/models/payment.py similarity index 100% rename from addons/payment_buckaroo/models/buckaroo.py rename to addons/payment_buckaroo/models/payment.py diff --git a/addons/payment_buckaroo/views/buckaroo.xml b/addons/payment_buckaroo/views/payment_buckaroo_templates.xml similarity index 100% rename from addons/payment_buckaroo/views/buckaroo.xml rename to addons/payment_buckaroo/views/payment_buckaroo_templates.xml diff --git a/addons/payment_buckaroo/views/payment_acquirer.xml b/addons/payment_buckaroo/views/payment_views.xml similarity index 100% rename from addons/payment_buckaroo/views/payment_acquirer.xml rename to addons/payment_buckaroo/views/payment_views.xml From 14d761b98662e45d18701a5807065c9984473764 Mon Sep 17 00:00:00 2001 From: Rutul Raval Date: Tue, 5 Jul 2016 13:26:12 +0200 Subject: [PATCH 10/22] [MIG] payment_buckaroo: new API No functional change. --- addons/payment_buckaroo/controllers/main.py | 8 +- .../data/payment_acquirer_data.xml | 4 +- addons/payment_buckaroo/models/payment.py | 107 ++++++++---------- .../payment_buckaroo/tests/test_buckaroo.py | 107 ++++++++---------- .../views/payment_buckaroo_templates.xml | 4 +- .../payment_buckaroo/views/payment_views.xml | 4 +- 6 files changed, 105 insertions(+), 129 deletions(-) diff --git a/addons/payment_buckaroo/controllers/main.py b/addons/payment_buckaroo/controllers/main.py index 515d8cf2d1e..e5e61f6e8f3 100644 --- a/addons/payment_buckaroo/controllers/main.py +++ b/addons/payment_buckaroo/controllers/main.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -import json + import logging import pprint import werkzeug -from openerp import http, SUPERUSER_ID -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) @@ -25,7 +25,7 @@ class BuckarooController(http.Controller): def buckaroo_return(self, **post): """ Buckaroo.""" _logger.info('Buckaroo: entering form_feedback with post data %s', pprint.pformat(post)) # debug - request.registry['payment.transaction'].form_feedback(request.cr, SUPERUSER_ID, post, 'buckaroo', context=request.context) + request.env['payment.transaction'].sudo().form_feedback(post, 'buckaroo') post = dict((key.upper(), value) for key, value in post.items()) return_url = post.get('ADD_RETURNDATA') or '/' return werkzeug.utils.redirect(return_url) diff --git a/addons/payment_buckaroo/data/payment_acquirer_data.xml b/addons/payment_buckaroo/data/payment_acquirer_data.xml index 57e28818212..8019baf3593 100644 --- a/addons/payment_buckaroo/data/payment_acquirer_data.xml +++ b/addons/payment_buckaroo/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -16,4 +16,4 @@ - + diff --git a/addons/payment_buckaroo/models/payment.py b/addons/payment_buckaroo/models/payment.py index cb9914ee222..82b532c9e15 100644 --- a/addons/payment_buckaroo/models/payment.py +++ b/addons/payment_buckaroo/models/payment.py @@ -4,11 +4,10 @@ import logging import urllib import urlparse -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_buckaroo.controllers.main import BuckarooController -from openerp.osv import osv, fields -from openerp.tools.float_utils import float_compare -from openerp.tools.translate import _ +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_buckaroo.controllers.main import BuckarooController +from odoo.tools.float_utils import float_compare _logger = logging.getLogger(__name__) @@ -23,10 +22,14 @@ def normalize_keys_upper(data): return dict((key.upper(), val) for key, val in data.items()) -class AcquirerBuckaroo(osv.Model): +class AcquirerBuckaroo(models.Model): _inherit = 'payment.acquirer' - def _get_buckaroo_urls(self, cr, uid, environment, context=None): + provider = fields.Selection(selection_add=[('buckaroo', 'Buckaroo')]) + brq_websitekey = fields.Char('WebsiteKey', required_if_provider='buckaroo') + brq_secretkey = fields.Char('SecretKey', required_if_provider='buckaroo') + + def _get_buckaroo_urls(self, environment): """ Buckaroo URLs """ if environment == 'prod': @@ -38,29 +41,19 @@ class AcquirerBuckaroo(osv.Model): 'buckaroo_form_url': 'https://testcheckout.buckaroo.nl/html/', } - def _get_providers(self, cr, uid, context=None): - providers = super(AcquirerBuckaroo, self)._get_providers(cr, uid, context=context) - providers.append(['buckaroo', 'Buckaroo']) - return providers - - _columns = { - 'brq_websitekey': fields.char('WebsiteKey', required_if_provider='buckaroo'), - 'brq_secretkey': fields.char('SecretKey', required_if_provider='buckaroo'), - } - - def _buckaroo_generate_digital_sign(self, acquirer, inout, values): + def _buckaroo_generate_digital_sign(self, inout, values): """ Generate the shasign for incoming or outgoing communications. :param browse acquirer: the payment.acquirer browse record. It should have a shakey in shaky out - :param string inout: 'in' (openerp contacting buckaroo) or 'out' (buckaroo - contacting openerp). + :param string inout: 'in' (odoo contacting buckaroo) or 'out' (buckaroo + contacting odoo). :param dict values: transaction values :return string: shasign """ assert inout in ('in', 'out') - assert acquirer.provider == 'buckaroo' + assert self.provider == 'buckaroo' keys = "add_returndata Brq_amount Brq_culture Brq_currency Brq_invoicenumber Brq_return Brq_returncancel Brq_returnerror Brq_returnreject brq_test Brq_websitekey".split() @@ -81,25 +74,25 @@ class AcquirerBuckaroo(osv.Model): items = sorted(values.items(), key=lambda (x, y): x.lower()) sign = ''.join('%s=%s' % (k, urllib.unquote_plus(v)) for k, v in items) else: - sign = ''.join('%s=%s' % (k,get_value(k)) for k in keys) - #Add the pre-shared secret key at the end of the signature - sign = sign + acquirer.brq_secretkey + sign = ''.join('%s=%s' % (k, get_value(k)) for k in keys) + # Add the pre-shared secret key at the end of the signature + sign = sign + self.brq_secretkey if isinstance(sign, str): # TODO: remove me? should not be used sign = urlparse.parse_qsl(sign) shasign = sha1(sign.encode('utf-8')).hexdigest() return shasign - def buckaroo_form_generate_values(self, cr, uid, ids, values, context=None): - base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def buckaroo_form_generate_values(self, values): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') buckaroo_tx_values = dict(values) buckaroo_tx_values.update({ - 'Brq_websitekey': acquirer.brq_websitekey, + 'Brq_websitekey': self.brq_websitekey, 'Brq_amount': values['amount'], 'Brq_currency': values['currency'] and values['currency'].name or '', 'Brq_invoicenumber': values['reference'], - 'brq_test': False if acquirer.environment == 'prod' else True, + 'brq_test': False if self.environment == 'prod' else True, 'Brq_return': '%s' % urlparse.urljoin(base_url, BuckarooController._return_url), 'Brq_returncancel': '%s' % urlparse.urljoin(base_url, BuckarooController._cancel_url), 'Brq_returnerror': '%s' % urlparse.urljoin(base_url, BuckarooController._exception_url), @@ -107,14 +100,15 @@ class AcquirerBuckaroo(osv.Model): 'Brq_culture': (values.get('partner_lang') or 'en_US').replace('_', '-'), 'add_returndata': buckaroo_tx_values.pop('return_url', '') or '', }) - buckaroo_tx_values['Brq_signature'] = self._buckaroo_generate_digital_sign(acquirer, 'in', buckaroo_tx_values) + buckaroo_tx_values['Brq_signature'] = self._buckaroo_generate_digital_sign('in', buckaroo_tx_values) return buckaroo_tx_values - def buckaroo_get_form_action_url(self, cr, uid, ids, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - return self._get_buckaroo_urls(cr, uid, acquirer.environment, context=context)['buckaroo_form_url'] + @api.multi + def buckaroo_get_form_action_url(self): + return self._get_buckaroo_urls(self.environment)['buckaroo_form_url'] -class TxBuckaroo(osv.Model): + +class TxBuckaroo(models.Model): _inherit = 'payment.transaction' # buckaroo status @@ -124,12 +118,12 @@ class TxBuckaroo(osv.Model): _buckaroo_error_tx_status = [490, 491, 492] _buckaroo_reject_tx_status = [690] - # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- - def _buckaroo_form_get_tx_from_data(self, cr, uid, data, context=None): + @api.model + def _buckaroo_form_get_tx_from_data(self, data): """ Given a data dict coming from buckaroo, verify it and find the related transaction record. """ origin_data = dict(data) @@ -140,58 +134,55 @@ class TxBuckaroo(osv.Model): _logger.info(error_msg) raise ValidationError(error_msg) - tx_ids = self.search(cr, uid, [('reference', '=', reference)], context=context) - if not tx_ids or len(tx_ids) > 1: + tx = self.search([('reference', '=', reference)]) + if not tx or len(tx) > 1: error_msg = _('Buckaroo: received data for reference %s') % (reference) - if not tx_ids: + if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) - tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) - #verify shasign - shasign_check = self.pool['payment.acquirer']._buckaroo_generate_digital_sign(tx.acquirer_id, 'out', origin_data) + # verify shasign + shasign_check = tx.acquirer_id._buckaroo_generate_digital_sign('out', origin_data) if shasign_check.upper() != shasign.upper(): error_msg = _('Buckaroo: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data) _logger.info(error_msg) raise ValidationError(error_msg) - return tx + return tx - def _buckaroo_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _buckaroo_form_get_invalid_parameters(self, data): invalid_parameters = [] data = normalize_keys_upper(data) - if tx.acquirer_reference and data.get('BRQ_TRANSACTIONS') != tx.acquirer_reference: - invalid_parameters.append(('Transaction Id', data.get('BRQ_TRANSACTIONS'), tx.acquirer_reference)) + if self.acquirer_reference and data.get('BRQ_TRANSACTIONS') != self.acquirer_reference: + invalid_parameters.append(('Transaction Id', data.get('BRQ_TRANSACTIONS'), self.acquirer_reference)) # check what is buyed - if float_compare(float(data.get('BRQ_AMOUNT', '0.0')), tx.amount, 2) != 0: - invalid_parameters.append(('Amount', data.get('BRQ_AMOUNT'), '%.2f' % tx.amount)) - if data.get('BRQ_CURRENCY') != tx.currency_id.name: - invalid_parameters.append(('Currency', data.get('BRQ_CURRENCY'), tx.currency_id.name)) + if float_compare(float(data.get('BRQ_AMOUNT', '0.0')), self.amount, 2) != 0: + invalid_parameters.append(('Amount', data.get('BRQ_AMOUNT'), '%.2f' % self.amount)) + if data.get('BRQ_CURRENCY') != self.currency_id.name: + invalid_parameters.append(('Currency', data.get('BRQ_CURRENCY'), self.currency_id.name)) return invalid_parameters - def _buckaroo_form_validate(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _buckaroo_form_validate(self, data): data = normalize_keys_upper(data) - status_code = int(data.get('BRQ_STATUSCODE','0')) + status_code = int(data.get('BRQ_STATUSCODE', '0')) if status_code in self._buckaroo_valid_tx_status: - tx.write({ + self.write({ 'state': 'done', 'acquirer_reference': data.get('BRQ_TRANSACTIONS'), }) return True elif status_code in self._buckaroo_pending_tx_status: - tx.write({ + self.write({ 'state': 'pending', 'acquirer_reference': data.get('BRQ_TRANSACTIONS'), }) return True elif status_code in self._buckaroo_cancel_tx_status: - tx.write({ + self.write({ 'state': 'cancel', 'acquirer_reference': data.get('BRQ_TRANSACTIONS'), }) @@ -199,7 +190,7 @@ class TxBuckaroo(osv.Model): else: error = 'Buckaroo: feedback error' _logger.info(error) - tx.write({ + self.write({ 'state': 'error', 'state_message': error, 'acquirer_reference': data.get('BRQ_TRANSACTIONS'), diff --git a/addons/payment_buckaroo/tests/test_buckaroo.py b/addons/payment_buckaroo/tests/test_buckaroo.py index 9f8c311b64a..447e6c62529 100644 --- a/addons/payment_buckaroo/tests/test_buckaroo.py +++ b/addons/payment_buckaroo/tests/test_buckaroo.py @@ -3,35 +3,31 @@ from lxml import objectify import urlparse -import openerp -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment.tests.common import PaymentAcquirerCommon -from openerp.addons.payment_buckaroo.controllers.main import BuckarooController -from openerp.tools import mute_logger +import odoo +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.addons.payment_buckaroo.controllers.main import BuckarooController +from odoo.tools import mute_logger -@openerp.tests.common.at_install(False) -@openerp.tests.common.post_install(False) +@odoo.tests.common.at_install(False) +@odoo.tests.common.post_install(False) class BuckarooCommon(PaymentAcquirerCommon): def setUp(self): super(BuckarooCommon, self).setUp() - cr, uid = self.cr, self.uid - self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - # get the buckaroo account - model, self.buckaroo_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment', 'payment_acquirer_buckaroo') + self.buckaroo = self.env.ref('payment.payment_acquirer_buckaroo') -@openerp.tests.common.at_install(False) -@openerp.tests.common.post_install(False) +@odoo.tests.common.at_install(False) +@odoo.tests.common.post_install(False) class BuckarooForm(BuckarooCommon): def test_10_Buckaroo_form_render(self): - cr, uid, context = self.cr, self.uid, {} + base_url = self.env['ir.config_parameter'].get_param('web.base.url') # be sure not to do stupid things - buckaroo = self.payment_acquirer.browse(self.cr, self.uid, self.buckaroo_id, None) - self.assertEqual(buckaroo.environment, 'test', 'test without test environment') + self.assertEqual(self.buckaroo.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering @@ -39,26 +35,24 @@ class BuckarooForm(BuckarooCommon): form_values = { 'add_returndata': None, - 'Brq_websitekey': buckaroo.brq_websitekey, + 'Brq_websitekey': self.buckaroo.brq_websitekey, 'Brq_amount': '2240.0', 'Brq_currency': 'EUR', 'Brq_invoicenumber': 'SO004', 'Brq_signature': '1b8c10074c622d965272a91a9e88b5b3777d2474', # update me 'brq_test': 'True', - 'Brq_return': '%s' % urlparse.urljoin(self.base_url, BuckarooController._return_url), - 'Brq_returncancel': '%s' % urlparse.urljoin(self.base_url, BuckarooController._cancel_url), - 'Brq_returnerror': '%s' % urlparse.urljoin(self.base_url, BuckarooController._exception_url), - 'Brq_returnreject': '%s' % urlparse.urljoin(self.base_url, BuckarooController._reject_url), + 'Brq_return': '%s' % urlparse.urljoin(base_url, BuckarooController._return_url), + 'Brq_returncancel': '%s' % urlparse.urljoin(base_url, BuckarooController._cancel_url), + 'Brq_returnerror': '%s' % urlparse.urljoin(base_url, BuckarooController._exception_url), + 'Brq_returnreject': '%s' % urlparse.urljoin(base_url, BuckarooController._reject_url), 'Brq_culture': 'en-US', } # render the button - res = self.payment_acquirer.render( - cr, uid, self.buckaroo_id, - 'SO004', 2240.0, self.currency_euro_id, + res = self.buckaroo.render( + 'SO004', 2240.0, self.currency_euro.id, partner_id=None, - partner_values=self.buyer_values, - context=context) + partner_values=self.buyer_values) # check form result tree = objectify.fromstring(res) @@ -77,24 +71,20 @@ class BuckarooForm(BuckarooCommon): # ---------------------------------------- # create a new draft tx - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 2240.0, - 'acquirer_id': self.buckaroo_id, - 'currency_id': self.currency_euro_id, - 'reference': 'SO004', - 'partner_id': self.buyer_id, - }, context=context - ) + tx = self.env['payment.transaction'].create({ + 'amount': 2240.0, + 'acquirer_id': self.buckaroo.id, + 'currency_id': self.currency_euro.id, + 'reference': 'SO004', + 'partner_id': self.buyer_id, + }) # render the button - res = self.payment_acquirer.render( - cr, uid, self.buckaroo_id, + res = self.buckaroo_id.render( 'should_be_erased', 2240.0, self.currency_euro, - tx_id=tx_id, + tx_id=tx.id, partner_id=None, - partner_values=self.buyer_values, - context=context) + partner_values=self.buyer_values) # check form result tree = objectify.fromstring(res) @@ -108,12 +98,10 @@ class BuckarooForm(BuckarooCommon): 'Buckaroo: wrong value for form input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')]) ) - @mute_logger('openerp.addons.payment_buckaroo.models.buckaroo', 'ValidationError') + @mute_logger('openerp.addons.payment_buckaroo.models.payment', 'ValidationError') def test_20_buckaroo_form_management(self): - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid thing - buckaroo = self.payment_acquirer.browse(self.cr, self.uid, self.buckaroo_id, None) - self.assertEqual(buckaroo.environment, 'test', 'test without test environment') + self.assertEqual(self.buckaroo.environment, 'test', 'test without test environment') # typical data posted by buckaroo after client has successfully paid buckaroo_post_data = { @@ -125,7 +113,7 @@ class BuckarooForm(BuckarooCommon): 'brq_payment': u'573311D081B04069BD6336001611DBD4', 'BRQ_PAYMENT_METHOD': u'paypal', 'BRQ_SERVICE_PAYPAL_PAYERCOUNTRY': u'NL', - 'BRQ_SERVICE_PAYPAL_PAYEREMAIL': u'fhe@openerp.com', + 'BRQ_SERVICE_PAYPAL_PAYEREMAIL': u'fhe@odoo.com', 'BRQ_SERVICE_PAYPAL_PAYERFIRSTNAME': u'Jan', 'BRQ_SERVICE_PAYPAL_PAYERLASTNAME': u'Tester', 'BRQ_SERVICE_PAYPAL_PAYERMIDDLENAME': u'de', @@ -142,22 +130,19 @@ class BuckarooForm(BuckarooCommon): # should raise error about unknown tx with self.assertRaises(ValidationError): - self.payment_transaction.form_feedback(cr, uid, buckaroo_post_data, 'buckaroo', context=context) + self.env['payment.transaction'].form_feedback(buckaroo_post_data, 'buckaroo') + + tx = self.env['payment.transaction'].create({ + 'amount': 2240.0, + 'acquirer_id': self.buckaroo.id, + 'currency_id': self.currency_euro.id, + 'reference': 'SO004', + 'partner_name': 'Norbert Buyer', + 'partner_country_id': self.country_france.id}) - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 2240.0, - 'acquirer_id': self.buckaroo_id, - 'currency_id': self.currency_euro_id, - 'reference': 'SO004', - 'partner_name': 'Norbert Buyer', - 'partner_country_id': self.country_france_id, - }, context=context - ) # validate it - self.payment_transaction.form_feedback(cr, uid, buckaroo_post_data, 'buckaroo', context=context) + tx.form_feedback(buckaroo_post_data, 'buckaroo') # check state - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertEqual(tx.state, 'done', 'Buckaroo: validation did not put tx into done state') self.assertEqual(tx.acquirer_reference, buckaroo_post_data.get('BRQ_TRANSACTIONS'), 'Buckaroo: validation did not update tx payid') @@ -167,12 +152,12 @@ class BuckarooForm(BuckarooCommon): # now buckaroo post is ok: try to modify the SHASIGN buckaroo_post_data['BRQ_SIGNATURE'] = '54d928810e343acf5fb0c3ee75fd747ff159ef7a' with self.assertRaises(ValidationError): - self.payment_transaction.form_feedback(cr, uid, buckaroo_post_data, 'buckaroo', context=context) + tx.form_feedback(buckaroo_post_data, 'buckaroo') # simulate an error buckaroo_post_data['BRQ_STATUSCODE'] = 2 buckaroo_post_data['BRQ_SIGNATURE'] = '4164b52adb1e6a2221d3d8a39d8c3e18a9ecb90b' - self.payment_transaction.form_feedback(cr, uid, buckaroo_post_data, 'buckaroo', context=context) + tx.form_feedback(buckaroo_post_data, 'buckaroo') + # check state - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertEqual(tx.state, 'error', 'Buckaroo: erroneous validation did not put tx into error state') diff --git a/addons/payment_buckaroo/views/payment_buckaroo_templates.xml b/addons/payment_buckaroo/views/payment_buckaroo_templates.xml index 0ce58e6850a..820f923eb21 100644 --- a/addons/payment_buckaroo/views/payment_buckaroo_templates.xml +++ b/addons/payment_buckaroo/views/payment_buckaroo_templates.xml @@ -1,5 +1,5 @@ - + - + diff --git a/addons/payment_buckaroo/views/payment_views.xml b/addons/payment_buckaroo/views/payment_views.xml index e9cecec2309..db49146c410 100644 --- a/addons/payment_buckaroo/views/payment_views.xml +++ b/addons/payment_buckaroo/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -18,4 +18,4 @@ - + From b6c5b3a6b7ad33c679c821e6dd223500289f84df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 14:55:11 +0200 Subject: [PATCH 11/22] [MOV] payment_ogone: file organization --- addons/payment_ogone/__openerp__.py | 6 +++--- .../data/{ogone.xml => payment_acquirer_data.xml} | 0 addons/payment_ogone/models/__init__.py | 2 +- addons/payment_ogone/models/{ogone.py => payment.py} | 0 .../views/{ogone.xml => payment_ogone_templates.xml} | 0 .../views/{payment_acquirer.xml => payment_views.xml} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename addons/payment_ogone/data/{ogone.xml => payment_acquirer_data.xml} (100%) rename addons/payment_ogone/models/{ogone.py => payment.py} (100%) rename addons/payment_ogone/views/{ogone.xml => payment_ogone_templates.xml} (100%) rename addons/payment_ogone/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_ogone/__openerp__.py b/addons/payment_ogone/__openerp__.py index 3a4a807c983..1fd1ee9c55b 100644 --- a/addons/payment_ogone/__openerp__.py +++ b/addons/payment_ogone/__openerp__.py @@ -8,9 +8,9 @@ 'description': """Ogone Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/ogone.xml', - 'views/payment_acquirer.xml', - 'data/ogone.xml', + 'views/payment_views.xml', + 'views/payment_ogone_templates.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, } diff --git a/addons/payment_ogone/data/ogone.xml b/addons/payment_ogone/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_ogone/data/ogone.xml rename to addons/payment_ogone/data/payment_acquirer_data.xml diff --git a/addons/payment_ogone/models/__init__.py b/addons/payment_ogone/models/__init__.py index 349d8f668e8..10b988e0c28 100644 --- a/addons/payment_ogone/models/__init__.py +++ b/addons/payment_ogone/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import ogone +import payment diff --git a/addons/payment_ogone/models/ogone.py b/addons/payment_ogone/models/payment.py similarity index 100% rename from addons/payment_ogone/models/ogone.py rename to addons/payment_ogone/models/payment.py diff --git a/addons/payment_ogone/views/ogone.xml b/addons/payment_ogone/views/payment_ogone_templates.xml similarity index 100% rename from addons/payment_ogone/views/ogone.xml rename to addons/payment_ogone/views/payment_ogone_templates.xml diff --git a/addons/payment_ogone/views/payment_acquirer.xml b/addons/payment_ogone/views/payment_views.xml similarity index 100% rename from addons/payment_ogone/views/payment_acquirer.xml rename to addons/payment_ogone/views/payment_views.xml From 4ef937ed38b65ce0257bd61fb3d194b54518eadb Mon Sep 17 00:00:00 2001 From: Ravi Gadhia Date: Tue, 5 Jul 2016 14:15:58 +0200 Subject: [PATCH 12/22] [MIG] payment_ogone: new API No functional change. --- addons/payment_ogone/controllers/main.py | 25 +- .../data/payment_acquirer_data.xml | 4 +- addons/payment_ogone/models/payment.py | 248 ++++++++---------- addons/payment_ogone/tests/test_ogone.py | 149 ++++------- .../views/payment_ogone_templates.xml | 4 +- addons/payment_ogone/views/payment_views.xml | 4 +- 6 files changed, 179 insertions(+), 255 deletions(-) diff --git a/addons/payment_ogone/controllers/main.py b/addons/payment_ogone/controllers/main.py index 3137f619d2d..b17198cfe40 100644 --- a/addons/payment_ogone/controllers/main.py +++ b/addons/payment_ogone/controllers/main.py @@ -3,9 +3,9 @@ import logging import pprint import werkzeug -from openerp import http, SUPERUSER_ID -from openerp.http import request -from openerp.addons.payment.models.payment_acquirer import ValidationError +from odoo import http +from odoo.http import request +from odoo.addons.payment.models.payment_acquirer import ValidationError _logger = logging.getLogger(__name__) @@ -25,33 +25,24 @@ class OgoneController(http.Controller): def ogone_form_feedback(self, **post): """ Ogone contacts using GET, at least for accept """ _logger.info('Ogone: 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, 'ogone', context=context) + request.env['payment.transaction'].sudo().form_feedback(post, 'ogone') return werkzeug.utils.redirect(post.pop('return_url', '/')) @http.route(['/payment/ogone/s2s/create_json'], type='json', auth='public', csrf=False) def ogone_s2s_create_json(self, **kwargs): - data = kwargs - acquirer_id = int(data.get('acquirer_id')) - acquirer = request.env['payment.acquirer'].browse(acquirer_id) - new_id = acquirer.s2s_process(data) + new_id = request.env['payment.acquirer'].browse(int(kwargs.get('acquirer_id'))).s2s_process(kwargs) return new_id @http.route(['/payment/ogone/s2s/create'], type='http', auth='public', methods=["POST"], csrf=False) def ogone_s2s_create(self, **post): - acquirer_id = int(post.get('acquirer_id')) - acquirer = request.env['payment.acquirer'].browse(acquirer_id) - acquirer.s2s_process(post) + request.env['payment.acquirer'].browse(int(post.get('acquirer_id'))).s2s_process(post) return werkzeug.utils.redirect(post.get('return_url', '/')) @http.route(['/payment/ogone/s2s/feedback'], auth='none', csrf=False) def feedback(self, **kwargs): - cr, uid, context = request.cr, SUPERUSER_ID, request.context - payment = request.registry.get('payment.transaction') try: - tx = payment._ogone_form_get_tx_from_data(cr, uid, kwargs, context=context) - payment._ogone_s2s_validate(tx) + tx = request.env['payment.transaction']._ogone_form_get_tx_from_data(kwargs) + tx._ogone_s2s_validate() except ValidationError: return 'ko' - return 'ok' diff --git a/addons/payment_ogone/data/payment_acquirer_data.xml b/addons/payment_ogone/data/payment_acquirer_data.xml index 308d13e70b9..a78ea78107a 100644 --- a/addons/payment_ogone/data/payment_acquirer_data.xml +++ b/addons/payment_ogone/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -20,4 +20,4 @@ - + diff --git a/addons/payment_ogone/models/payment.py b/addons/payment_ogone/models/payment.py index 54aee7f7f70..7e37479b5e6 100644 --- a/addons/payment_ogone/models/payment.py +++ b/addons/payment_ogone/models/payment.py @@ -1,39 +1,45 @@ # coding: utf-8 -import datetime from hashlib import sha1 -import logging from lxml import etree, objectify -from openerp.tools.translate import _ from pprint import pformat -import time from unicodedata import normalize from urllib import urlencode + +import datetime +import logging +import time import urllib2 import urlparse -from openerp import SUPERUSER_ID -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_ogone.controllers.main import OgoneController -from openerp.addons.payment_ogone.data import ogone -from openerp.osv import osv, fields -from openerp.tools import float_round, DEFAULT_SERVER_DATE_FORMAT -from openerp.tools.float_utils import float_compare, float_repr -from openerp.tools.safe_eval import safe_eval +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_ogone.controllers.main import OgoneController +from odoo.addons.payment_ogone.data import ogone +from odoo.tools import float_round, DEFAULT_SERVER_DATE_FORMAT +from odoo.tools.float_utils import float_compare, float_repr +from odoo.tools.safe_eval import safe_eval _logger = logging.getLogger(__name__) -class PaymentAcquirerOgone(osv.Model): +class PaymentAcquirerOgone(models.Model): _inherit = 'payment.acquirer' - def _get_ogone_urls(self, cr, uid, environment, context=None): + provider = fields.Selection(selection_add=[('ogone', 'Ogone')]) + ogone_pspid = fields.Char('PSPID', required_if_provider='ogone') + ogone_userid = fields.Char('API User ID', required_if_provider='ogone') + ogone_password = fields.Char('API User Password', required_if_provider='ogone') + ogone_shakey_in = fields.Char('SHA Key IN', size=32, required_if_provider='ogone') + ogone_shakey_out = fields.Char('SHA Key OUT', size=32, required_if_provider='ogone') + ogone_alias_usage = fields.Char('Alias Usage', help="""If you want to use Ogone Aliases, + this default Alias Usage will be presented to + the customer as the reason you want to + keep his payment data""") + + def _get_ogone_urls(self, environment): """ Ogone URLS: - - - standard order: POST address for form-based - - @TDETODO: complete me - """ + - standard order: POST address for form-based """ return { 'ogone_standard_order_url': 'https://secure.ogone.com/ncol/%s/orderstandard_utf8.asp' % (environment,), 'ogone_direct_order_url': 'https://secure.ogone.com/ncol/%s/orderdirect_utf8.asp' % (environment,), @@ -41,38 +47,19 @@ class PaymentAcquirerOgone(osv.Model): 'ogone_afu_agree_url': 'https://secure.ogone.com/ncol/%s/AFU_agree.asp' % (environment,), } - def _get_providers(self, cr, uid, context=None): - providers = super(PaymentAcquirerOgone, self)._get_providers(cr, uid, context=context) - providers.append(['ogone', 'Ogone']) - return providers - - _columns = { - 'ogone_pspid': fields.char('PSPID', required_if_provider='ogone'), - 'ogone_userid': fields.char('API User ID', required_if_provider='ogone'), - 'ogone_password': fields.char('API User Password', required_if_provider='ogone'), - 'ogone_shakey_in': fields.char('SHA Key IN', size=32, required_if_provider='ogone'), - 'ogone_shakey_out': fields.char('SHA Key OUT', size=32, required_if_provider='ogone'), - 'ogone_alias_usage': fields.char('Alias Usage', help="""If you want to use Ogone Aliases, - this default Alias Usage will be presented to - the customer as the reason you want to - keep his payment data""") - } - - def _ogone_generate_shasign(self, acquirer, inout, values): + def _ogone_generate_shasign(self, inout, values): """ Generate the shasign for incoming or outgoing communications. - :param browse acquirer: the payment.acquirer browse record. It should - have a shakey in shaky out - :param string inout: 'in' (openerp contacting ogone) or 'out' (ogone - contacting openerp). In this last case only some + :param string inout: 'in' (odoo contacting ogone) or 'out' (ogone + contacting odoo). In this last case only some fields should be contained (see e-Commerce basic) :param dict values: transaction values :return string: shasign """ assert inout in ('in', 'out') - assert acquirer.provider == 'ogone' - key = getattr(acquirer, 'ogone_shakey_' + inout) + assert self.provider == 'ogone' + key = getattr(self, 'ogone_shakey_' + inout) def filter_key(key): if inout == 'in': @@ -147,12 +134,11 @@ class PaymentAcquirerOgone(osv.Model): shasign = sha1(sign).hexdigest() return shasign - def ogone_form_generate_values(self, cr, uid, ids, values, context=None): - base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url') - acquirer = self.browse(cr, uid, ids, context=context)[0] + def ogone_form_generate_values(self, values): + base_url = self.env['ir.config_parameter'].get_param('web.base.url') ogone_tx_values = dict(values) temp_ogone_tx_values = { - 'PSPID': acquirer.ogone_pspid, + 'PSPID': self.ogone_pspid, 'ORDERID': values['reference'], 'AMOUNT': float_repr(float_round(values['amount'], 2) * 100, 0), 'CURRENCY': values['currency'] and values['currency'].name or '', @@ -173,20 +159,18 @@ class PaymentAcquirerOgone(osv.Model): if values.get('type') == 'form_save': temp_ogone_tx_values.update({ 'ALIAS': 'ODOO-NEW-ALIAS-%s' % time.time(), # something unique, - 'ALIASUSAGE': values.get('alias_usage') or acquirer.ogone_alias_usage, + 'ALIASUSAGE': values.get('alias_usage') or self.ogone_alias_usage, }) - shasign = self._ogone_generate_shasign(acquirer, 'in', temp_ogone_tx_values) + shasign = self._ogone_generate_shasign('in', temp_ogone_tx_values) temp_ogone_tx_values['SHASIGN'] = shasign ogone_tx_values.update(temp_ogone_tx_values) return ogone_tx_values - def ogone_get_form_action_url(self, cr, uid, ids, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - return self._get_ogone_urls(cr, uid, acquirer.environment, context=context)['ogone_standard_order_url'] + def ogone_get_form_action_url(self): + return self._get_ogone_urls(self.environment)['ogone_standard_order_url'] - def ogone_s2s_form_validate(self, cr, uid, ids, data, context=None): + def ogone_s2s_form_validate(self, data): error = dict() - error_message = [] mandatory_fields = ["cc_number", "cc_cvc", "cc_holder_name", "cc_expiry", "cc_brand"] # Validation @@ -196,7 +180,7 @@ class PaymentAcquirerOgone(osv.Model): return False if error else True - def ogone_s2s_form_process(self, cr, uid, data, context=None): + def ogone_s2s_form_process(self, data): values = { 'cc_number': data.get('cc_number'), 'cc_cvc': int(data.get('cc_cvc')), @@ -206,11 +190,11 @@ class PaymentAcquirerOgone(osv.Model): 'acquirer_id': int(data.get('acquirer_id')), 'partner_id': int(data.get('partner_id')) } - pm_id = self.pool['payment.token'].create(cr, SUPERUSER_ID, values, context=context) + pm_id = self.env['payment.token'].sudo().create(values) return pm_id -class PaymentTxOgone(osv.Model): +class PaymentTxOgone(models.Model): _inherit = 'payment.transaction' # ogone status _ogone_valid_tx_status = [5, 9] @@ -222,7 +206,8 @@ class PaymentTxOgone(osv.Model): # FORM RELATED METHODS # -------------------------------------------------- - def _ogone_form_get_tx_from_data(self, cr, uid, data, context=None): + @api.model + def _ogone_form_get_tx_from_data(self, data): """ Given a data dict coming from ogone, verify it and find the related transaction record. Create a payment token if an alias is returned.""" reference, pay_id, shasign, alias = data.get('orderID'), data.get('PAYID'), data.get('SHASIGN'), data.get('ALIAS') @@ -232,19 +217,18 @@ class PaymentTxOgone(osv.Model): raise ValidationError(error_msg) # find tx -> @TDENOTE use paytid ? - tx_ids = self.search(cr, uid, [('reference', '=', reference)], context=context) - if not tx_ids or len(tx_ids) > 1: + tx = self.search([('reference', '=', reference)]) + if not tx or len(tx) > 1: error_msg = _('Ogone: received data for reference %s') % (reference) - if not tx_ids: + if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) - tx = self.pool['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) # verify shasign - shasign_check = self.pool['payment.acquirer']._ogone_generate_shasign(tx.acquirer_id, 'out', data) + shasign_check = tx.acquirer_id._ogone_generate_shasign('out', data) if shasign_check.upper() != shasign.upper(): error_msg = _('Ogone: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data) _logger.info(error_msg) @@ -255,39 +239,36 @@ class PaymentTxOgone(osv.Model): # alias was created on ogone server, store it if alias: - method_obj = self.pool['payment.token'] + Method = self.env['payment.token'] domain = [('acquirer_ref', '=', alias)] cardholder = data.get('CN') - if not method_obj.search_count(cr, uid, domain, context=context): + if not Method.search_count(domain): _logger.info('Ogone: saving alias %s for partner %s' % (data.get('CARDNO'), tx.partner_id)) - ref = method_obj.create(cr, uid, {'name': data.get('CARDNO') + (' - ' + cardholder if cardholder else ''), - 'partner_id': tx.partner_id.id, - 'acquirer_id': tx.acquirer_id.id, - 'acquirer_ref': alias - }) + ref = Method.create({'name': data.get('CARDNO') + (' - ' + cardholder if cardholder else ''), + 'partner_id': tx.partner_id.id, + 'acquirer_id': tx.acquirer_id.id, + 'acquirer_ref': alias}) tx.write({'payment_token_id': ref}) return tx - def _ogone_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _ogone_form_get_invalid_parameters(self, data): invalid_parameters = [] # TODO: txn_id: should be false at draft, set afterwards, and verified with txn details - if tx.acquirer_reference and data.get('PAYID') != tx.acquirer_reference: - invalid_parameters.append(('PAYID', data.get('PAYID'), tx.acquirer_reference)) + if self.acquirer_reference and data.get('PAYID') != self.acquirer_reference: + invalid_parameters.append(('PAYID', data.get('PAYID'), self.acquirer_reference)) # check what is bought - if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: - invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) - if data.get('currency') != tx.currency_id.name: - invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name)) + if float_compare(float(data.get('amount', '0.0')), self.amount, 2) != 0: + invalid_parameters.append(('amount', data.get('amount'), '%.2f' % self.amount)) + if data.get('currency') != self.currency_id.name: + invalid_parameters.append(('currency', data.get('currency'), self.currency_id.name)) return invalid_parameters - def _ogone_form_validate(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] - if tx.state == 'done': - _logger.info('Ogone: trying to validate an already validated tx (ref %s)', tx.reference) + def _ogone_form_validate(self, data): + if self.state == 'done': + _logger.info('Ogone: trying to validate an already validated tx (ref %s)', self.reference) return True status = int(data.get('STATUS', '0')) @@ -297,25 +278,25 @@ class PaymentTxOgone(osv.Model): 'date_validate': datetime.datetime.strptime(data['TRXDATE'], '%m/%d/%y').strftime(DEFAULT_SERVER_DATE_FORMAT), 'acquirer_reference': data['PAYID'], } - if data.get('ALIAS') and tx.partner_id and tx.type == 'form_save' and not tx.payment_token_id: - pm_id = self.pool['payment.token'].create(cr, uid, { - 'partner_id': tx.partner_id.id, - 'acquirer_id': tx.acquirer_id.id, + if data.get('ALIAS') and self.partner_id and self.type == 'form_save' and not self.payment_token_id: + pm = self.env['payment.token'].create({ + 'partner_id': self.partner_id.id, + 'acquirer_id': self.acquirer_id.id, 'acquirer_ref': data.get('ALIAS'), 'name': '%s - %s' % (data.get('CARDNO'), data.get('CN')) - }, context=context) - vals.update(payment_token_id=pm_id) - tx.write(vals) - if tx.callback_eval: - safe_eval(tx.callback_eval, {'self': tx}) + }) + vals.update(payment_token_id=pm.id) + self.write(vals) + if self.callback_eval: + safe_eval(self.callback_eval, {'self': self}) return True elif status in self._ogone_cancel_tx_status: - tx.write({ + self.write({ 'state': 'cancel', 'acquirer_reference': data.get('PAYID'), }) elif status in self._ogone_pending_tx_status or status in self._ogone_wait_tx_status: - tx.write({ + self.write({ 'state': 'pending', 'acquirer_reference': data.get('PAYID'), }) @@ -326,7 +307,7 @@ class PaymentTxOgone(osv.Model): 'error_msg': ogone.OGONE_ERROR_MAP.get(data.get('NCERROR')), } _logger.info(error) - tx.write({ + self.write({ 'state': 'error', 'state_message': error, 'acquirer_reference': data.get('PAYID'), @@ -336,29 +317,29 @@ class PaymentTxOgone(osv.Model): # -------------------------------------------------- # S2S RELATED METHODS # -------------------------------------------------- - def ogone_s2s_do_transaction(self, cr, uid, ids, context=None, **kwargs): + + def ogone_s2s_do_transaction(self, **kwargs): # TODO: create tx with s2s type - tx = self.browse(cr, uid, ids, context=context)[0] - account = tx.acquirer_id - reference = tx.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%y%m%d_%H%M%S'), tx.partner_id.id) + account = self.acquirer_id + reference = self.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%y%m%d_%H%M%S'), self.partner_id.id) data = { 'PSPID': account.ogone_pspid, 'USERID': account.ogone_userid, 'PSWD': account.ogone_password, 'ORDERID': reference, - 'AMOUNT': long(tx.amount * 100), - 'CURRENCY': tx.currency_id.name, + 'AMOUNT': long(self.amount * 100), + 'CURRENCY': self.currency_id.name, 'OPERATION': 'SAL', 'ECI': 2, # Recurring (from MOTO) - 'ALIAS': tx.payment_token_id.acquirer_ref, + 'ALIAS': self.payment_token_id.acquirer_ref, 'RTIMEOUT': 30, } if kwargs.get('3d_secure'): data.update({ 'FLAG3D': 'Y', - 'LANGUAGE': tx.partner_id.lang or 'en_US', + 'LANGUAGE': self.partner_id.lang or 'en_US', }) for url in 'accept decline exception'.split(): @@ -368,9 +349,9 @@ class PaymentTxOgone(osv.Model): key = '{0}URL'.format(url).upper() data[key] = val - data['SHASIGN'] = self.pool['payment.acquirer']._ogone_generate_shasign(tx.acquirer_id, 'in', data) + data['SHASIGN'] = self.acquirer_id._ogone_generate_shasign('in', data) - direct_order_url = 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % (tx.acquirer_id.environment) + direct_order_url = 'https://secure.ogone.com/ncol/%s/orderdirect.asp' % (self.acquirer_id.environment) _logger.debug("Ogone data %s", pformat(data)) request = urllib2.Request(direct_order_url, urlencode(data)) @@ -384,53 +365,51 @@ class PaymentTxOgone(osv.Model): _logger.exception('Invalid xml response from ogone') raise - return self._ogone_s2s_validate_tree(tx, tree) + return self._ogone_s2s_validate_tree(tree) - def _ogone_s2s_validate(self, cr, uid, ids, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] - tree = self._ogone_s2s_get_tx_status(tx) - return self._ogone_s2s_validate_tree(tx, tree) + def _ogone_s2s_validate(self): + tree = self._ogone_s2s_get_tx_status() + return self._ogone_s2s_validate_tree(tree) - def _ogone_s2s_validate_tree(self, cr, uid, ids, tree, tries=2, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] - if tx.state not in ('draft', 'pending'): - _logger.info('Ogone: trying to validate an already validated tx (ref %s)', tx.reference) + def _ogone_s2s_validate_tree(self, tree, tries=2): + if self.state not in ('draft', 'pending'): + _logger.info('Ogone: trying to validate an already validated tx (ref %s)', self.reference) return True status = int(tree.get('STATUS') or 0) if status in self._ogone_valid_tx_status: - tx.write({ + self.write({ 'state': 'done', 'date_validate': datetime.date.today().strftime(DEFAULT_SERVER_DATE_FORMAT), 'acquirer_reference': tree.get('PAYID'), }) - if tree.get('ALIAS') and tx.partner_id and tx.type == 'form_save' and not tx.payment_token_id: - pm = tx.env['payment.token'].create({ - 'partner_id': tx.partner_id.id, - 'acquirer_id': tx.acquirer_id.id, + if tree.get('ALIAS') and self.partner_id and self.type == 'form_save' and not self.payment_token_id: + pm = self.env['payment.token'].create({ + 'partner_id': self.partner_id.id, + 'acquirer_id': self.acquirer_id.id, 'acquirer_ref': tree.get('ALIAS'), 'name': tree.get('CARDNO'), }) - tx.write({'payment_token_id': pm.id}) - if tx.callback_eval: - safe_eval(tx.callback_eval, {'self': tx}) + self.write({'payment_token_id': pm.id}) + if self.callback_eval: + safe_eval(self.callback_eval, {'self': self}) return True elif status in self._ogone_cancel_tx_status: - tx.write({ + self.write({ 'state': 'cancel', 'acquirer_reference': tree.get('PAYID'), }) elif status in self._ogone_pending_tx_status: - tx.write({ + self.write({ 'state': 'pending', 'acquirer_reference': tree.get('PAYID'), 'html_3ds': str(tree.HTML_ANSWER).decode('base64') }) elif (not status or status in self._ogone_wait_tx_status) and tries > 0: time.sleep(500) - tx.write({'acquirer_reference': tree.get('PAYID')}) - tree = self._ogone_s2s_get_tx_status(tx) - return self._ogone_s2s_validate_tree(tx, tree, tries - 1) + self.write({'acquirer_reference': tree.get('PAYID')}) + tree = self._ogone_s2s_get_tx_status(self) + return self._ogone_s2s_validate_tree(self, tree, tries - 1) else: error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % { 'error_str': tree.get('NCERRORPLUS'), @@ -438,26 +417,25 @@ class PaymentTxOgone(osv.Model): 'error_msg': ogone.OGONE_ERROR_MAP.get(tree.get('NCERROR')), } _logger.info(error) - tx.write({ + self.write({ 'state': 'error', 'state_message': error, 'acquirer_reference': tree.get('PAYID'), }) return False - def _ogone_s2s_get_tx_status(self, cr, uid, ids, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] - account = tx.acquirer_id + def _ogone_s2s_get_tx_status(self): + account = self.acquirer_id #reference = tx.reference or "ODOO-%s-%s" % (datetime.datetime.now().strftime('%Y%m%d_%H%M%S'), tx.partner_id.id) data = { - 'PAYID': tx.acquirer_reference, + 'PAYID': self.acquirer_reference, 'PSPID': account.ogone_pspid, 'USERID': account.ogone_userid, 'PSWD': account.ogone_password, } - query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (tx.acquirer_id.environment) + query_direct_url = 'https://secure.ogone.com/ncol/%s/querydirect.asp' % (self.acquirer_id.environment) _logger.debug("Ogone data %s", pformat(data)) request = urllib2.Request(query_direct_url, urlencode(data)) @@ -474,14 +452,14 @@ class PaymentTxOgone(osv.Model): return tree -class PaymentToken(osv.Model): +class PaymentToken(models.Model): _inherit = 'payment.token' - def ogone_create(self, cr, uid, values, context=None): + def ogone_create(self, values): if values.get('cc_number'): # create a alias via batch values['cc_number'] = values['cc_number'].replace(' ', '') - acquirer = self.pool['payment.acquirer'].browse(cr, uid, values['acquirer_id']) + acquirer = self.env['payment.acquirer'].browse(values['acquirer_id']) alias = 'ODOO-NEW-ALIAS-%s' % time.time() expiry = str(values['cc_expiry'][:2]) + str(values['cc_expiry'][-2:]) diff --git a/addons/payment_ogone/tests/test_ogone.py b/addons/payment_ogone/tests/test_ogone.py index 81f09873fa4..2651b00fefe 100644 --- a/addons/payment_ogone/tests/test_ogone.py +++ b/addons/payment_ogone/tests/test_ogone.py @@ -4,27 +4,23 @@ from lxml import objectify import time import urlparse -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment.tests.common import PaymentAcquirerCommon -from openerp.addons.payment_ogone.controllers.main import OgoneController -from openerp.tools import mute_logger +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.addons.payment_ogone.controllers.main import OgoneController +from odoo.tools import mute_logger class OgonePayment(PaymentAcquirerCommon): def setUp(self): super(OgonePayment, self).setUp() - cr, uid = self.cr, self.uid - self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - # get the adyen account - model, self.ogone_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment', 'payment_acquirer_ogone') + self.ogone = self.env.ref('payment.payment_acquirer_ogone') def test_10_ogone_form_render(self): - cr, uid, context = self.cr, self.uid, {} + base_url = self.env['ir.config_parameter'].get_param('web.base.url') # be sure not to do stupid thing - ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None) - self.assertEqual(ogone.environment, 'test', 'test without test environment') + self.assertEqual(self.ogone.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering + shasign @@ -44,19 +40,17 @@ class OgonePayment(PaymentAcquirerCommon): 'OWNERTOWN': 'Sin City', 'OWNERTELNO': '0032 12 34 56 78', 'SHASIGN': '815f67b8ff70d234ffcf437c13a9fa7f807044cc', - 'ACCEPTURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._accept_url), - 'DECLINEURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._decline_url), - 'EXCEPTIONURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._exception_url), - 'CANCELURL': '%s' % urlparse.urljoin(self.base_url, OgoneController._cancel_url), + 'ACCEPTURL': '%s' % urlparse.urljoin(base_url, OgoneController._accept_url), + 'DECLINEURL': '%s' % urlparse.urljoin(base_url, OgoneController._decline_url), + 'EXCEPTIONURL': '%s' % urlparse.urljoin(base_url, OgoneController._exception_url), + 'CANCELURL': '%s' % urlparse.urljoin(base_url, OgoneController._cancel_url), } # render the button - res = self.payment_acquirer.render( - cr, uid, self.ogone_id, - 'test_ref0', 0.01, self.currency_euro_id, + res = self.ogone.render( + 'test_ref0', 0.01, self.currency_euro.id, partner_id=None, - partner_values=self.buyer_values, - context=context) + partner_values=self.buyer_values) # check form result tree = objectify.fromstring(res) @@ -75,23 +69,18 @@ class OgonePayment(PaymentAcquirerCommon): # ---------------------------------------- # create a new draft tx - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 0.01, - 'acquirer_id': self.ogone_id, - 'currency_id': self.currency_euro_id, - 'reference': 'test_ref0', - 'partner_id': self.buyer_id, - }, context=context - ) + tx = self.env['payment.transaction'].create({ + 'amount': 0.01, + 'acquirer_id': self.ogone.id, + 'currency_id': self.currency_euro.id, + 'reference': 'test_ref0', + 'partner_id': self.buyer_id}) # render the button - res = self.payment_acquirer.render( - cr, uid, self.ogone_id, + res = self.ogone.render( 'should_be_erased', 0.01, self.currency_euro, - tx_id=tx_id, + tx_id=tx.id, partner_id=None, - partner_values=self.buyer_values, - context=context) + partner_values=self.buyer_values) # check form result tree = objectify.fromstring(res) @@ -105,12 +94,10 @@ class OgonePayment(PaymentAcquirerCommon): 'ogone: wrong value for form input %s: received %s instead of %s' % (form_input.get('name'), form_input.get('value'), form_values[form_input.get('name')]) ) - @mute_logger('openerp.addons.payment_ogone.models.ogone', 'ValidationError') + @mute_logger('openerp.addons.payment_ogone.models.payment', 'ValidationError') def test_20_ogone_form_management(self): - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid thing - ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None) - self.assertEqual(ogone.environment, 'test', 'test without test environment') + self.assertEqual(self.ogone.environment, 'test', 'test without test environment') # typical data posted by ogone after client has successfully paid ogone_post_data = { @@ -133,23 +120,19 @@ class OgonePayment(PaymentAcquirerCommon): # should raise error about unknown tx with self.assertRaises(ValidationError): - self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + self.env['payment.transaction'].form_feedback(ogone_post_data) # create tx - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 1.95, - 'acquirer_id': self.ogone_id, - 'currency_id': self.currency_euro_id, - 'reference': 'test_ref_2', - 'partner_name': 'Norbert Buyer', - 'partner_country_id': self.country_france_id, - }, context=context - ) + tx = self.env['payment.transaction'].create({ + 'amount': 1.95, + 'acquirer_id': self.ogone.id, + 'currency_id': self.currency_euro.id, + 'reference': 'test_ref_2', + 'partner_name': 'Norbert Buyer', + 'partner_country_id': self.country_france.id}) # validate it - self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + tx.form_feedback(ogone_post_data) # check state - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertEqual(tx.state, 'done', 'ogone: validation did not put tx into done state') self.assertEqual(tx.ogone_payid, ogone_post_data.get('PAYID'), 'ogone: validation did not update tx payid') @@ -159,67 +142,39 @@ class OgonePayment(PaymentAcquirerCommon): # now ogone post is ok: try to modify the SHASIGN ogone_post_data['SHASIGN'] = 'a4c16bae286317b82edb49188d3399249a784691' with self.assertRaises(ValidationError): - self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + tx.form_feedback(ogone_post_data) # simulate an error ogone_post_data['STATUS'] = 2 ogone_post_data['SHASIGN'] = 'a4c16bae286317b82edb49188d3399249a784691' - self.payment_transaction.ogone_form_feedback(cr, uid, ogone_post_data, context=context) + tx.form_feedback(ogone_post_data) # check state - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertEqual(tx.state, 'error', 'ogone: erroneous validation did not put tx into error state') def test_30_ogone_s2s(self): test_ref = 'test_ref_%.15f' % time.time() - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid thing - ogone = self.payment_acquirer.browse(self.cr, self.uid, self.ogone_id, None) - self.assertEqual(ogone.environment, 'test', 'test without test environment') + self.assertEqual(self.ogone.environment, 'test', 'test without test environment') # create a new draft tx - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 0.01, - 'acquirer_id': self.ogone_id, - 'currency_id': self.currency_euro_id, - 'reference': test_ref, - 'partner_id': self.buyer_id, - 'type': 'server2server', - }, context=context - ) + tx = self.env['payment.transaction'].create({ + 'amount': 0.01, + 'acquirer_id': self.ogone.id, + 'currency_id': self.currency_euro.id, + 'reference': test_ref, + 'partner_id': self.buyer_id, + 'type': 'server2server', + }) # create an alias - res = self.payment_transaction.ogone_s2s_create_alias( - cr, uid, tx_id, { - 'expiry_date_mm': '01', - 'expiry_date_yy': '2015', - 'holder_name': 'Norbert Poilu', - 'number': '4000000000000002', - 'brand': 'VISA', - }, context=context) + res = tx.ogone_s2s_create_alias({ + 'expiry_date_mm': '01', + 'expiry_date_yy': '2015', + 'holder_name': 'Norbert Poilu', + 'number': '4000000000000002', + 'brand': 'VISA'}) # check an alias is set, containing at least OPENERP - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertIn('OPENERP', tx.partner_reference, 'ogone: wrong partner reference after creating an alias') - res = self.payment_transaction.ogone_s2s_execute(cr, uid, tx_id, {}, context=context) - # print res - - -# { -# 'orderID': u'reference', -# 'STATUS': u'9', -# 'CARDNO': u'XXXXXXXXXXXX0002', -# 'PAYID': u'24998692', -# 'CN': u'Norbert Poilu', -# 'NCERROR': u'0', -# 'TRXDATE': u'11/05/13', -# 'IP': u'85.201.233.72', -# 'BRAND': u'VISA', -# 'ACCEPTANCE': u'test123', -# 'currency': u'EUR', -# 'amount': u'1.95', -# 'SHASIGN': u'EFDC56879EF7DE72CCF4B397076B5C9A844CB0FA', -# 'ED': u'0314', -# 'PM': u'CreditCard' -# } + res = tx.ogone_s2s_execute({}) diff --git a/addons/payment_ogone/views/payment_ogone_templates.xml b/addons/payment_ogone/views/payment_ogone_templates.xml index 69ebe0d7e5f..8e9dd72c103 100644 --- a/addons/payment_ogone/views/payment_ogone_templates.xml +++ b/addons/payment_ogone/views/payment_ogone_templates.xml @@ -1,5 +1,5 @@ - + - + diff --git a/addons/payment_ogone/views/payment_views.xml b/addons/payment_ogone/views/payment_views.xml index 8efde9b908c..bffca767fbd 100644 --- a/addons/payment_ogone/views/payment_views.xml +++ b/addons/payment_ogone/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -22,4 +22,4 @@ - + From 9e69cfd0b46b1e6ac35a98d224627c88c4b520c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 11:48:16 +0200 Subject: [PATCH 13/22] [MOV] payment_paypal: file organization --- addons/payment_paypal/__openerp__.py | 8 ++++---- .../data/{paypal.xml => payment_acquirer_data.xml} | 0 addons/payment_paypal/models/__init__.py | 2 +- addons/payment_paypal/models/{paypal.py => payment.py} | 0 ..._config_view.xml => account_config_settings_views.xml} | 0 .../views/{paypal.xml => payment_paypal_templates.xml} | 0 .../views/{payment_acquirer.xml => payment_views.xml} | 0 7 files changed, 5 insertions(+), 5 deletions(-) rename addons/payment_paypal/data/{paypal.xml => payment_acquirer_data.xml} (100%) rename addons/payment_paypal/models/{paypal.py => payment.py} (100%) rename addons/payment_paypal/views/{res_config_view.xml => account_config_settings_views.xml} (100%) rename addons/payment_paypal/views/{paypal.xml => payment_paypal_templates.xml} (100%) rename addons/payment_paypal/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_paypal/__openerp__.py b/addons/payment_paypal/__openerp__.py index 2e53042ccc6..80274a5b64e 100644 --- a/addons/payment_paypal/__openerp__.py +++ b/addons/payment_paypal/__openerp__.py @@ -8,10 +8,10 @@ 'description': """Paypal Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/paypal.xml', - 'views/payment_acquirer.xml', - 'views/res_config_view.xml', - 'data/paypal.xml', + 'views/payment_views.xml', + 'views/payment_paypal_templates.xml', + 'views/account_config_settings_views.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, } diff --git a/addons/payment_paypal/data/paypal.xml b/addons/payment_paypal/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_paypal/data/paypal.xml rename to addons/payment_paypal/data/payment_acquirer_data.xml diff --git a/addons/payment_paypal/models/__init__.py b/addons/payment_paypal/models/__init__.py index a1fe670f56f..10b988e0c28 100644 --- a/addons/payment_paypal/models/__init__.py +++ b/addons/payment_paypal/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import paypal +import payment diff --git a/addons/payment_paypal/models/paypal.py b/addons/payment_paypal/models/payment.py similarity index 100% rename from addons/payment_paypal/models/paypal.py rename to addons/payment_paypal/models/payment.py diff --git a/addons/payment_paypal/views/res_config_view.xml b/addons/payment_paypal/views/account_config_settings_views.xml similarity index 100% rename from addons/payment_paypal/views/res_config_view.xml rename to addons/payment_paypal/views/account_config_settings_views.xml diff --git a/addons/payment_paypal/views/paypal.xml b/addons/payment_paypal/views/payment_paypal_templates.xml similarity index 100% rename from addons/payment_paypal/views/paypal.xml rename to addons/payment_paypal/views/payment_paypal_templates.xml diff --git a/addons/payment_paypal/views/payment_acquirer.xml b/addons/payment_paypal/views/payment_views.xml similarity index 100% rename from addons/payment_paypal/views/payment_acquirer.xml rename to addons/payment_paypal/views/payment_views.xml From f1ac1b127139c538794cddf6f676bc210848030a Mon Sep 17 00:00:00 2001 From: Shivam Dudhat Date: Tue, 5 Jul 2016 10:28:44 +0200 Subject: [PATCH 14/22] [MIG] payment_paypal: new API No functional change. --- addons/payment_paypal/controllers/main.py | 14 +- .../data/payment_acquirer_data.xml | 4 +- addons/payment_paypal/models/payment.py | 169 ++++++++---------- addons/payment_paypal/tests/test_paypal.py | 93 ++++------ .../views/account_config_settings_views.xml | 4 +- .../views/payment_paypal_templates.xml | 4 +- addons/payment_paypal/views/payment_views.xml | 4 +- 7 files changed, 128 insertions(+), 164 deletions(-) diff --git a/addons/payment_paypal/controllers/main.py b/addons/payment_paypal/controllers/main.py index 0048c3ffb26..a74ab8e1d29 100644 --- a/addons/payment_paypal/controllers/main.py +++ b/addons/payment_paypal/controllers/main.py @@ -6,8 +6,8 @@ import pprint import urllib2 import werkzeug -from openerp import http, SUPERUSER_ID -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) @@ -37,21 +37,18 @@ class PaypalController(http.Controller): Once data is validated, process it. """ res = False new_post = dict(post, cmd='_notify-validate') - cr, uid, context = request.cr, request.uid, request.context reference = post.get('item_number') tx = None if reference: - tx_ids = request.registry['payment.transaction'].search(cr, uid, [('reference', '=', reference)], context=context) - if tx_ids: - tx = request.registry['payment.transaction'].browse(cr, uid, tx_ids[0], context=context) - paypal_urls = request.registry['payment.acquirer']._get_paypal_urls(cr, uid, tx and tx.acquirer_id and tx.acquirer_id.environment or 'prod', context=context) + tx = request.env['payment.transaction'].search([('reference', '=', reference)]) + paypal_urls = tx.acquirer_id._get_paypal_urls(tx.acquirer_id.environment or 'prod') validate_url = paypal_urls['paypal_form_url'] urequest = urllib2.Request(validate_url, werkzeug.url_encode(new_post)) uopen = urllib2.urlopen(urequest) resp = uopen.read() if resp == 'VERIFIED': _logger.info('Paypal: validated data') - res = request.registry['payment.transaction'].form_feedback(cr, SUPERUSER_ID, post, 'paypal', context=context) + res = request.env['payment.transaction'].sudo().form_feedback(post, 'paypal') elif resp == 'INVALID': _logger.warning('Paypal: answered INVALID on data verification') else: @@ -76,7 +73,6 @@ class PaypalController(http.Controller): @http.route('/payment/paypal/cancel', type='http', auth="none", csrf=False) def paypal_cancel(self, **post): """ When the user cancels its Paypal payment: GET on this route """ - cr, uid, context = request.cr, SUPERUSER_ID, request.context _logger.info('Beginning Paypal cancel with post data %s', pprint.pformat(post)) # debug return_url = self._get_return_url(**post) return werkzeug.utils.redirect(return_url) diff --git a/addons/payment_paypal/data/payment_acquirer_data.xml b/addons/payment_paypal/data/payment_acquirer_data.xml index fd474b27532..6ae2dd7df05 100644 --- a/addons/payment_paypal/data/payment_acquirer_data.xml +++ b/addons/payment_paypal/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -18,4 +18,4 @@ - + diff --git a/addons/payment_paypal/models/payment.py b/addons/payment_paypal/models/payment.py index 62e307a5ae9..6919302293e 100644 --- a/addons/payment_paypal/models/payment.py +++ b/addons/payment_paypal/models/payment.py @@ -1,26 +1,41 @@ # coding: utf-8 -import base64 import json import logging import urlparse -import werkzeug.urls -import urllib2 -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_paypal.controllers.main import PaypalController -from openerp.osv import osv, fields -from openerp.tools.float_utils import float_compare -from openerp import SUPERUSER_ID -from openerp.tools.translate import _ +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_paypal.controllers.main import PaypalController +from odoo.tools.float_utils import float_compare + _logger = logging.getLogger(__name__) -class AcquirerPaypal(osv.Model): +class AcquirerPaypal(models.Model): _inherit = 'payment.acquirer' - def _get_paypal_urls(self, cr, uid, environment, context=None): + provider = fields.Selection(selection_add=[('paypal', 'Paypal')]) + paypal_email_account = fields.Char('Paypal Email ID', required_if_provider='paypal') + paypal_seller_account = fields.Char( + 'Paypal Merchant ID', + help='The Merchant ID is used to ensure communications coming from Paypal are valid and secured.') + paypal_use_ipn = fields.Boolean('Use IPN', default=True, help='Paypal Instant Payment Notification') + # Server 2 server + paypal_api_enabled = fields.Boolean('Use Rest API', default=False) + paypal_api_username = fields.Char('Rest API Username') + paypal_api_password = fields.Char('Rest API Password') + paypal_api_access_token = fields.Char('Access Token') + paypal_api_access_token_validity = fields.Datetime('Access Token Validity') + # Default paypal fees + fees_dom_fixed = fields.Float(default=0.35) + fees_dom_var = fields.Float(default=3.4) + fees_int_fixed = fields.Float(default=0.35) + fees_int_var = fields.Float(default=3.9) + + @api.model + def _get_paypal_urls(self, environment): """ Paypal URLS """ if environment == 'prod': return { @@ -33,36 +48,8 @@ class AcquirerPaypal(osv.Model): 'paypal_rest_url': 'https://api.sandbox.paypal.com/v1/oauth2/token', } - def _get_providers(self, cr, uid, context=None): - providers = super(AcquirerPaypal, self)._get_providers(cr, uid, context=context) - providers.append(['paypal', 'Paypal']) - return providers - - _columns = { - 'paypal_email_account': fields.char('Paypal Email ID', required_if_provider='paypal'), - 'paypal_seller_account': fields.char( - 'Paypal Merchant ID', - help='The Merchant ID is used to ensure communications coming from Paypal are valid and secured.'), - 'paypal_use_ipn': fields.boolean('Use IPN', help='Paypal Instant Payment Notification'), - # Server 2 server - 'paypal_api_enabled': fields.boolean('Use Rest API'), - 'paypal_api_username': fields.char('Rest API Username'), - 'paypal_api_password': fields.char('Rest API Password'), - 'paypal_api_access_token': fields.char('Access Token'), - 'paypal_api_access_token_validity': fields.datetime('Access Token Validity'), - } - - _defaults = { - 'paypal_use_ipn': True, - 'fees_active': False, - 'fees_dom_fixed': 0.35, - 'fees_dom_var': 3.4, - 'fees_int_fixed': 0.35, - 'fees_int_var': 3.9, - 'paypal_api_enabled': False, - } - - def paypal_compute_fees(self, cr, uid, ids, amount, currency_id, country_id, context=None): + @api.multi + def paypal_compute_fees(self, amount, currency_id, country_id): """ Compute paypal fees. :param float amount: the amount to pay @@ -71,28 +58,27 @@ class AcquirerPaypal(osv.Model): the acquirer company country. :return float fees: computed fees """ - acquirer = self.browse(cr, uid, ids, context=context)[0] - if not acquirer.fees_active: + if not self.fees_active: return 0.0 - country = self.pool['res.country'].browse(cr, uid, country_id, context=context) - if country and acquirer.company_id.country_id.id == country.id: - percentage = acquirer.fees_dom_var - fixed = acquirer.fees_dom_fixed + country = self.env['res.country'].browse(country_id) + if country and self.company_id.country_id.id == country.id: + percentage = self.fees_dom_var + fixed = self.fees_dom_fixed else: - percentage = acquirer.fees_int_var - fixed = acquirer.fees_int_fixed + percentage = self.fees_int_var + fixed = self.fees_int_fixed fees = (percentage / 100.0 * amount + fixed) / (1 - percentage / 100.0) return fees - def paypal_form_generate_values(self, cr, uid, ids, values, context=None): - base_url = self.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, 'web.base.url') - acquirer = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def paypal_form_generate_values(self, values): + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') paypal_tx_values = dict(values) paypal_tx_values.update({ 'cmd': '_xclick', - 'business': acquirer.paypal_email_account, - 'item_name': '%s: %s' % (acquirer.company_id.name, values['reference']), + 'business': self.paypal_email_account, + 'item_name': '%s: %s' % (self.company_id.name, values['reference']), 'item_number': values['reference'], 'amount': values['amount'], 'currency_code': values['currency'] and values['currency'].name or '', @@ -107,28 +93,27 @@ class AcquirerPaypal(osv.Model): 'paypal_return': '%s' % urlparse.urljoin(base_url, PaypalController._return_url), 'notify_url': '%s' % urlparse.urljoin(base_url, PaypalController._notify_url), 'cancel_return': '%s' % urlparse.urljoin(base_url, PaypalController._cancel_url), - 'handling': '%.2f' % paypal_tx_values.pop('fees', 0.0) if acquirer.fees_active else False, + 'handling': '%.2f' % paypal_tx_values.pop('fees', 0.0) if self.fees_active else False, 'custom': json.dumps({'return_url': '%s' % paypal_tx_values.pop('return_url')}) if paypal_tx_values.get('return_url') else False, }) return paypal_tx_values - def paypal_get_form_action_url(self, cr, uid, ids, context=None): - acquirer = self.browse(cr, uid, ids, context=context)[0] - return self._get_paypal_urls(cr, uid, acquirer.environment, context=context)['paypal_form_url'] + @api.multi + def paypal_get_form_action_url(self): + return self._get_paypal_urls(self.environment)['paypal_form_url'] -class TxPaypal(osv.Model): +class TxPaypal(models.Model): _inherit = 'payment.transaction' - _columns = { - 'paypal_txn_type': fields.char('Transaction type'), - } + paypal_txn_type = fields.Char('Transaction type') # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- - def _paypal_form_get_tx_from_data(self, cr, uid, data, context=None): + @api.model + def _paypal_form_get_tx_from_data(self, data): 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) @@ -136,19 +121,19 @@ class TxPaypal(osv.Model): 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: + txs = self.env['payment.transaction'].search([('reference', '=', reference)]) + if not txs or len(txs) > 1: error_msg = 'Paypal: received data for reference %s' % (reference) - if not tx_ids: + if not txs: 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) + return txs[0] - def _paypal_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def _paypal_form_get_invalid_parameters(self, data): invalid_parameters = [] _logger.info('Received a notification from Paypal with IPN version %s', data.get('notify_version')) if data.get('test_ipn'): @@ -157,50 +142,50 @@ class TxPaypal(osv.Model): ), # TODO: txn_id: shoudl be false at draft, set afterwards, and verified with txn details - if tx.acquirer_reference and data.get('txn_id') != tx.acquirer_reference: - invalid_parameters.append(('txn_id', data.get('txn_id'), tx.acquirer_reference)) + if self.acquirer_reference and data.get('txn_id') != self.acquirer_reference: + invalid_parameters.append(('txn_id', data.get('txn_id'), self.acquirer_reference)) # check what is buyed - if float_compare(float(data.get('mc_gross', '0.0')), (tx.amount + tx.fees), 2) != 0: - invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % tx.amount)) # mc_gross is amount + fees - if data.get('mc_currency') != tx.currency_id.name: - invalid_parameters.append(('mc_currency', data.get('mc_currency'), tx.currency_id.name)) - if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), tx.fees, 2) != 0: - invalid_parameters.append(('handling_amount', data.get('handling_amount'), tx.fees)) + if float_compare(float(data.get('mc_gross', '0.0')), (self.amount + self.fees), 2) != 0: + invalid_parameters.append(('mc_gross', data.get('mc_gross'), '%.2f' % self.amount)) # mc_gross is amount + fees + if data.get('mc_currency') != self.currency_id.name: + invalid_parameters.append(('mc_currency', data.get('mc_currency'), self.currency_id.name)) + if 'handling_amount' in data and float_compare(float(data.get('handling_amount')), self.fees, 2) != 0: + invalid_parameters.append(('handling_amount', data.get('handling_amount'), self.fees)) # check buyer - if tx.payment_token_id and data.get('payer_id') != tx.payment_token_id.acquirer_ref: - invalid_parameters.append(('payer_id', data.get('payer_id'), tx.payment_token_id.acquirer_ref)) + if self.payment_token_id and data.get('payer_id') != self.payment_token_id.acquirer_ref: + invalid_parameters.append(('payer_id', data.get('payer_id'), self.payment_token_id.acquirer_ref)) # check seller - if data.get('receiver_id') and tx.acquirer_id.paypal_seller_account and data['receiver_id'] != tx.acquirer_id.paypal_seller_account: - invalid_parameters.append(('receiver_id', data.get('receiver_id'), tx.acquirer_id.paypal_seller_account)) - if not data.get('receiver_id') or not tx.acquirer_id.paypal_seller_account: + if data.get('receiver_id') and self.acquirer_id.paypal_seller_account and data['receiver_id'] != self.acquirer_id.paypal_seller_account: + invalid_parameters.append(('receiver_id', data.get('receiver_id'), self.acquirer_id.paypal_seller_account)) + if not data.get('receiver_id') or not self.acquirer_id.paypal_seller_account: # Check receiver_email only if receiver_id was not checked. # In Paypal, this is possible to configure as receiver_email a different email than the business email (the login email) # In Odoo, there is only one field for the Paypal email: the business email. This isn't possible to set a receiver_email # different than the business email. Therefore, if you want such a configuration in your Paypal, you are then obliged to fill # the Merchant ID in the Paypal payment acquirer in Odoo, so the check is performed on this variable instead of the receiver_email. # At least one of the two checks must be done, to avoid fraudsters. - if data.get('receiver_email') != tx.acquirer_id.paypal_email_account: - invalid_parameters.append(('receiver_email', data.get('receiver_email'), tx.acquirer_id.paypal_email_account)) + if data.get('receiver_email') != self.acquirer_id.paypal_email_account: + invalid_parameters.append(('receiver_email', data.get('receiver_email'), self.acquirer_id.paypal_email_account)) return invalid_parameters - def _paypal_form_validate(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + @api.multi + def _paypal_form_validate(self, data): 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)) + _logger.info('Validated Paypal payment for tx %s: set as done' % (self.reference)) res.update(state='done', date_validate=data.get('payment_date', fields.datetime.now())) - return tx.write(res) + return self.write(res) elif status in ['Pending', 'Expired']: - _logger.info('Received notification for Paypal payment %s: set as pending' % (tx.reference)) + _logger.info('Received notification for Paypal payment %s: set as pending' % (self.reference)) res.update(state='pending', state_message=data.get('pending_reason', '')) - return tx.write(res) + return self.write(res) else: - error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (tx.reference, status) + error = 'Received unrecognized status for Paypal payment %s: %s, set as error' % (self.reference, status) _logger.info(error) res.update(state='error', state_message=error) - return tx.write(res) + return self.write(res) diff --git a/addons/payment_paypal/tests/test_paypal.py b/addons/payment_paypal/tests/test_paypal.py index e0e6db55947..5f122e8b296 100644 --- a/addons/payment_paypal/tests/test_paypal.py +++ b/addons/payment_paypal/tests/test_paypal.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment.tests.common import PaymentAcquirerCommon -from openerp.addons.payment_paypal.controllers.main import PaypalController -from openerp.tools import mute_logger +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment.tests.common import PaymentAcquirerCommon +from odoo.addons.payment_paypal.controllers.main import PaypalController +from odoo.tools import mute_logger from lxml import objectify import urlparse @@ -13,12 +13,8 @@ class PaypalCommon(PaymentAcquirerCommon): def setUp(self): super(PaypalCommon, self).setUp() - cr, uid = self.cr, self.uid - self.base_url = self.registry('ir.config_parameter').get_param(cr, uid, 'web.base.url') - # get the paypal account - model, self.paypal_id = self.registry('ir.model.data').get_object_reference(cr, uid, 'payment', 'payment_acquirer_paypal') - # tde+seller@openerp.com - tde+buyer@openerp.com - tde+buyer-it@openerp.com + self.paypal = self.env.ref('payment.payment_acquirer_paypal') # some CC self.amex = (('378282246310005', '123'), ('371449635398431', '123')) @@ -36,26 +32,23 @@ class PaypalCommon(PaymentAcquirerCommon): class PaypalForm(PaypalCommon): def test_10_paypal_form_render(self): - cr, uid, context = self.cr, self.uid, {} + base_url = self.env['ir.config_parameter'].get_param('web.base.url') # be sure not to do stupid things - self.payment_acquirer.write(cr, uid, self.paypal_id, {'paypal_email_account': 'tde+paypal-facilitator@openerp.com', 'fees_active': False}, context) - paypal = self.payment_acquirer.browse(cr, uid, self.paypal_id, context) - self.assertEqual(paypal.environment, 'test', 'test without test environment') + self.paypal.write({'paypal_email_account': 'tde+paypal-facilitator@odoo.com', 'fees_active': False}) + self.assertEqual(self.paypal.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering # ---------------------------------------- # render the button - res = self.payment_acquirer.render( - cr, uid, self.paypal_id, - 'test_ref0', 0.01, self.currency_euro_id, - values=self.buyer_values, - context=context) + res = self.paypal.render( + 'test_ref0', 0.01, self.currency_euro.id, + values=self.buyer_values) form_values = { 'cmd': '_xclick', - 'business': 'tde+paypal-facilitator@openerp.com', + 'business': 'tde+paypal-facilitator@odoo.com', 'item_name': 'YourCompany: test_ref0', 'item_number': 'test_ref0', 'first_name': 'Norbert', @@ -67,9 +60,9 @@ class PaypalForm(PaypalCommon): 'zip': '1000', 'country': 'Belgium', 'email': 'norbert.buyer@example.com', - 'return': '%s' % urlparse.urljoin(self.base_url, PaypalController._return_url), - 'notify_url': '%s' % urlparse.urljoin(self.base_url, PaypalController._notify_url), - 'cancel_return': '%s' % urlparse.urljoin(self.base_url, PaypalController._cancel_url), + 'return': '%s' % urlparse.urljoin(base_url, PaypalController._return_url), + 'notify_url': '%s' % urlparse.urljoin(base_url, PaypalController._notify_url), + 'cancel_return': '%s' % urlparse.urljoin(base_url, PaypalController._cancel_url), } # check form result @@ -85,26 +78,22 @@ class PaypalForm(PaypalCommon): ) def test_11_paypal_form_with_fees(self): - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid things - paypal = self.payment_acquirer.browse(self.cr, self.uid, self.paypal_id, None) - self.assertEqual(paypal.environment, 'test', 'test without test environment') + self.assertEqual(self.paypal.environment, 'test', 'test without test environment') # update acquirer: compute fees - self.payment_acquirer.write(cr, uid, self.paypal_id, { + self.paypal.write({ 'fees_active': True, 'fees_dom_fixed': 1.0, 'fees_dom_var': 0.35, 'fees_int_fixed': 1.5, 'fees_int_var': 0.50, - }, context) + }) # render the button - res = self.payment_acquirer.render( - cr, uid, self.paypal_id, - 'test_ref0', 12.50, self.currency_euro_id, - values=self.buyer_values, - context=context) + res = self.paypal.render( + 'test_ref0', 12.50, self.currency_euro.id, + values=self.buyer_values) # check form result handling_found = False @@ -116,12 +105,10 @@ class PaypalForm(PaypalCommon): self.assertEqual(form_input.get('value'), '1.57', 'paypal: wrong computed fees') self.assertTrue(handling_found, 'paypal: fees_active did not add handling input in rendered form') - @mute_logger('openerp.addons.payment_paypal.models.paypal', 'ValidationError') + @mute_logger('openerp.addons.payment_paypal.models.payment', 'ValidationError') def test_20_paypal_form_management(self): - cr, uid, context = self.cr, self.uid, {} # be sure not to do stupid things - paypal = self.payment_acquirer.browse(cr, uid, self.paypal_id, context) - self.assertEqual(paypal.environment, 'test', 'test without test environment') + self.assertEqual(self.paypal.environment, 'test', 'test without test environment') # typical data posted by paypal after client has successfully paid paypal_post_data = { @@ -160,7 +147,7 @@ class PaypalForm(PaypalCommon): 'address_status': u'unconfirmed', 'mc_currency': u'EUR', 'shipping': u'0.00', - 'payer_email': u'tde+buyer@openerp.com', + 'payer_email': u'tde+buyer@odoo.com', 'payment_type': u'instant', 'mc_gross': u'1.95', 'ipn_track_id': u'866df2ccd444b', @@ -169,39 +156,35 @@ class PaypalForm(PaypalCommon): # should raise error about unknown tx with self.assertRaises(ValidationError): - self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) + self.env['payment.transaction'].form_feedback(paypal_post_data, 'paypal') # create tx - tx_id = self.payment_transaction.create( - cr, uid, { - 'amount': 1.95, - 'acquirer_id': self.paypal_id, - 'currency_id': self.currency_euro_id, - 'reference': 'test_ref_2', - 'partner_name': 'Norbert Buyer', - 'partner_country_id': self.country_france_id, - }, context=context - ) + tx = self.env['payment.transaction'].create({ + 'amount': 1.95, + 'acquirer_id': self.paypal.id, + 'currency_id': self.currency_euro.id, + 'reference': 'test_ref_2', + 'partner_name': 'Norbert Buyer', + 'partner_country_id': self.country_france.id}) + # validate it - self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) + tx.form_feedback(paypal_post_data, 'paypal') # check - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertEqual(tx.state, 'pending', 'paypal: wrong state after receiving a valid pending notification') self.assertEqual(tx.state_message, 'multi_currency', 'paypal: wrong state message after receiving a valid pending notification') self.assertEqual(tx.acquirer_reference, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification') self.assertFalse(tx.date_validate, 'paypal: validation date should not be updated whenr receiving pending notification') # update tx - self.payment_transaction.write(cr, uid, [tx_id], { + tx.write({ 'state': 'draft', - 'acquirer_reference': False, - }, context=context) + 'acquirer_reference': False}) + # update notification from paypal paypal_post_data['payment_status'] = 'Completed' # validate it - self.payment_transaction.form_feedback(cr, uid, paypal_post_data, 'paypal', context=context) + tx.form_feedback(paypal_post_data, 'paypal') # check - tx = self.payment_transaction.browse(cr, uid, tx_id, context=context) self.assertEqual(tx.state, 'done', 'paypal: wrong state after receiving a valid pending notification') self.assertEqual(tx.acquirer_reference, '08D73520KX778924N', 'paypal: wrong txn_id after receiving a valid pending notification') self.assertEqual(tx.date_validate, '2013-11-18 03:21:19', 'paypal: wrong validation date') diff --git a/addons/payment_paypal/views/account_config_settings_views.xml b/addons/payment_paypal/views/account_config_settings_views.xml index 30e79a4992d..cfe6ce12748 100644 --- a/addons/payment_paypal/views/account_config_settings_views.xml +++ b/addons/payment_paypal/views/account_config_settings_views.xml @@ -1,5 +1,5 @@ - + @@ -12,4 +12,4 @@ - + diff --git a/addons/payment_paypal/views/payment_paypal_templates.xml b/addons/payment_paypal/views/payment_paypal_templates.xml index 6491f0e8ed5..495aac7158e 100644 --- a/addons/payment_paypal/views/payment_paypal_templates.xml +++ b/addons/payment_paypal/views/payment_paypal_templates.xml @@ -1,5 +1,5 @@ - + - + diff --git a/addons/payment_paypal/views/payment_views.xml b/addons/payment_paypal/views/payment_views.xml index a624366c1ed..01a28e9c04f 100644 --- a/addons/payment_paypal/views/payment_views.xml +++ b/addons/payment_paypal/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -37,4 +37,4 @@ - + From 7fbb9977321a1827aa1b9bd5301be8094f4612f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 14:55:21 +0200 Subject: [PATCH 15/22] [MOV] payment_payumoney: file organization --- addons/payment_payumoney/__openerp__.py | 6 +- ...ney_data.xml => payment_acquirer_data.xml} | 0 addons/payment_payumoney/models/__init__.py | 3 +- .../{payment_acquirer.py => payment.py} | 81 +++++++++++++++++ .../models/payment_transaction.py | 86 ------------------- ...ey.xml => payment_payumoney_templates.xml} | 0 ...payment_acquirer.xml => payment_views.xml} | 0 7 files changed, 85 insertions(+), 91 deletions(-) rename addons/payment_payumoney/data/{payment_payumoney_data.xml => payment_acquirer_data.xml} (100%) rename addons/payment_payumoney/models/{payment_acquirer.py => payment.py} (51%) delete mode 100644 addons/payment_payumoney/models/payment_transaction.py rename addons/payment_payumoney/views/{payumoney.xml => payment_payumoney_templates.xml} (100%) rename addons/payment_payumoney/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_payumoney/__openerp__.py b/addons/payment_payumoney/__openerp__.py index 62e92bb78d8..ce4a57eb68c 100644 --- a/addons/payment_payumoney/__openerp__.py +++ b/addons/payment_payumoney/__openerp__.py @@ -12,9 +12,9 @@ """, 'depends': ['payment'], 'data': [ - 'views/payumoney.xml', - 'views/payment_acquirer.xml', - 'data/payment_payumoney_data.xml', + 'views/payment_views.xml', + 'views/payment_payumoney_templates.xml', + 'data/payment_acquirer_data.xml', ], 'license': 'OEEL-1', } diff --git a/addons/payment_payumoney/data/payment_payumoney_data.xml b/addons/payment_payumoney/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_payumoney/data/payment_payumoney_data.xml rename to addons/payment_payumoney/data/payment_acquirer_data.xml diff --git a/addons/payment_payumoney/models/__init__.py b/addons/payment_payumoney/models/__init__.py index 29abdbcb773..8ba584ff326 100644 --- a/addons/payment_payumoney/models/__init__.py +++ b/addons/payment_payumoney/models/__init__.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import payment_acquirer -import payment_transaction +import payment diff --git a/addons/payment_payumoney/models/payment_acquirer.py b/addons/payment_payumoney/models/payment.py similarity index 51% rename from addons/payment_payumoney/models/payment_acquirer.py rename to addons/payment_payumoney/models/payment.py index 0abe333e73d..98edf7a72ff 100644 --- a/addons/payment_payumoney/models/payment_acquirer.py +++ b/addons/payment_payumoney/models/payment.py @@ -5,6 +5,12 @@ import hashlib import urlparse from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.tools.float_utils import float_compare + +import logging + +_logger = logging.getLogger(__name__) class PaymentAcquirerPayumoney(models.Model): @@ -76,3 +82,78 @@ class PaymentAcquirerPayumoney(models.Model): def payumoney_get_form_action_url(self): self.ensure_one() return self._get_payumoney_urls(self.environment)['payumoney_form_url'] + + +class PaymentTransactionPayumoney(models.Model): + _inherit = 'payment.transaction' + + @api.model + def _payumoney_form_get_tx_from_data(self, data): + """ Given a data dict coming from payumoney, verify it and find the related + transaction record. """ + reference = data.get('txnid') + pay_id = data.get('mihpayid') + shasign = data.get('hash') + if not reference or not pay_id or not shasign: + raise ValidationError(_('PayUmoney: received data with missing reference (%s) or pay_id (%s) or shashign (%s)') % (reference, pay_id, shasign)) + + transaction = self.search([('reference', '=', reference)]) + + if not transaction: + error_msg = (_('PayUmoney: received data for reference %s; no order found') % (reference)) + raise ValidationError(error_msg) + elif len(transaction) > 1: + error_msg = (_('PayUmoney: received data for reference %s; multiple orders found') % (reference)) + raise ValidationError(error_msg) + + #verify shasign + shasign_check = transaction.acquirer_id._payumoney_generate_sign('out', data) + if shasign_check.upper() != shasign.upper(): + raise ValidationError(_('PayUmoney: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data)) + return transaction + + @api.multi + def _payumoney_form_get_invalid_parameters(self, data): + invalid_parameters = [] + + if self.acquirer_reference and data.get('mihpayid') != self.acquirer_reference: + invalid_parameters.append( + ('Transaction Id', data.get('mihpayid'), self.acquirer_reference)) + #check what is buyed + if float_compare(float(data.get('amount', '0.0')), self.amount, 2) != 0: + invalid_parameters.append( + ('Amount', data.get('amount'), '%.2f' % self.amount)) + + return invalid_parameters + + @api.multi + def _payumoney_form_validate(self, data): + status = data.get('status') + transaction_status = { + 'success': { + 'state': 'done', + 'acquirer_reference': data.get('payuMoneyId'), + 'date_validate': fields.Datetime.now(), + }, + 'pending': { + 'state': 'pending', + 'acquirer_reference': data.get('payuMoneyId'), + 'date_validate': fields.Datetime.now(), + }, + 'failure': { + 'state': 'cancel', + 'acquirer_reference': data.get('payuMoneyId'), + 'date_validate': fields.Datetime.now(), + }, + 'error': { + 'state': 'error', + 'state_message': data.get('error_Message') or _('PayUmoney: feedback error'), + 'acquirer_reference': data.get('payuMoneyId'), + 'date_validate': fields.Datetime.now(), + } + } + vals = transaction_status.get(status, False) + if not vals: + vals = transaction_status['error'] + _logger.info(vals['state_message']) + return self.write(vals) diff --git a/addons/payment_payumoney/models/payment_transaction.py b/addons/payment_payumoney/models/payment_transaction.py deleted file mode 100644 index e89a95511ec..00000000000 --- a/addons/payment_payumoney/models/payment_transaction.py +++ /dev/null @@ -1,86 +0,0 @@ -# -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. - -import logging - -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 PaymentTransactionPayumoney(models.Model): - _inherit = 'payment.transaction' - - @api.model - def _payumoney_form_get_tx_from_data(self, data): - """ Given a data dict coming from payumoney, verify it and find the related - transaction record. """ - reference = data.get('txnid') - pay_id = data.get('mihpayid') - shasign = data.get('hash') - if not reference or not pay_id or not shasign: - raise ValidationError(_('PayUmoney: received data with missing reference (%s) or pay_id (%s) or shashign (%s)') % (reference, pay_id, shasign)) - - transaction = self.search([('reference', '=', reference)]) - - if not transaction: - error_msg = (_('PayUmoney: received data for reference %s; no order found') % (reference)) - raise ValidationError(error_msg) - elif len(transaction) > 1: - error_msg = (_('PayUmoney: received data for reference %s; multiple orders found') % (reference)) - raise ValidationError(error_msg) - - #verify shasign - shasign_check = transaction.acquirer_id._payumoney_generate_sign('out', data) - if shasign_check.upper() != shasign.upper(): - raise ValidationError(_('PayUmoney: invalid shasign, received %s, computed %s, for data %s') % (shasign, shasign_check, data)) - return transaction - - @api.multi - def _payumoney_form_get_invalid_parameters(self, data): - invalid_parameters = [] - - if self.acquirer_reference and data.get('mihpayid') != self.acquirer_reference: - invalid_parameters.append( - ('Transaction Id', data.get('mihpayid'), self.acquirer_reference)) - #check what is buyed - if float_compare(float(data.get('amount', '0.0')), self.amount, 2) != 0: - invalid_parameters.append( - ('Amount', data.get('amount'), '%.2f' % self.amount)) - - return invalid_parameters - - @api.multi - def _payumoney_form_validate(self, data): - status = data.get('status') - transaction_status = { - 'success': { - 'state': 'done', - 'acquirer_reference': data.get('payuMoneyId'), - 'date_validate': fields.Datetime.now(), - }, - 'pending': { - 'state': 'pending', - 'acquirer_reference': data.get('payuMoneyId'), - 'date_validate': fields.Datetime.now(), - }, - 'failure': { - 'state': 'cancel', - 'acquirer_reference': data.get('payuMoneyId'), - 'date_validate': fields.Datetime.now(), - }, - 'error': { - 'state': 'error', - 'state_message': data.get('error_Message') or _('PayUmoney: feedback error'), - 'acquirer_reference': data.get('payuMoneyId'), - 'date_validate': fields.Datetime.now(), - } - } - vals = transaction_status.get(status, False) - if not vals: - vals = transaction_status['error'] - _logger.info(vals['state_message']) - return self.write(vals) diff --git a/addons/payment_payumoney/views/payumoney.xml b/addons/payment_payumoney/views/payment_payumoney_templates.xml similarity index 100% rename from addons/payment_payumoney/views/payumoney.xml rename to addons/payment_payumoney/views/payment_payumoney_templates.xml diff --git a/addons/payment_payumoney/views/payment_acquirer.xml b/addons/payment_payumoney/views/payment_views.xml similarity index 100% rename from addons/payment_payumoney/views/payment_acquirer.xml rename to addons/payment_payumoney/views/payment_views.xml From 5f6c21c720182ac448bf420f0a87258b056fce93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 14:43:43 +0200 Subject: [PATCH 16/22] [CLN] payment_payumoney: cleaning and guidelines As this module is already in new API only small linting is performed. --- addons/payment_payumoney/models/payment.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/addons/payment_payumoney/models/payment.py b/addons/payment_payumoney/models/payment.py index 98edf7a72ff..38d89c2c7f9 100644 --- a/addons/payment_payumoney/models/payment.py +++ b/addons/payment_payumoney/models/payment.py @@ -16,6 +16,7 @@ _logger = logging.getLogger(__name__) class PaymentAcquirerPayumoney(models.Model): _inherit = 'payment.acquirer' + provider = fields.Selection(selection_add=[('payumoney', 'PayUmoney')]) payumoney_merchant_key = fields.Char(string='Merchant Key', required_if_provider='payumoney') payumoney_merchant_salt = fields.Char(string='Merchant Salt', required_if_provider='payumoney') @@ -26,12 +27,6 @@ class PaymentAcquirerPayumoney(models.Model): else: return {'payumoney_form_url': 'https://test.payu.in/_payment'} - @api.model - def _get_providers(self): - providers = super(PaymentAcquirerPayumoney, self)._get_providers() - providers.append(['payumoney', 'PayUmoney']) - return providers - def _payumoney_generate_sign(self, inout, values): """ Generate the shasign for incoming or outgoing communications. :param self: the self browse record. It should have a shakey in shakey out From d70d6c3ceef41ed616e0088ecea1d4de3ce1aa7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 13:51:23 +0200 Subject: [PATCH 17/22] [MOV] payment_sips: file organization --- addons/payment_sips/__openerp__.py | 6 +++--- .../data/{sips.xml => payment_acquirer_data.xml} | 0 addons/payment_sips/models/__init__.py | 2 +- addons/payment_sips/models/{sips.py => payment.py} | 0 .../views/{sips.xml => payment_sips_templates.xml} | 0 .../views/{payment_acquirer.xml => payment_views.xml} | 0 6 files changed, 4 insertions(+), 4 deletions(-) rename addons/payment_sips/data/{sips.xml => payment_acquirer_data.xml} (100%) rename addons/payment_sips/models/{sips.py => payment.py} (100%) rename addons/payment_sips/views/{sips.xml => payment_sips_templates.xml} (100%) rename addons/payment_sips/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_sips/__openerp__.py b/addons/payment_sips/__openerp__.py index 08298fbfd3f..a8c608d8774 100644 --- a/addons/payment_sips/__openerp__.py +++ b/addons/payment_sips/__openerp__.py @@ -29,9 +29,9 @@ Works with Worldline keys version 2.0, contains implementation of payments acquirer using Worldline SIPS.""", 'depends': ['payment'], 'data': [ - 'views/sips.xml', - 'views/payment_acquirer.xml', - 'data/sips.xml', + 'views/payment_views.xml', + 'views/payment_sips_templates.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, } diff --git a/addons/payment_sips/data/sips.xml b/addons/payment_sips/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_sips/data/sips.xml rename to addons/payment_sips/data/payment_acquirer_data.xml diff --git a/addons/payment_sips/models/__init__.py b/addons/payment_sips/models/__init__.py index 365abd07d65..10b988e0c28 100644 --- a/addons/payment_sips/models/__init__.py +++ b/addons/payment_sips/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import sips +import payment diff --git a/addons/payment_sips/models/sips.py b/addons/payment_sips/models/payment.py similarity index 100% rename from addons/payment_sips/models/sips.py rename to addons/payment_sips/models/payment.py diff --git a/addons/payment_sips/views/sips.xml b/addons/payment_sips/views/payment_sips_templates.xml similarity index 100% rename from addons/payment_sips/views/sips.xml rename to addons/payment_sips/views/payment_sips_templates.xml diff --git a/addons/payment_sips/views/payment_acquirer.xml b/addons/payment_sips/views/payment_views.xml similarity index 100% rename from addons/payment_sips/views/payment_acquirer.xml rename to addons/payment_sips/views/payment_views.xml From 28ca53c70e67d446bca3f0864fa90365b4d92300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 14:20:32 +0200 Subject: [PATCH 18/22] [CLN] payment_sips: cleaning and guidelines As this module is already in new API only small linting is performed. --- addons/payment_sips/controllers/main.py | 23 ++++++---------- .../data/payment_acquirer_data.xml | 4 +-- addons/payment_sips/models/payment.py | 26 +++++++------------ .../views/payment_sips_templates.xml | 4 +-- addons/payment_sips/views/payment_views.xml | 4 +-- 5 files changed, 23 insertions(+), 38 deletions(-) diff --git a/addons/payment_sips/controllers/main.py b/addons/payment_sips/controllers/main.py index 0bf4a5f52b3..41ad8508210 100644 --- a/addons/payment_sips/controllers/main.py +++ b/addons/payment_sips/controllers/main.py @@ -4,8 +4,8 @@ import json import logging import werkzeug -from openerp import http -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) @@ -18,27 +18,20 @@ class SipsController(http.Controller): """ Extract the return URL from the data coming from sips. """ return_url = post.pop('return_url', '') if not return_url: - tx_obj = request.registry['payment.transaction'] - data = tx_obj._sips_data_to_object(post.get('Data')) + Tx = request.env['payment.transaction'] + data = Tx._sips_data_to_object(post.get('Data')) custom = json.loads(data.pop('returnContext', False) or '{}') return_url = custom.get('return_url', '/') return return_url def sips_validate_data(self, **post): - res = False - env = request.env - tx_obj = env['payment.transaction'] - acquirer_obj = env['payment.acquirer'] - - sips = acquirer_obj.search([('provider', '=', 'sips')], limit=1) - + sips = request.env['payment.acquirer'].search([('provider', '=', 'sips')], limit=1) security = sips._sips_generate_shasign(post) if security == post['Seal']: _logger.debug('Sips: validated data') - res = tx_obj.sudo().form_feedback(post, 'sips') - else: - _logger.warning('Sips: data are corrupted') - return res + return request.env['payment.transaction'].sudo().form_feedback(post, 'sips') + _logger.warning('Sips: data are corrupted') + return False @http.route([ '/payment/sips/ipn/'], diff --git a/addons/payment_sips/data/payment_acquirer_data.xml b/addons/payment_sips/data/payment_acquirer_data.xml index 89ec787ea5e..e841c411f5b 100644 --- a/addons/payment_sips/data/payment_acquirer_data.xml +++ b/addons/payment_sips/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -15,4 +15,4 @@ - + diff --git a/addons/payment_sips/models/payment.py b/addons/payment_sips/models/payment.py index e194cb281e5..7ce02a9d147 100644 --- a/addons/payment_sips/models/payment.py +++ b/addons/payment_sips/models/payment.py @@ -4,13 +4,12 @@ import json import logging from hashlib import sha256 import urlparse -import unicodedata -from openerp import models, fields, api -from openerp.tools.float_utils import float_compare -from openerp.tools.translate import _ -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.addons.payment_sips.controllers.main import SipsController +from odoo import models, fields, api +from odoo.tools.float_utils import float_compare +from odoo.tools.translate import _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.addons.payment_sips.controllers.main import SipsController _logger = logging.getLogger(__name__) @@ -36,12 +35,11 @@ CURRENCY_CODES = { class AcquirerSips(models.Model): _inherit = 'payment.acquirer' - # Fields - sips_merchant_id = fields.Char('SIPS API User Password', - required_if_provider='sips') + + provider = fields.Selection(selection_add=[('sips', 'Sips')]) + sips_merchant_id = fields.Char('SIPS API User Password', required_if_provider='sips') sips_secret = fields.Char('SIPS Secret', size=64, required_if_provider='sips') - # Methods def _get_sips_urls(self, environment): """ Worldline SIPS URLS """ url = { @@ -50,12 +48,6 @@ class AcquirerSips(models.Model): return {'sips_form_url': url.get(environment, url['test']), } - @api.model - def _get_providers(self): - providers = super(AcquirerSips, self)._get_providers() - providers.append(['sips', 'Sips']) - return providers - def _sips_generate_shasign(self, values): """ Generate the shasign for incoming or outgoing communications. :param dict values: transaction values @@ -124,7 +116,6 @@ class AcquirerSips(models.Model): class TxSips(models.Model): _inherit = 'payment.transaction' - # sips status _sips_valid_tx_status = ['00'] _sips_wait_tx_status = ['90', '99'] _sips_refused_tx_status = ['05', '14', '34', '54', '75', '97'] @@ -135,6 +126,7 @@ class TxSips(models.Model): # -------------------------------------------------- # FORM RELATED METHODS # -------------------------------------------------- + def _sips_data_to_object(self, data): res = {} for element in data.split('|'): diff --git a/addons/payment_sips/views/payment_sips_templates.xml b/addons/payment_sips/views/payment_sips_templates.xml index 2aeda71c3aa..1d8b487d379 100644 --- a/addons/payment_sips/views/payment_sips_templates.xml +++ b/addons/payment_sips/views/payment_sips_templates.xml @@ -1,5 +1,5 @@ - + - + diff --git a/addons/payment_sips/views/payment_views.xml b/addons/payment_sips/views/payment_views.xml index 9336cdd7ae4..4e5585af458 100644 --- a/addons/payment_sips/views/payment_views.xml +++ b/addons/payment_sips/views/payment_views.xml @@ -1,5 +1,5 @@ - + @@ -17,4 +17,4 @@ - + From 86a51d28d02a0a0f819e218ece00cfd9d2dd85c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 13:51:53 +0200 Subject: [PATCH 19/22] [MOV] payment_stripe: file organization --- addons/payment_stripe/__openerp__.py | 7 +- ...ipe_data.xml => payment_acquirer_data.xml} | 0 addons/payment_stripe/models/__init__.py | 4 +- addons/payment_stripe/models/payment.py | 210 ++++++++++++++++++ .../payment_stripe/models/payment_acquirer.py | 72 ------ addons/payment_stripe/models/payment_token.py | 50 ----- .../models/payment_transaction.py | 101 --------- .../views/payment_stripe_template.xml | 8 - ...tripe.xml => payment_stripe_templates.xml} | 6 + ...payment_acquirer.xml => payment_views.xml} | 0 10 files changed, 220 insertions(+), 238 deletions(-) rename addons/payment_stripe/data/{payment_stripe_data.xml => payment_acquirer_data.xml} (100%) create mode 100644 addons/payment_stripe/models/payment.py delete mode 100644 addons/payment_stripe/models/payment_acquirer.py delete mode 100644 addons/payment_stripe/models/payment_token.py delete mode 100644 addons/payment_stripe/models/payment_transaction.py delete mode 100644 addons/payment_stripe/views/payment_stripe_template.xml rename addons/payment_stripe/views/{stripe.xml => payment_stripe_templates.xml} (95%) rename addons/payment_stripe/views/{payment_acquirer.xml => payment_views.xml} (100%) diff --git a/addons/payment_stripe/__openerp__.py b/addons/payment_stripe/__openerp__.py index 80e5f5395c7..60e629dde85 100644 --- a/addons/payment_stripe/__openerp__.py +++ b/addons/payment_stripe/__openerp__.py @@ -8,10 +8,9 @@ 'description': """Stripe Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/stripe.xml', - 'views/payment_acquirer.xml', - 'views/payment_stripe_template.xml', - 'data/payment_stripe_data.xml', + 'views/payment_views.xml', + 'views/payment_stripe_templates.xml', + 'data/payment_acquirer_data.xml', ], 'images': ['static/description/icon.png'], 'installable': True, diff --git a/addons/payment_stripe/data/payment_stripe_data.xml b/addons/payment_stripe/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_stripe/data/payment_stripe_data.xml rename to addons/payment_stripe/data/payment_acquirer_data.xml diff --git a/addons/payment_stripe/models/__init__.py b/addons/payment_stripe/models/__init__.py index fa88cddcbb1..10b988e0c28 100644 --- a/addons/payment_stripe/models/__init__.py +++ b/addons/payment_stripe/models/__init__.py @@ -1,5 +1,3 @@ # -*- coding: utf-8 -*- -import payment_transaction -import payment_acquirer -import payment_token +import payment diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py new file mode 100644 index 00000000000..e1d1d8e1aa8 --- /dev/null +++ b/addons/payment_stripe/models/payment.py @@ -0,0 +1,210 @@ +# coding: utf-8 + +import logging +import requests + +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.exceptions import UserError +from odoo.tools.safe_eval import safe_eval + +_logger = logging.getLogger(__name__) + +# Force the API version to avoid breaking in case of update on Stripe side +# cf https://stripe.com/docs/api#versioning +# changelog https://stripe.com/docs/upgrades#api-changelog +STRIPE_HEADERS = {'Stripe-Version': '2016-03-07'} + + +class PaymentAcquirerStripe(models.Model): + _inherit = 'payment.acquirer' + + stripe_secret_key = fields.Char(required_if_provider='stripe') + stripe_publishable_key = fields.Char(required_if_provider='stripe') + stripe_image_url = fields.Char("Checkout Image URL", + help="A relative or absolute URL pointing to a square image of your " + "brand or product. As defined in your Stripe profile. See: " + "https://stripe.com/docs/checkout") + + @api.model + def _get_providers(self): + providers = super(PaymentAcquirerStripe, self)._get_providers() + providers.append(['stripe', 'Stripe']) + return providers + + @api.multi + def stripe_form_generate_values(self, tx_values): + self.ensure_one() + stripe_tx_values = dict(tx_values) + temp_stripe_tx_values = { + 'amount': tx_values.get('amount'), + 'currency': tx_values.get('currency') and tx_values.get('currency').name or '', + 'address_line1': tx_values['partner_address'], + 'address_city': tx_values['partner_city'], + 'address_country': tx_values['partner_country'] and tx_values['partner_country'].name or '', + 'email': tx_values['partner_email'], + 'address_zip': tx_values['partner_zip'], + 'name': tx_values['partner_name'], + 'phone': tx_values['partner_phone'], + } + + temp_stripe_tx_values['returndata'] = stripe_tx_values.pop('return_url', '') + stripe_tx_values.update(temp_stripe_tx_values) + return stripe_tx_values + + @api.model + def _get_stripe_api_url(self): + return 'api.stripe.com/v1' + + @api.model + def stripe_s2s_form_process(self, data): + payment_token = self.env['payment.token'].sudo().create({ + 'cc_number': data['cc_number'], + 'cc_holder_name': data['cc_holder_name'], + 'cc_expiry': data['cc_expiry'], + 'cc_brand': data['cc_brand'], + 'cvc': data['cvc'], + 'acquirer_id': int(data['acquirer_id']), + 'partner_id': int(data['partner_id']) + }) + return payment_token.id + + @api.multi + def stripe_s2s_form_validate(self, data): + self.ensure_one() + + # mandatory fields + for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]: + if not data.get(field_name): + return False + return True + + +class PaymentTransactionStripe(models.Model): + _inherit = 'payment.transaction' + + def _create_stripe_charge(self, acquirer_ref=None, tokenid=None): + api_url_charge = 'https://%s/charges' % (self.acquirer_id._get_stripe_api_url()) + charge_params = { + 'amount': int(self.amount*100), # Stripe takes amount in cents (https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support) + 'currency': self.currency_id.name, + 'metadata[reference]': self.reference + } + if acquirer_ref: + charge_params['customer'] = acquirer_ref + if tokenid: + charge_params['card'] = str(tokenid) + r = requests.post(api_url_charge, + auth=(self.acquirer_id.stripe_secret_key, ''), + params=charge_params, + headers=STRIPE_HEADERS) + return r.json() + + @api.multi + def stripe_s2s_do_transaction(self, **kwargs): + self.ensure_one() + result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref) + return self._stripe_s2s_validate_tree(result) + + @api.model + def _stripe_form_get_tx_from_data(self, data): + """ Given a data dict coming from stripe, verify it and find the related + transaction record. """ + reference = data['metadata']['reference'] + if not reference: + error_msg = _('Stripe: invalid reply received from provider, missing reference') + _logger.error(error_msg, data['metadata']) + raise ValidationError(error_msg) + tx = self.search([('reference', '=', reference)]) + if not tx: + error_msg = (_('Stripe: no order found for reference %s') % reference) + _logger.error(error_msg) + raise ValidationError(error_msg) + elif len(tx) > 1: + error_msg = (_('Stripe: %s orders found for reference %s') % (len(tx), reference)) + _logger.error(error_msg) + raise ValidationError(error_msg) + return tx[0] + + @api.multi + def _stripe_s2s_validate_tree(self, tree): + self.ensure_one() + if self.state not in ('draft', 'pending'): + _logger.info('Stripe: trying to validate an already validated tx (ref %s)', self.reference) + return True + + status = tree.get('status') + if status == 'succeeded': + self.write({ + 'state': 'done', + 'date_validate': fields.datetime.now(), + 'acquirer_reference': tree.get('id'), + }) + if self.callback_eval: + safe_eval(self.callback_eval, {'self': self}) + return True + else: + error = tree['error']['message'] + _logger.warn(error) + self.sudo().write({ + 'state': 'error', + 'state_message': error, + 'acquirer_reference': tree.get('id'), + 'date_validate': fields.datetime.now(), + }) + return False + + @api.multi + def _stripe_form_get_invalid_parameters(self, data): + invalid_parameters = [] + reference = data['metadata']['reference'] + if reference != self.reference: + invalid_parameters.append(('Reference', reference, self.reference)) + return invalid_parameters + + @api.multi + def _stripe_form_validate(self, data): + return self._stripe_s2s_validate_tree(data) + + +class PaymentTokenStripe(models.Model): + _inherit = 'payment.token' + + @api.model + def stripe_create(self, values): + res = None + payment_acquirer = self.env['payment.acquirer'].browse(values.get('acquirer_id')) + url_token = 'https://%s/tokens' % payment_acquirer._get_stripe_api_url() + url_customer = 'https://%s/customers' % payment_acquirer._get_stripe_api_url() + if values['cc_number']: + payment_params = { + 'card[number]': values['cc_number'].replace(' ', ''), + 'card[exp_month]': str(values['cc_expiry'][:2]), + 'card[exp_year]': str(values['cc_expiry'][-2:]), + 'card[cvc]': values['cvc'], + } + r = requests.post(url_token, + auth=(payment_acquirer.stripe_secret_key, ''), + params=payment_params, + headers=STRIPE_HEADERS) + token = r.json() + if token.get('id'): + customer_params = { + 'source': token['id'] + } + r = requests.post(url_customer, + auth=(payment_acquirer.stripe_secret_key, ''), + params=customer_params, + headers=STRIPE_HEADERS) + customer = r.json() + res = { + 'acquirer_ref': customer['id'], + 'name': 'XXXXXXXXXXXX%s - %s' % (values['cc_number'][-4:], values['cc_holder_name']) + } + elif token.get('error'): + raise UserError(token['error']['message']) + + # pop credit card info to info sent to create + for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]: + values.pop(field_name) + return res diff --git a/addons/payment_stripe/models/payment_acquirer.py b/addons/payment_stripe/models/payment_acquirer.py deleted file mode 100644 index 4dad6b15e5f..00000000000 --- a/addons/payment_stripe/models/payment_acquirer.py +++ /dev/null @@ -1,72 +0,0 @@ -# coding: utf-8 - -from odoo import api, fields, models - -# Force the API version to avoid breaking in case of update on Stripe side -# cf https://stripe.com/docs/api#versioning -# changelog https://stripe.com/docs/upgrades#api-changelog -STRIPE_HEADERS = {'Stripe-Version': '2016-03-07'} - - -class PaymentAcquirerStripe(models.Model): - _inherit = 'payment.acquirer' - - stripe_secret_key = fields.Char(required_if_provider='stripe') - stripe_publishable_key = fields.Char(required_if_provider='stripe') - stripe_image_url = fields.Char("Checkout Image URL", - help="A relative or absolute URL pointing to a square image of your " - "brand or product. As defined in your Stripe profile. See: " - "https://stripe.com/docs/checkout") - - @api.model - def _get_providers(self): - providers = super(PaymentAcquirerStripe, self)._get_providers() - providers.append(['stripe', 'Stripe']) - return providers - - @api.multi - def stripe_form_generate_values(self, tx_values): - self.ensure_one() - stripe_tx_values = dict(tx_values) - temp_stripe_tx_values = { - 'amount': tx_values.get('amount'), - 'currency': tx_values.get('currency') and tx_values.get('currency').name or '', - 'address_line1': tx_values['partner_address'], - 'address_city': tx_values['partner_city'], - 'address_country': tx_values['partner_country'] and tx_values['partner_country'].name or '', - 'email': tx_values['partner_email'], - 'address_zip': tx_values['partner_zip'], - 'name': tx_values['partner_name'], - 'phone': tx_values['partner_phone'], - } - - temp_stripe_tx_values['returndata'] = stripe_tx_values.pop('return_url', '') - stripe_tx_values.update(temp_stripe_tx_values) - return stripe_tx_values - - @api.model - def _get_stripe_api_url(self): - return 'api.stripe.com/v1' - - @api.model - def stripe_s2s_form_process(self, data): - payment_token = self.env['payment.token'].sudo().create({ - 'cc_number': data['cc_number'], - 'cc_holder_name': data['cc_holder_name'], - 'cc_expiry': data['cc_expiry'], - 'cc_brand': data['cc_brand'], - 'cvc': data['cvc'], - 'acquirer_id': int(data['acquirer_id']), - 'partner_id': int(data['partner_id']) - }) - return payment_token.id - - @api.multi - def stripe_s2s_form_validate(self, data): - self.ensure_one() - - # mandatory fields - for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]: - if not data.get(field_name): - return False - return True diff --git a/addons/payment_stripe/models/payment_token.py b/addons/payment_stripe/models/payment_token.py deleted file mode 100644 index ca2921c8a72..00000000000 --- a/addons/payment_stripe/models/payment_token.py +++ /dev/null @@ -1,50 +0,0 @@ -# coding: utf-8 - -import requests - -from odoo import api, models -from odoo.exceptions import UserError -from . import payment_acquirer as pa - - -class PaymentTokenStripe(models.Model): - _inherit = 'payment.token' - - @api.model - def stripe_create(self, values): - res = None - payment_acquirer = self.env['payment.acquirer'].browse(values.get('acquirer_id')) - url_token = 'https://%s/tokens' % payment_acquirer._get_stripe_api_url() - url_customer = 'https://%s/customers' % payment_acquirer._get_stripe_api_url() - if values['cc_number']: - payment_params = { - 'card[number]': values['cc_number'].replace(' ', ''), - 'card[exp_month]': str(values['cc_expiry'][:2]), - 'card[exp_year]': str(values['cc_expiry'][-2:]), - 'card[cvc]': values['cvc'], - } - r = requests.post(url_token, - auth=(payment_acquirer.stripe_secret_key, ''), - params=payment_params, - headers=pa.STRIPE_HEADERS) - token = r.json() - if token.get('id'): - customer_params = { - 'source': token['id'] - } - r = requests.post(url_customer, - auth=(payment_acquirer.stripe_secret_key, ''), - params=customer_params, - headers=pa.STRIPE_HEADERS) - customer = r.json() - res = { - 'acquirer_ref': customer['id'], - 'name': 'XXXXXXXXXXXX%s - %s' % (values['cc_number'][-4:], values['cc_holder_name']) - } - elif token.get('error'): - raise UserError(token['error']['message']) - - # pop credit card info to info sent to create - for field_name in ["cc_number", "cvc", "cc_holder_name", "cc_expiry", "cc_brand"]: - values.pop(field_name) - return res diff --git a/addons/payment_stripe/models/payment_transaction.py b/addons/payment_stripe/models/payment_transaction.py deleted file mode 100644 index c1e3e5608af..00000000000 --- a/addons/payment_stripe/models/payment_transaction.py +++ /dev/null @@ -1,101 +0,0 @@ -# coding: utf-8 - -import json -import logging -import requests -import urllib - -from odoo import api, fields, models, _ -from odoo.addons.payment.models.payment_acquirer import ValidationError -from odoo.tools.safe_eval import safe_eval -from . import payment_acquirer as pa - - -_logger = logging.getLogger(__name__) - - -class PaymentTransactionStripe(models.Model): - _inherit = 'payment.transaction' - - def _create_stripe_charge(self, acquirer_ref=None, tokenid=None): - api_url_charge = 'https://%s/charges' % (self.acquirer_id._get_stripe_api_url()) - charge_params = { - 'amount': int(self.amount*100), # Stripe takes amount in cents (https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support) - 'currency': self.currency_id.name, - 'metadata[reference]': self.reference - } - if acquirer_ref: - charge_params['customer'] = acquirer_ref - if tokenid: - charge_params['card'] = str(tokenid) - r = requests.post(api_url_charge, - auth=(self.acquirer_id.stripe_secret_key, ''), - params=charge_params, - headers=pa.STRIPE_HEADERS) - return r.json() - - @api.multi - def stripe_s2s_do_transaction(self, **kwargs): - self.ensure_one() - result = self._create_stripe_charge(acquirer_ref=self.payment_token_id.acquirer_ref) - return self._stripe_s2s_validate_tree(result) - - @api.model - def _stripe_form_get_tx_from_data(self, data): - """ Given a data dict coming from stripe, verify it and find the related - transaction record. """ - reference = data['metadata']['reference'] - if not reference: - error_msg = _('Stripe: invalid reply received from provider, missing reference') - _logger.error(error_msg, data['metadata']) - raise ValidationError(error_msg) - tx = self.search([('reference', '=', reference)]) - if not tx: - error_msg = (_('Stripe: no order found for reference %s') % reference) - _logger.error(error_msg) - raise ValidationError(error_msg) - elif len(tx) > 1: - error_msg = (_('Stripe: %s orders found for reference %s') % (len(tx), reference)) - _logger.error(error_msg) - raise ValidationError(error_msg) - return tx[0] - - @api.multi - def _stripe_s2s_validate_tree(self, tree): - self.ensure_one() - if self.state not in ('draft', 'pending'): - _logger.info('Stripe: trying to validate an already validated tx (ref %s)', self.reference) - return True - - status = tree.get('status') - if status == 'succeeded': - self.write({ - 'state': 'done', - 'date_validate': fields.datetime.now(), - 'acquirer_reference': tree.get('id'), - }) - if self.callback_eval: - safe_eval(self.callback_eval, {'self': self}) - return True - else: - error = tree['error']['message'] - _logger.warn(error) - self.sudo().write({ - 'state': 'error', - 'state_message': error, - 'acquirer_reference': tree.get('id'), - 'date_validate': fields.datetime.now(), - }) - return False - - @api.multi - def _stripe_form_get_invalid_parameters(self, data): - invalid_parameters = [] - reference = data['metadata']['reference'] - if reference != self.reference: - invalid_parameters.append(('Reference', reference, self.reference)) - return invalid_parameters - - @api.multi - def _stripe_form_validate(self, data): - return self._stripe_s2s_validate_tree(data) diff --git a/addons/payment_stripe/views/payment_stripe_template.xml b/addons/payment_stripe/views/payment_stripe_template.xml deleted file mode 100644 index 74a7d7e03e2..00000000000 --- a/addons/payment_stripe/views/payment_stripe_template.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/addons/payment_stripe/views/stripe.xml b/addons/payment_stripe/views/payment_stripe_templates.xml similarity index 95% rename from addons/payment_stripe/views/stripe.xml rename to addons/payment_stripe/views/payment_stripe_templates.xml index 978f1ffea42..310a26b3531 100644 --- a/addons/payment_stripe/views/stripe.xml +++ b/addons/payment_stripe/views/payment_stripe_templates.xml @@ -64,5 +64,11 @@ + + diff --git a/addons/payment_stripe/views/payment_acquirer.xml b/addons/payment_stripe/views/payment_views.xml similarity index 100% rename from addons/payment_stripe/views/payment_acquirer.xml rename to addons/payment_stripe/views/payment_views.xml From 415eee1ca7c3b7db71c493f288f274f19b662f2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 14:21:26 +0200 Subject: [PATCH 20/22] [CLN] payment_stripe: cleaning and guidelines As this module is already in new API only small linting is performed. --- addons/payment_stripe/models/payment.py | 10 +++----- addons/payment_stripe/tests/test_stripe.py | 27 +++++++++------------- 2 files changed, 14 insertions(+), 23 deletions(-) diff --git a/addons/payment_stripe/models/payment.py b/addons/payment_stripe/models/payment.py index e1d1d8e1aa8..59f9b1a8c82 100644 --- a/addons/payment_stripe/models/payment.py +++ b/addons/payment_stripe/models/payment.py @@ -19,19 +19,15 @@ STRIPE_HEADERS = {'Stripe-Version': '2016-03-07'} class PaymentAcquirerStripe(models.Model): _inherit = 'payment.acquirer' + provider = fields.Selection(selection_add=[('stripe', 'Stripe')]) stripe_secret_key = fields.Char(required_if_provider='stripe') stripe_publishable_key = fields.Char(required_if_provider='stripe') - stripe_image_url = fields.Char("Checkout Image URL", + stripe_image_url = fields.Char( + "Checkout Image URL", help="A relative or absolute URL pointing to a square image of your " "brand or product. As defined in your Stripe profile. See: " "https://stripe.com/docs/checkout") - @api.model - def _get_providers(self): - providers = super(PaymentAcquirerStripe, self)._get_providers() - providers.append(['stripe', 'Stripe']) - return providers - @api.multi def stripe_form_generate_values(self, tx_values): self.ensure_one() diff --git a/addons/payment_stripe/tests/test_stripe.py b/addons/payment_stripe/tests/test_stripe.py index 496ede5c8fd..ef2f6627cd8 100644 --- a/addons/payment_stripe/tests/test_stripe.py +++ b/addons/payment_stripe/tests/test_stripe.py @@ -12,9 +12,7 @@ class StripeCommon(PaymentAcquirerCommon): def setUp(self): super(StripeCommon, self).setUp() - self.currency_euro = self.env['res.currency'].search([('name', '=', 'EUR')], limit=1) - # get the stripe account - self.stripe_id = self.env.ref('payment.payment_acquirer_stripe').id + self.stripe = self.env.ref('payment.payment_acquirer_stripe') @odoo.tests.common.at_install(True) @@ -22,18 +20,17 @@ class StripeCommon(PaymentAcquirerCommon): class StripeTest(StripeCommon): def test_10_stripe_s2s(self): - stripe = self.env['payment.acquirer'].browse(self.stripe_id) - self.assertEqual(stripe.environment, 'test', 'test without test environment') + self.assertEqual(self.stripe.environment, 'test', 'test without test environment') # Add Stripe credentials - stripe.write({ + self.stripe.write({ 'stripe_secret_key': 'sk_test_bldAlqh1U24L5HtRF9mBFpK7', 'stripe_publishable_key': 'pk_test_0TKSyYSZS9AcS4keZ2cxQQCW', }) # Create payment meethod for Stripe payment_token = self.env['payment.token'].create({ - 'acquirer_id': self.stripe_id, + 'acquirer_id': self.stripe.id, 'partner_id': self.buyer_id, 'cc_number': '4242424242424242', 'cc_expiry': '02 / 26', @@ -46,7 +43,7 @@ class StripeTest(StripeCommon): tx = self.env['payment.transaction'].create({ 'reference': 'test_ref_%s' % fields.date.today(), 'currency_id': self.currency_euro.id, - 'acquirer_id': self.stripe_id, + 'acquirer_id': self.stripe.id, 'partner_id': self.buyer_id, 'payment_token_id': payment_token.id, 'type': 'server2server', @@ -58,8 +55,7 @@ class StripeTest(StripeCommon): self.assertEqual(tx.state, 'done', 'Stripe: Transcation has been discarded.') def test_20_stripe_form_render(self): - stripe = self.env['payment.acquirer'].browse(self.stripe_id) - self.assertEqual(stripe.environment, 'test', 'test without test environment') + self.assertEqual(self.stripe.environment, 'test', 'test without test environment') # ---------------------------------------- # Test: button direct rendering @@ -77,7 +73,7 @@ class StripeTest(StripeCommon): } # render the button - res = stripe.render('SO404', 320.0, self.currency_euro.id, values=self.buyer_values) + res = self.stripe.render('SO404', 320.0, self.currency_euro.id, values=self.buyer_values) post_url = "https://checkout.stripe.com/checkout.js" email = "norbert.buyer@example.com" # check form result @@ -91,8 +87,7 @@ class StripeTest(StripeCommon): ) def test_30_stripe_form_management(self): - stripe = self.env['payment.acquirer'].browse(self.stripe_id) - self.assertEqual(stripe.environment, 'test', 'test without test environment') + self.assertEqual(self.stripe.environment, 'test', 'test without test environment') # typical data posted by Stripe after client has successfully paid stripe_post_data = { @@ -153,11 +148,11 @@ class StripeTest(StripeCommon): tx = self.env['payment.transaction'].create({ 'amount': 4700, - 'acquirer_id': self.stripe_id, + 'acquirer_id': self.stripe.id, 'currency_id': self.currency_euro.id, 'reference': 'SO100', 'partner_name': 'Norbert Buyer', - 'partner_country_id': self.country_france_id}) + 'partner_country_id': self.country_france.id}) # validate it tx.form_feedback(stripe_post_data, 'stripe') @@ -168,7 +163,7 @@ class StripeTest(StripeCommon): # simulate an error stripe_post_data['status'] = 'error' stripe_post_data.update({u'error': {u'message': u"Your card's expiration year is invalid.", u'code': u'invalid_expiry_year', u'type': u'card_error', u'param': u'exp_year'}}) - with mute_logger('openerp.addons.payment_stripe.models.payment_transaction'): + with mute_logger('openerp.addons.payment_stripe.models.payment'): tx.form_feedback(stripe_post_data, 'stripe') # check state self.assertEqual(tx.state, 'error', 'Stipe: erroneous validation did not put tx into error state') From 1d227799ac37860a402e86ae4770543c67df45ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 13:53:47 +0200 Subject: [PATCH 21/22] [MOV] payment_transfer: file organization --- addons/payment_transfer/__openerp__.py | 4 ++-- .../data/{transfer.xml => payment_acquirer_data.xml} | 0 addons/payment_transfer/models/__init__.py | 2 +- .../models/{payment_acquirer.py => payment.py} | 0 .../views/{transfer.xml => payment_transfer_templates.xml} | 0 5 files changed, 3 insertions(+), 3 deletions(-) rename addons/payment_transfer/data/{transfer.xml => payment_acquirer_data.xml} (100%) rename addons/payment_transfer/models/{payment_acquirer.py => payment.py} (100%) rename addons/payment_transfer/views/{transfer.xml => payment_transfer_templates.xml} (100%) diff --git a/addons/payment_transfer/__openerp__.py b/addons/payment_transfer/__openerp__.py index c5fa2f171b8..d26949df288 100644 --- a/addons/payment_transfer/__openerp__.py +++ b/addons/payment_transfer/__openerp__.py @@ -8,8 +8,8 @@ 'description': """Transfer Payment Acquirer""", 'depends': ['payment'], 'data': [ - 'views/transfer.xml', - 'data/transfer.xml', + 'views/payment_transfer_templates.xml', + 'data/payment_acquirer_data.xml', ], 'installable': True, 'auto_install': True, diff --git a/addons/payment_transfer/data/transfer.xml b/addons/payment_transfer/data/payment_acquirer_data.xml similarity index 100% rename from addons/payment_transfer/data/transfer.xml rename to addons/payment_transfer/data/payment_acquirer_data.xml diff --git a/addons/payment_transfer/models/__init__.py b/addons/payment_transfer/models/__init__.py index da51c9c1854..10b988e0c28 100644 --- a/addons/payment_transfer/models/__init__.py +++ b/addons/payment_transfer/models/__init__.py @@ -1,3 +1,3 @@ # -*- coding: utf-8 -*- -import payment_acquirer +import payment diff --git a/addons/payment_transfer/models/payment_acquirer.py b/addons/payment_transfer/models/payment.py similarity index 100% rename from addons/payment_transfer/models/payment_acquirer.py rename to addons/payment_transfer/models/payment.py diff --git a/addons/payment_transfer/views/transfer.xml b/addons/payment_transfer/views/payment_transfer_templates.xml similarity index 100% rename from addons/payment_transfer/views/transfer.xml rename to addons/payment_transfer/views/payment_transfer_templates.xml From 48278ed39511ef8d58356f97afd67f78d2e86a5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 5 Jul 2016 14:24:14 +0200 Subject: [PATCH 22/22] [MIG] payment_transfer No functional change. --- addons/payment_transfer/controllers/main.py | 7 +- .../data/payment_acquirer_data.xml | 4 +- addons/payment_transfer/models/payment.py | 65 +++++++++---------- .../views/payment_transfer_templates.xml | 4 +- 4 files changed, 36 insertions(+), 44 deletions(-) diff --git a/addons/payment_transfer/controllers/main.py b/addons/payment_transfer/controllers/main.py index 055858222e0..6411414c597 100644 --- a/addons/payment_transfer/controllers/main.py +++ b/addons/payment_transfer/controllers/main.py @@ -3,8 +3,8 @@ import logging import pprint import werkzeug -from openerp import http, SUPERUSER_ID -from openerp.http import request +from odoo import http +from odoo.http import request _logger = logging.getLogger(__name__) @@ -16,7 +16,6 @@ class OgoneController(http.Controller): '/payment/transfer/feedback', ], type='http', auth='none', csrf=False) def transfer_form_feedback(self, **post): - cr, uid, context = request.cr, SUPERUSER_ID, request.context _logger.info('Beginning form_feedback with post data %s', pprint.pformat(post)) # debug - request.registry['payment.transaction'].form_feedback(cr, uid, post, 'transfer', context) + request.env['payment.transaction'].sudo().form_feedback(post, 'transfer') return werkzeug.utils.redirect(post.pop('return_url', '/')) diff --git a/addons/payment_transfer/data/payment_acquirer_data.xml b/addons/payment_transfer/data/payment_acquirer_data.xml index 141dc84f7d5..cab245767cb 100644 --- a/addons/payment_transfer/data/payment_acquirer_data.xml +++ b/addons/payment_transfer/data/payment_acquirer_data.xml @@ -1,5 +1,5 @@ - + @@ -17,4 +17,4 @@ - + diff --git a/addons/payment_transfer/models/payment.py b/addons/payment_transfer/models/payment.py index 126329e8a6f..2ec43959bd6 100644 --- a/addons/payment_transfer/models/payment.py +++ b/addons/payment_transfer/models/payment.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- -from openerp.addons.payment.models.payment_acquirer import ValidationError -from openerp.osv import osv -from openerp.tools.float_utils import float_compare -from openerp.tools.translate import _ +from odoo import api, fields, models, _ +from odoo.addons.payment.models.payment_acquirer import ValidationError +from odoo.tools.float_utils import float_compare import logging import pprint @@ -11,22 +10,19 @@ import pprint _logger = logging.getLogger(__name__) -class TransferPaymentAcquirer(osv.Model): +class TransferPaymentAcquirer(models.Model): _inherit = 'payment.acquirer' - def _get_providers(self, cr, uid, context=None): - providers = super(TransferPaymentAcquirer, self)._get_providers(cr, uid, context=context) - providers.append(['transfer', _('Wire Transfer')]) - return providers + provider = fields.Selection(selection_add=[('transfer', 'Wire Transfer')]) - def transfer_get_form_action_url(self, cr, uid, ids, context=None): + def transfer_get_form_action_url(self): return '/payment/transfer/feedback' - def _format_transfer_data(self, cr, uid, context=None): - company_id = self.pool['res.users'].browse(cr, uid, uid, context=context).company_id.id + def _format_transfer_data(self): + company_id = self.env.user.company_id.id # filter only bank accounts marked as visible - journal_ids = self.pool['account.journal'].search(cr, uid, [('type', '=', 'bank'), ('display_on_footer', '=', True), ('company_id', '=', company_id)], context=context) - accounts = self.pool['account.journal'].browse(cr, uid, journal_ids, context=context).mapped('bank_account_id').name_get() + journals = self.env['account.journal'].search([('type', '=', 'bank'), ('display_on_footer', '=', True), ('company_id', '=', company_id)]) + accounts = journals.mapped('bank_account_id').name_get() bank_title = _('Bank Accounts') if len(accounts) > 1 else _('Bank Account') bank_accounts = ''.join(['
    '] + ['
  • %s
  • ' % name for id, name in accounts] + ['
']) post_msg = '''
@@ -41,48 +37,45 @@ class TransferPaymentAcquirer(osv.Model): } return post_msg - def create(self, cr, uid, values, context=None): + @api.model + def create(self, values): """ Hook in create to create a default post_msg. This is done in create to have access to the name and other creation values. If no post_msg or a void post_msg is given at creation, generate a default one. """ if values.get('provider') == 'transfer' and not values.get('post_msg'): - values['post_msg'] = self._format_transfer_data(cr, uid, context=context) - return super(TransferPaymentAcquirer, self).create(cr, uid, values, context=context) + values['post_msg'] = self._format_transfer_data() + return super(TransferPaymentAcquirer, self).create(values) -class TransferPaymentTransaction(osv.Model): +class TransferPaymentTransaction(models.Model): _inherit = 'payment.transaction' - def _transfer_form_get_tx_from_data(self, cr, uid, data, context=None): + @api.model + def _transfer_form_get_tx_from_data(self, data): reference, amount, currency_name = data.get('reference'), data.get('amount'), data.get('currency_name') - tx_ids = self.search( - cr, uid, [ - ('reference', '=', reference), - ], context=context) + tx = self.search([('reference', '=', reference)]) - if not tx_ids or len(tx_ids) > 1: + if not tx or len(tx) > 1: error_msg = _('received data for reference %s') % (pprint.pformat(reference)) - if not tx_ids: + if not tx: 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) + return tx - def _transfer_form_get_invalid_parameters(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] + def _transfer_form_get_invalid_parameters(self, data): invalid_parameters = [] - if float_compare(float(data.get('amount', '0.0')), tx.amount, 2) != 0: - invalid_parameters.append(('amount', data.get('amount'), '%.2f' % tx.amount)) - if data.get('currency') != tx.currency_id.name: - invalid_parameters.append(('currency', data.get('currency'), tx.currency_id.name)) + if float_compare(float(data.get('amount', '0.0')), self.amount, 2) != 0: + invalid_parameters.append(('amount', data.get('amount'), '%.2f' % self.amount)) + if data.get('currency') != self.currency_id.name: + invalid_parameters.append(('currency', data.get('currency'), self.currency_id.name)) return invalid_parameters - def _transfer_form_validate(self, cr, uid, ids, data, context=None): - tx = self.browse(cr, uid, ids, context=context)[0] - _logger.info('Validated transfer payment for tx %s: set as pending' % (tx.reference)) - return tx.write({'state': 'pending'}) + def _transfer_form_validate(self, data): + _logger.info('Validated transfer payment for tx %s: set as pending' % (self.reference)) + return self.write({'state': 'pending'}) diff --git a/addons/payment_transfer/views/payment_transfer_templates.xml b/addons/payment_transfer/views/payment_transfer_templates.xml index 787cf848f74..0716d99c349 100644 --- a/addons/payment_transfer/views/payment_transfer_templates.xml +++ b/addons/payment_transfer/views/payment_transfer_templates.xml @@ -1,5 +1,5 @@ - + - +