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] [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