diff options
Diffstat (limited to 'addons/payment_authorize/models')
| -rw-r--r-- | addons/payment_authorize/models/__init__.py | 2 | ||||
| -rw-r--r-- | addons/payment_authorize/models/authorize_request.py | 401 | ||||
| -rw-r--r-- | addons/payment_authorize/models/payment.py | 335 |
3 files changed, 738 insertions, 0 deletions
diff --git a/addons/payment_authorize/models/__init__.py b/addons/payment_authorize/models/__init__.py new file mode 100644 index 00000000..01bcbec2 --- /dev/null +++ b/addons/payment_authorize/models/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import payment diff --git a/addons/payment_authorize/models/authorize_request.py b/addons/payment_authorize/models/authorize_request.py new file mode 100644 index 00000000..78db4977 --- /dev/null +++ b/addons/payment_authorize/models/authorize_request.py @@ -0,0 +1,401 @@ +# -*- coding: utf-8 -*- +import json +import logging +import requests + +from uuid import uuid4 + +from odoo import _ +from odoo.exceptions import UserError + +from odoo.addons.payment.models.payment_acquirer import _partner_split_name + +_logger = logging.getLogger(__name__) + + +class AuthorizeAPI(): + """Authorize.net Gateway API integration. + + This class allows contacting the Authorize.net API with simple operation + requests. It implements a *very limited* subset of the complete API + (http://developer.authorize.net/api/reference); namely: + - Customer Profile/Payment Profile creation + - Transaction authorization/capture/voiding + """ + + AUTH_ERROR_STATUS = 3 + + def __init__(self, acquirer): + """Initiate the environment with the acquirer data. + + :param record acquirer: payment.acquirer account that will be contacted + """ + if acquirer.state == 'test': + self.url = 'https://apitest.authorize.net/xml/v1/request.api' + else: + self.url = 'https://api.authorize.net/xml/v1/request.api' + + self.state = acquirer.state + self.name = acquirer.authorize_login + self.transaction_key = acquirer.authorize_transaction_key + + def _authorize_request(self, data): + _logger.info('_authorize_request: Sending values to URL %s, values:\n%s', self.url, data) + resp = requests.post(self.url, json.dumps(data)) + resp.raise_for_status() + resp = json.loads(resp.content) + _logger.info("_authorize_request: Received response:\n%s", resp) + messages = resp.get('messages') + if messages and messages.get('resultCode') == 'Error': + return { + 'err_code': messages.get('message')[0].get('code'), + 'err_msg': messages.get('message')[0].get('text') + } + + return resp + + # Customer profiles + def create_customer_profile(self, partner, opaqueData): + """Create a payment and customer profile in the Authorize.net backend. + + Creates a customer profile for the partner/credit card combination and links + a corresponding payment profile to it. Note that a single partner in the Odoo + database can have multiple customer profiles in Authorize.net (i.e. a customer + profile is created for every res.partner/payment.token couple). + + :param record partner: the res.partner record of the customer + :param str cardnumber: cardnumber in string format (numbers only, no separator) + :param str expiration_date: expiration date in 'YYYY-MM' string format + :param str card_code: three- or four-digit verification number + + :return: a dict containing the profile_id and payment_profile_id of the + newly created customer profile and payment profile + :rtype: dict + """ + values = { + 'createCustomerProfileRequest': { + 'merchantAuthentication': { + 'name': self.name, + 'transactionKey': self.transaction_key + }, + 'profile': { + 'description': ('ODOO-%s-%s' % (partner.id, uuid4().hex[:8]))[:20], + 'email': partner.email or '', + 'paymentProfiles': { + 'customerType': 'business' if partner.is_company else 'individual', + 'billTo': { + 'firstName': '' if partner.is_company else _partner_split_name(partner.name)[0], + 'lastName': _partner_split_name(partner.name)[1], + 'address': (partner.street or '' + (partner.street2 if partner.street2 else '')) or None, + 'city': partner.city, + 'state': partner.state_id.name or None, + 'zip': partner.zip or '', + 'country': partner.country_id.name or None, + 'phoneNumber': partner.phone or '', + }, + 'payment': { + 'opaqueData': { + 'dataDescriptor': opaqueData.get('dataDescriptor'), + 'dataValue': opaqueData.get('dataValue') + } + } + } + }, + 'validationMode': 'liveMode' if self.state == 'enabled' else 'testMode' + } + } + + response = self._authorize_request(values) + + if response and response.get('err_code'): + raise UserError(_( + "Authorize.net Error:\nCode: %s\nMessage: %s", + response.get('err_code'), response.get('err_msg'), + )) + + return { + 'profile_id': response.get('customerProfileId'), + 'payment_profile_id': response.get('customerPaymentProfileIdList')[0] + } + + def create_customer_profile_from_tx(self, partner, transaction_id): + """Create an Auth.net payment/customer profile from an existing transaction. + + Creates a customer profile for the partner/credit card combination and links + a corresponding payment profile to it. Note that a single partner in the Odoo + database can have multiple customer profiles in Authorize.net (i.e. a customer + profile is created for every res.partner/payment.token couple). + + Note that this function makes 2 calls to the authorize api, since we need to + obtain a partial cardnumber to generate a meaningful payment.token name. + + :param record partner: the res.partner record of the customer + :param str transaction_id: id of the authorized transaction in the + Authorize.net backend + + :return: a dict containing the profile_id and payment_profile_id of the + newly created customer profile and payment profile as well as the + last digits of the card number + :rtype: dict + """ + values = { + 'createCustomerProfileFromTransactionRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + 'transId': transaction_id, + 'customer': { + 'merchantCustomerId': ('ODOO-%s-%s' % (partner.id, uuid4().hex[:8]))[:20], + 'email': partner.email or '' + } + } + } + + response = self._authorize_request(values) + + if not response.get('customerProfileId'): + _logger.warning( + 'Unable to create customer payment profile, data missing from transaction. Transaction_id: %s - Partner_id: %s' + % (transaction_id, partner) + ) + return False + + res = { + 'profile_id': response.get('customerProfileId'), + 'payment_profile_id': response.get('customerPaymentProfileIdList')[0] + } + + values = { + 'getCustomerPaymentProfileRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + 'customerProfileId': res['profile_id'], + 'customerPaymentProfileId': res['payment_profile_id'], + } + } + + response = self._authorize_request(values) + + res['name'] = response.get('paymentProfile', {}).get('payment', {}).get('creditCard', {}).get('cardNumber') + return res + + # Transaction management + def auth_and_capture(self, token, amount, reference): + """Authorize and capture a payment for the given amount. + + Authorize and immediately capture a payment for the given payment.token + record for the specified amount with reference as communication. + + :param record token: the payment.token record that must be charged + :param str amount: transaction amount (up to 15 digits with decimal point) + :param str reference: used as "invoiceNumber" in the Authorize.net backend + + :return: a dict containing the response code, transaction id and transaction type + :rtype: dict + """ + values = { + 'createTransactionRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + 'transactionRequest': { + 'transactionType': 'authCaptureTransaction', + 'amount': str(amount), + 'profile': { + 'customerProfileId': token.authorize_profile, + 'paymentProfile': { + 'paymentProfileId': token.acquirer_ref, + } + }, + 'order': { + 'invoiceNumber': reference[:20], + 'description': reference[:255], + } + } + + } + } + response = self._authorize_request(values) + + if response and response.get('err_code'): + return { + 'x_response_code': self.AUTH_ERROR_STATUS, + 'x_response_reason_text': response.get('err_msg') + } + + result = { + 'x_response_code': response.get('transactionResponse', {}).get('responseCode'), + 'x_trans_id': response.get('transactionResponse', {}).get('transId'), + 'x_type': 'auth_capture' + } + errors = response.get('transactionResponse', {}).get('errors') + if errors: + result['x_response_reason_text'] = '\n'.join([e.get('errorText') for e in errors]) + return result + + def authorize(self, token, amount, reference): + """Authorize a payment for the given amount. + + Authorize (without capture) a payment for the given payment.token + record for the specified amount with reference as communication. + + :param record token: the payment.token record that must be charged + :param str amount: transaction amount (up to 15 digits with decimal point) + :param str reference: used as "invoiceNumber" in the Authorize.net backend + + :return: a dict containing the response code, transaction id and transaction type + :rtype: dict + """ + values = { + 'createTransactionRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + 'transactionRequest': { + 'transactionType': 'authOnlyTransaction', + 'amount': str(amount), + 'profile': { + 'customerProfileId': token.authorize_profile, + 'paymentProfile': { + 'paymentProfileId': token.acquirer_ref, + } + }, + 'order': { + 'invoiceNumber': reference[:20], + 'description': reference[:255], + } + } + + } + } + response = self._authorize_request(values) + + if response and response.get('err_code'): + return { + 'x_response_code': self.AUTH_ERROR_STATUS, + 'x_response_reason_text': response.get('err_msg') + } + + return { + 'x_response_code': response.get('transactionResponse', {}).get('responseCode'), + 'x_trans_id': response.get('transactionResponse', {}).get('transId'), + 'x_type': 'auth_only' + } + + def capture(self, transaction_id, amount): + """Capture a previously authorized payment for the given amount. + + Capture a previsouly authorized payment. Note that the amount is required + even though we do not support partial capture. + + :param str transaction_id: id of the authorized transaction in the + Authorize.net backend + :param str amount: transaction amount (up to 15 digits with decimal point) + + :return: a dict containing the response code, transaction id and transaction type + :rtype: dict + """ + values = { + 'createTransactionRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + 'transactionRequest': { + 'transactionType': 'priorAuthCaptureTransaction', + 'amount': str(amount), + 'refTransId': transaction_id, + } + } + } + + response = self._authorize_request(values) + + if response and response.get('err_code'): + return { + 'x_response_code': self.AUTH_ERROR_STATUS, + 'x_response_reason_text': response.get('err_msg') + } + + return { + 'x_response_code': response.get('transactionResponse', {}).get('responseCode'), + 'x_trans_id': response.get('transactionResponse', {}).get('transId'), + 'x_type': 'prior_auth_capture' + } + + def void(self, transaction_id): + """Void a previously authorized payment. + + :param str transaction_id: the id of the authorized transaction in the + Authorize.net backend + + :return: a dict containing the response code, transaction id and transaction type + :rtype: dict + """ + values = { + 'createTransactionRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + 'transactionRequest': { + 'transactionType': 'voidTransaction', + 'refTransId': transaction_id + } + } + } + + response = self._authorize_request(values) + + if response and response.get('err_code'): + return { + 'x_response_code': self.AUTH_ERROR_STATUS, + 'x_response_reason_text': response.get('err_msg') + } + + return { + 'x_response_code': response.get('transactionResponse', {}).get('responseCode'), + 'x_trans_id': response.get('transactionResponse', {}).get('transId'), + 'x_type': 'void' + } + + # Test + def test_authenticate(self): + """Test Authorize.net communication with a simple credentials check. + + :return: True if authentication was successful, else False (or throws an error) + :rtype: bool + """ + values = { + 'authenticateTestRequest': { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key + }, + } + } + + response = self._authorize_request(values) + if response and response.get('err_code'): + return False + return True + + # Client Key + def get_client_secret(self): + """ Create a client secret that will be needed for the AcceptJS integration. """ + values = { + "getMerchantDetailsRequest": { + "merchantAuthentication": { + "name": self.name, + "transactionKey": self.transaction_key, + } + } + } + response = self._authorize_request(values) + client_secret = response.get('publicClientKey') + return client_secret diff --git a/addons/payment_authorize/models/payment.py b/addons/payment_authorize/models/payment.py new file mode 100644 index 00000000..c4146253 --- /dev/null +++ b/addons/payment_authorize/models/payment.py @@ -0,0 +1,335 @@ +# coding: utf-8 +from werkzeug import urls + +from .authorize_request import AuthorizeAPI +import hashlib +import hmac +import logging +import time + +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, float_repr +from odoo.exceptions import UserError + +_logger = logging.getLogger(__name__) + + +class PaymentAcquirerAuthorize(models.Model): + _inherit = 'payment.acquirer' + + provider = fields.Selection(selection_add=[ + ('authorize', 'Authorize.Net') + ], ondelete={'authorize': 'set default'}) + authorize_login = fields.Char(string='API Login Id', required_if_provider='authorize', groups='base.group_user') + authorize_transaction_key = fields.Char(string='API Transaction Key', required_if_provider='authorize', groups='base.group_user') + authorize_signature_key = fields.Char(string='API Signature Key', required_if_provider='authorize', groups='base.group_user') + authorize_client_key = fields.Char(string='API Client Key', groups='base.group_user') + + @api.onchange('provider', 'check_validity') + def onchange_check_validity(self): + if self.provider == 'authorize' and self.check_validity: + self.check_validity = False + return {'warning': { + 'title': _("Warning"), + 'message': ('This option is not supported for Authorize.net')}} + + def action_client_secret(self): + api = AuthorizeAPI(self) + if not api.test_authenticate(): + raise UserError(_('Unable to fetch Client Key, make sure the API Login and Transaction Key are correct.')) + self.authorize_client_key = api.get_client_secret() + return True + + def _get_feature_support(self): + """Get advanced feature support by provider. + + Each provider should add its technical in the corresponding + key for the following features: + * fees: support payment fees computations + * authorize: support authorizing payment (separates + authorization and capture) + * tokenize: support saving payment data in a payment.tokenize + object + """ + res = super(PaymentAcquirerAuthorize, self)._get_feature_support() + res['authorize'].append('authorize') + res['tokenize'].append('authorize') + return res + + def _get_authorize_urls(self, environment): + """ Authorize URLs """ + if environment == 'prod': + return {'authorize_form_url': 'https://secure2.authorize.net/gateway/transact.dll'} + else: + return {'authorize_form_url': 'https://test.authorize.net/gateway/transact.dll'} + + def _authorize_generate_hashing(self, values): + data = '^'.join([ + values['x_login'], + values['x_fp_sequence'], + values['x_fp_timestamp'], + values['x_amount'], + values['x_currency_code']]).encode('utf-8') + + return hmac.new(bytes.fromhex(self.authorize_signature_key), data, hashlib.sha512).hexdigest().upper() + + def authorize_form_generate_values(self, values): + self.ensure_one() + # State code is only supported in US, use state name by default + # See https://developer.authorize.net/api/reference/ + state = values['partner_state'].name if values.get('partner_state') else '' + if values.get('partner_country') and values.get('partner_country') == self.env.ref('base.us', False): + state = values['partner_state'].code if values.get('partner_state') else '' + billing_state = values['billing_partner_state'].name if values.get('billing_partner_state') else '' + if values.get('billing_partner_country') and values.get('billing_partner_country') == self.env.ref('base.us', False): + billing_state = values['billing_partner_state'].code if values.get('billing_partner_state') else '' + + base_url = self.get_base_url() + authorize_tx_values = dict(values) + temp_authorize_tx_values = { + 'x_login': self.authorize_login, + 'x_amount': float_repr(values['amount'], values['currency'].decimal_places if values['currency'] else 2), + 'x_show_form': 'PAYMENT_FORM', + 'x_type': 'AUTH_CAPTURE' if not self.capture_manually else 'AUTH_ONLY', + 'x_method': 'CC', + 'x_fp_sequence': '%s%s' % (self.id, int(time.time())), + 'x_version': '3.1', + 'x_relay_response': 'TRUE', + 'x_fp_timestamp': str(int(time.time())), + 'x_relay_url': urls.url_join(base_url, AuthorizeController._return_url), + 'x_cancel_url': urls.url_join(base_url, AuthorizeController._cancel_url), + 'x_currency_code': values['currency'] and values['currency'].name or '', + 'address': values.get('partner_address'), + 'city': values.get('partner_city'), + 'country': values.get('partner_country') and values.get('partner_country').name or '', + 'email': values.get('partner_email'), + 'zip_code': values.get('partner_zip'), + 'first_name': values.get('partner_first_name'), + 'last_name': values.get('partner_last_name'), + 'phone': values.get('partner_phone'), + 'state': state, + 'billing_address': values.get('billing_partner_address'), + 'billing_city': values.get('billing_partner_city'), + 'billing_country': values.get('billing_partner_country') and values.get('billing_partner_country').name or '', + 'billing_email': values.get('billing_partner_email'), + 'billing_zip_code': values.get('billing_partner_zip'), + 'billing_first_name': values.get('billing_partner_first_name'), + 'billing_last_name': values.get('billing_partner_last_name'), + 'billing_phone': values.get('billing_partner_phone'), + 'billing_state': billing_state, + } + temp_authorize_tx_values['returndata'] = authorize_tx_values.pop('return_url', '') + temp_authorize_tx_values['x_fp_hash'] = self._authorize_generate_hashing(temp_authorize_tx_values) + authorize_tx_values.update(temp_authorize_tx_values) + return authorize_tx_values + + def authorize_get_form_action_url(self): + self.ensure_one() + environment = 'prod' if self.state == 'enabled' else 'test' + return self._get_authorize_urls(environment)['authorize_form_url'] + + @api.model + def authorize_s2s_form_process(self, data): + values = { + 'opaqueData': data.get('opaqueData'), + 'encryptedCardData': data.get('encryptedCardData'), + 'acquirer_id': int(data.get('acquirer_id')), + 'partner_id': int(data.get('partner_id')) + } + PaymentMethod = self.env['payment.token'].sudo().create(values) + return PaymentMethod + + def authorize_s2s_form_validate(self, data): + error = dict() + mandatory_fields = ["opaqueData", "encryptedCardData"] + # Validation + for field_name in mandatory_fields: + if not data.get(field_name): + error[field_name] = 'missing' + return False if error else True + + def authorize_test_credentials(self): + self.ensure_one() + transaction = AuthorizeAPI(self.acquirer_id) + return transaction.test_authenticate() + +class TxAuthorize(models.Model): + _inherit = 'payment.transaction' + + _authorize_valid_tx_status = 1 + _authorize_pending_tx_status = 4 + _authorize_cancel_tx_status = 2 + _authorize_error_tx_status = 3 + + # -------------------------------------------------- + # FORM RELATED METHODS + # -------------------------------------------------- + + @api.model + def _authorize_form_get_tx_from_data(self, data): + """ Given a data dict coming from authorize, verify it and find the related + transaction record. """ + reference, description, trans_id, fingerprint = data.get('x_invoice_num'), data.get('x_description'), data.get('x_trans_id'), data.get('x_SHA2_Hash') or data.get('x_MD5_Hash') + if not reference or not trans_id or not fingerprint: + error_msg = _('Authorize: received data with missing reference (%s) or trans_id (%s) or fingerprint (%s)') % (reference, trans_id, fingerprint) + _logger.info(error_msg) + raise ValidationError(error_msg) + tx = self.search(['|', ('reference', '=', reference), ('reference', '=', description)]) + if not tx or len(tx) > 1: + error_msg = 'Authorize: received data for x_invoice_num %s and x_description %s' % (reference, description) + if not tx: + error_msg += '; no order found' + else: + error_msg += '; multiple order found' + _logger.info(error_msg) + raise ValidationError(error_msg) + return tx[0] + + 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')), self.amount, 2) != 0: + invalid_parameters.append(('Amount', data.get('x_amount'), '%.2f' % self.amount)) + return invalid_parameters + + 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: + if data.get('x_type').lower() in ['auth_capture', 'prior_auth_capture']: + self.write({ + 'acquirer_reference': data.get('x_trans_id'), + 'date': fields.Datetime.now(), + }) + self._set_transaction_done() + elif data.get('x_type').lower() in ['auth_only']: + self.write({'acquirer_reference': data.get('x_trans_id')}) + self._set_transaction_authorized() + if self.partner_id and not self.payment_token_id and \ + (self.type == 'form_save' or self.acquirer_id.save_token == 'always'): + transaction = AuthorizeAPI(self.acquirer_id) + res = transaction.create_customer_profile_from_tx(self.partner_id, self.acquirer_reference) + if res: + token_id = self.env['payment.token'].create({ + 'authorize_profile': res.get('profile_id'), + 'name': res.get('name'), + 'acquirer_ref': res.get('payment_profile_id'), + 'acquirer_id': self.acquirer_id.id, + 'partner_id': self.partner_id.id, + }) + self.payment_token_id = token_id + return True + elif status_code == self._authorize_pending_tx_status: + self.write({'acquirer_reference': data.get('x_trans_id')}) + self._set_transaction_pending() + return True + else: + error = data.get('x_response_reason_text') + _logger.info(error) + self.write({ + 'state_message': error, + 'acquirer_reference': data.get('x_trans_id'), + }) + self._set_transaction_cancel() + return False + + def authorize_s2s_do_transaction(self, **data): + self.ensure_one() + transaction = AuthorizeAPI(self.acquirer_id) + + if not self.payment_token_id.authorize_profile: + raise UserError(_('Invalid token found: the Authorize profile is missing.' + 'Please make sure the token has a valid acquirer reference.')) + + if not self.acquirer_id.capture_manually: + res = transaction.auth_and_capture(self.payment_token_id, round(self.amount, self.currency_id.decimal_places), self.reference) + else: + res = transaction.authorize(self.payment_token_id, round(self.amount, self.currency_id.decimal_places), self.reference) + return self._authorize_s2s_validate_tree(res) + + def authorize_s2s_capture_transaction(self): + self.ensure_one() + transaction = AuthorizeAPI(self.acquirer_id) + tree = transaction.capture(self.acquirer_reference or '', round(self.amount, self.currency_id.decimal_places)) + return self._authorize_s2s_validate_tree(tree) + + def authorize_s2s_void_transaction(self): + self.ensure_one() + transaction = AuthorizeAPI(self.acquirer_id) + tree = transaction.void(self.acquirer_reference or '') + return self._authorize_s2s_validate_tree(tree) + + def _authorize_s2s_validate_tree(self, tree): + return self._authorize_s2s_validate(tree) + + def _authorize_s2s_validate(self, tree): + if self.state == 'done': + _logger.warning('Authorize: trying to validate an already validated tx (ref %s)' % self.reference) + return True + status_code = int(tree.get('x_response_code', '0')) + if status_code == self._authorize_valid_tx_status: + if tree.get('x_type').lower() in ['auth_capture', 'prior_auth_capture']: + init_state = self.state + self.write({ + 'acquirer_reference': tree.get('x_trans_id'), + 'date': fields.Datetime.now(), + }) + + self._set_transaction_done() + + if init_state != 'authorized': + self.execute_callback() + if tree.get('x_type').lower() == 'auth_only': + self.write({'acquirer_reference': tree.get('x_trans_id')}) + self._set_transaction_authorized() + self.execute_callback() + if tree.get('x_type').lower() == 'void': + self._set_transaction_cancel() + return True + elif status_code == self._authorize_pending_tx_status: + self.write({'acquirer_reference': tree.get('x_trans_id')}) + self._set_transaction_pending() + return True + else: + error = tree.get('x_response_reason_text') + _logger.info(error) + self.write({ + 'acquirer_reference': tree.get('x_trans_id'), + }) + self._set_transaction_error(msg=error) + return False + + +class PaymentToken(models.Model): + _inherit = 'payment.token' + + authorize_profile = fields.Char(string='Authorize.net Profile ID', help='This contains the unique reference ' + 'for this partner/payment token combination in the Authorize.net backend') + provider = fields.Selection(string='Provider', related='acquirer_id.provider', readonly=False) + save_token = fields.Selection(string='Save Cards', related='acquirer_id.save_token', readonly=False) + + @api.model + def authorize_create(self, values): + if values.get('opaqueData') and values.get('encryptedCardData'): + acquirer = self.env['payment.acquirer'].browse(values['acquirer_id']) + partner = self.env['res.partner'].browse(values['partner_id']) + transaction = AuthorizeAPI(acquirer) + res = transaction.create_customer_profile(partner, values['opaqueData']) + if res.get('profile_id') and res.get('payment_profile_id'): + return { + 'authorize_profile': res.get('profile_id'), + 'name': values['encryptedCardData'].get('cardNumber'), + 'acquirer_ref': res.get('payment_profile_id'), + 'verified': True + } + else: + raise ValidationError(_('The Customer Profile creation in Authorize.NET failed.')) + else: + return values |
