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.get('reference') if not reference: stripe_error = data.get('error', {}).get('message', '') _logger.error( 'Stripe: invalid reply received from stripe API, looks like ' 'the transaction failed. (error: %s)', stripe_error or 'n/a') error_msg = _( "We're sorry to report that the transaction has failed.") if stripe_error: error_msg += " " + (_( "Stripe gave us the following info about the problem: '%s'" ) % stripe_error) error_msg += " " + _( "Perhaps the problem can be solved by double-checking your " "credit card details, or contacting your bank?") 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]
def _payulatam_form_get_tx_from_data(self, data): """ Given a data dict coming from payulatam, verify it and find the related transaction record. """ reference, txnid, sign = data.get('referenceCode'), data.get( 'transactionId'), data.get('signature') if not reference or not txnid or not sign: raise ValidationError( _('PayU Latam: received data with missing reference (%s) or transaction id (%s) or sign (%s)' ) % (reference, txnid, sign)) transaction = self.search([('reference', '=', reference)]) if not transaction: error_msg = ( _('PayU Latam: received data for reference %s; no order found') % (reference)) raise ValidationError(error_msg) elif len(transaction) > 1: error_msg = (_( 'PayU Latam: received data for reference %s; multiple orders found' ) % (reference)) raise ValidationError(error_msg) # verify shasign sign_check = transaction.acquirer_id._payulatam_generate_sign( 'out', data) if sign_check.upper() != sign.upper(): raise ValidationError(( 'PayU Latam: invalid sign, received %s, computed %s, for data %s' ) % (sign, sign_check, data)) return transaction
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
def _stripe_request(self, url, data=False, method='POST'): self.ensure_one() url = urls.url_join(self._get_stripe_api_url(), url) headers = { 'AUTHORIZATION': 'Bearer %s' % self.sudo().stripe_secret_key, 'Stripe-Version': '2019-05-16', # SetupIntent need a specific version } resp = requests.request(method, url, data=data, headers=headers) # Stripe can send 4XX errors for payment failure (not badly-formed requests) # check if error `code` is present in 4XX response and raise only if not # cfr https://stripe.com/docs/error-codes # these can be made customer-facing, as they usually indicate a problem with the payment # (e.g. insufficient funds, expired card, etc.) # if the context key `stripe_manual_payment` is set then these errors will be raised as ValidationError, # otherwise, they will be silenced, and the will be returned no matter the status. # This key should typically be set for payments in the present and unset for automated payments # (e.g. through crons) if not resp.ok and self._context.get('stripe_manual_payment') and ( 400 <= resp.status_code < 500 and resp.json().get('error', {}).get('code')): try: resp.raise_for_status() except HTTPError: _logger.error(resp.text) stripe_error = resp.json().get('error', {}).get('message', '') error_msg = " " + (_( "Stripe gave us the following info about the problem: '%s'" ) % stripe_error) raise ValidationError(error_msg) return resp.json()
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, trans_id, fingerprint = data.get('x_invoice_num'), 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)]) if not tx or len(tx) > 1: error_msg = 'Authorize: received data for reference %s' % (reference) 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 _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') if not reference or not pay_id or not shasign: error_msg = _('Ogone: received data with missing reference (%s) or pay_id (%s) or shasign (%s)') % (reference, pay_id, shasign) _logger.info(error_msg) raise ValidationError(error_msg) # find tx -> @TDENOTE use paytid ? tx = self.search([('reference', '=', reference)]) if not tx or len(tx) > 1: error_msg = _('Ogone: received data for reference %s') % (reference) if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) # verify shasign 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) raise ValidationError(error_msg) if not tx.acquirer_reference: tx.acquirer_reference = pay_id # alias was created on ogone server, store it if alias and tx.type == 'form_save': Token = self.env['payment.token'] domain = [('acquirer_ref', '=', alias)] cardholder = data.get('CN') if not Token.search_count(domain): _logger.info('Ogone: saving alias %s for partner %s' % (data.get('CARDNO'), tx.partner_id)) ref = Token.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.id}) return tx
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) _logger.info(error_msg) raise ValidationError(error_msg) # find tx -> @TDENOTE use txn_id ? 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 txs: error_msg += '; no order found' else: error_msg += '; multiple order found' _logger.info(error_msg) raise ValidationError(error_msg) return txs[0]
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) _logger.info(error_msg) raise ValidationError(error_msg) # find tx -> @TDENOTE use pspReference ? 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: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) # verify shasign if len(tx.acquirer_id.adyen_skin_hmac_key) == 64: shasign_check = tx.acquirer_id._adyen_generate_merchant_sig_sha256( 'out', data) else: shasign_check = tx.acquirer_id._adyen_generate_merchant_sig( 'out', data) if to_text(shasign_check) != to_text(data.get('merchantSig')): error_msg = _( 'Adyen: invalid merchantSig, received %s, computed %s') % ( data.get('merchantSig'), shasign_check) _logger.warning(error_msg) raise ValidationError(error_msg) return tx
def _transfer_form_get_tx_from_data(self, data): reference, amount, currency_name = data.get('reference'), data.get('amount'), data.get('currency_name') tx = self.search([('reference', '=', reference)]) if not tx or len(tx) > 1: error_msg = _('received data for reference %s') % (pprint.pformat(reference)) if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) return tx
def _alipay_form_get_tx_from_data(self, data): reference, txn_id, sign = data.get('reference'), data.get( 'trade_no'), data.get('sign') if not reference or not txn_id: _logger.info( 'Alipay: received data with missing reference (%s) or txn_id (%s)' % (reference, txn_id)) raise ValidationError( _('Alipay: received data with missing reference (%s) or txn_id (%s)' ) % (reference, txn_id)) txs = self.env['payment.transaction'].search([('reference', '=', reference)]) if not txs or len(txs) > 1: error_msg = _('Alipay: received data for reference %s') % ( reference) logger_msg = 'Alipay: received data for reference %s' % (reference) if not txs: error_msg += _('; no order found') logger_msg += '; no order found' else: error_msg += _('; multiple order found') logger_msg += '; multiple order found' _logger.info(logger_msg) raise ValidationError(error_msg) # verify sign sign_check = txs.acquirer_id._build_sign(data) if sign != sign_check: _logger.info( 'Alipay: invalid sign, received %s, computed %s, for data %s' % (sign, sign_check, data)) raise ValidationError( _('Alipay: invalid sign, received %s, computed %s, for data %s' ) % (sign, sign_check, data)) return txs
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) data = normalize_keys_upper(data) reference, pay_id, shasign = data.get('BRQ_INVOICENUMBER'), data.get( 'BRQ_PAYMENT'), data.get('BRQ_SIGNATURE') if not reference or not pay_id or not shasign: error_msg = _( 'Buckaroo: received data with missing reference (%s) or pay_id (%s) or shasign (%s)' ) % (reference, pay_id, shasign) _logger.info(error_msg) raise ValidationError(error_msg) tx = self.search([('reference', '=', reference)]) if not tx or len(tx) > 1: error_msg = _('Buckaroo: received data for reference %s') % ( reference) if not tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.info(error_msg) raise ValidationError(error_msg) # 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
def _sips_generate_shasign(self, values): """ Generate the shasign for incoming or outgoing communications. :param dict values: transaction values :return string: shasign """ if self.provider != 'sips': raise ValidationError(_('Incorrect payment acquirer provider')) data = values['Data'] # Test key provided by Worldine key = u'002001000000001_KEY1' if self.state == 'enabled': key = getattr(self, 'sips_secret') shasign = sha256((data + key).encode('utf-8')) return shasign.hexdigest()
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
def _stripe_sca_migrate_customer(self): """Migrate a token from the old implementation of Stripe to the SCA one. In the old implementation, it was possible to create a valid charge just by giving the customer ref to ask Stripe to use the default source (= default card). Since we have a one-to-one matching between a saved card, this used to work well - but now we need to specify the payment method for each call and so we have to contact stripe to get the default source for the customer and save it in the payment token. This conversion will happen once per token, the first time it gets used following the installation of the module.""" self.ensure_one() url = "customers/%s" % (self.acquirer_ref) data = self.acquirer_id._stripe_request(url, method="GET") sources = data.get('sources', {}).get('data', []) pm_ref = False if sources: if len(sources) > 1: _logger.warning( 'stripe sca customer conversion: there should be a single saved source per customer!' ) pm_ref = sources[0].get('id') else: url = 'payment_methods' params = { 'type': 'card', 'customer': self.acquirer_ref, } payment_methods = self.acquirer_id._stripe_request(url, params, method='GET') cards = payment_methods.get('data', []) if len(cards) > 1: _logger.warning( 'stripe sca customer conversion: there should be a single saved source per customer!' ) pm_ref = cards and cards[0].get('id') if not pm_ref: raise ValidationError( _('Unable to convert Stripe customer for SCA compatibility. Is there at least one card for this customer in the Stripe backend?' )) self.stripe_payment_method = pm_ref _logger.info( 'converted old customer ref to sca-compatible record for payment token %s', self.id)
def sips_form_generate_values(self, values): self.ensure_one() base_url = self.get_base_url() currency = self.env['res.currency'].sudo().browse( values['currency_id']) currency_code = CURRENCY_CODES.get(currency.name, False) if not currency_code: raise ValidationError(_('Currency not supported by Wordline')) amount = round(values['amount'] * 100) if self.state == 'enabled': # For production environment, key version 2 is required merchant_id = getattr(self, 'sips_merchant_id') key_version = self.env['ir.config_parameter'].sudo().get_param( 'sips.key_version', '2') else: # Test key provided by Atos Wordline works only with version 1 merchant_id = '002001000000001' key_version = '1' sips_tx_values = dict(values) sips_tx_values.update({ 'Data': u'amount=%s|' % amount + u'currencyCode=%s|' % currency_code + u'merchantId=%s|' % merchant_id + u'normalReturnUrl=%s|' % urls.url_join(base_url, SipsController._return_url) + u'automaticResponseUrl=%s|' % urls.url_join(base_url, SipsController._notify_url) + u'transactionReference=%s|' % values['reference'] + u'statementReference=%s|' % values['reference'] + u'keyVersion=%s' % key_version, 'InterfaceVersion': self.sips_version, }) return_context = {} if sips_tx_values.get('return_url'): return_context[u'return_url'] = u'%s' % urls.url_quote( sips_tx_values.pop('return_url')) return_context[u'reference'] = u'%s' % sips_tx_values['reference'] sips_tx_values['Data'] += u'|returnContext=%s' % ( json.dumps(return_context)) shasign = self._sips_generate_shasign(sips_tx_values) sips_tx_values['Seal'] = shasign return sips_tx_values
def _check_alipay_configuration(self, vals): acquirer_id = int(vals.get('acquirer_id')) acquirer = self.env['payment.acquirer'].sudo().browse(acquirer_id) if acquirer and acquirer.provider == 'alipay' and acquirer.alipay_payment_method == 'express_checkout': currency_id = int(vals.get('currency_id')) if currency_id: currency = self.env['res.currency'].sudo().browse(currency_id) if currency and currency.name != 'CNY': _logger.info( "Only CNY currency is allowed for Alipay Express Checkout" ) raise ValidationError( _(""" Only transactions in Chinese Yuan (CNY) are allowed for Alipay Express Checkout.\n If you wish to use another currency than CNY for your transactions, switch your configuration to a Cross-border account on the Alipay payment acquirer in Harpiya. """)) return True
def _sips_form_get_tx_from_data(self, data): """ Given a data dict coming from sips, verify it and find the related transaction record. """ data = self._sips_data_to_object(data.get('Data')) reference = data.get('transactionReference') if not reference: custom = json.loads(data.pop('returnContext', False) or '{}') reference = custom.get('reference') payment_tx = self.search([('reference', '=', reference)]) if not payment_tx or len(payment_tx) > 1: error_msg = _('Sips: received data for reference %s') % reference if not payment_tx: error_msg += _('; no order found') else: error_msg += _('; multiple order found') _logger.error(error_msg) raise ValidationError(error_msg) return payment_tx