def appoint_pay_token(self, appoint_id, pm_id=None, **kwargs): error_url = kwargs.get('error_url', '/my') success_url = kwargs.get('success_url', '/my') access_token = kwargs.get('access_token') params = {} if access_token: params['access_token'] = access_token appoint_sudo = request.env['appointment'].sudo().browse(appoint_id).exists() if not appoint_sudo: params['error'] = 'pay_appoint_invalid_doc' return request.redirect(_build_url_w_params(error_url, params)) try: token = request.env['payment.token'].sudo().browse(int(pm_id)) except (ValueError, TypeError): token = False token_owner = appoint_sudo.customer if request.env.user._is_public() else request.env.user.partner_id if not token or token.partner_id != token_owner: params['error'] = 'pay_invoice_invalid_token' return request.redirect(_build_url_w_params(error_url, params)) vals = { 'payment_token_id': token.id, 'type': 'server2server', 'return_url': success_url, } tx = appoint_sudo._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(tx) params['success'] = 'pay_invoice' return request.redirect(_build_url_w_params(success_url, params))
def payment_token(self, pm_id=None, **kwargs): """ Method that handles payment using saved tokens :param int pm_id: id of the payment.token that we want to use to pay. """ order = request.website.sale_get_order() # do not crash if the user has already paid and try to pay again if not order: return request.redirect('/shop/?error=no_order') assert order.partner_id.id != request.website.partner_id.id try: pm_id = int(pm_id) except ValueError: return request.redirect('/shop/?error=invalid_token_id') # We retrieve the token the user want to use to pay if not request.env['payment.token'].sudo().search_count([('id', '=', pm_id)]): return request.redirect('/shop/?error=token_not_found') # Create transaction vals = {'payment_token_id': pm_id, 'return_url': '/shop/payment/validate'} tx = order._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(tx) return request.redirect('/payment/process')
def payment_token(self, pm_id=None, **kwargs): """ Method that handles payment using saved tokens :param int pm_id: id of the payment.token that we want to use to pay. """ order = request.website.sale_get_order() # do not crash if the user has already paid and try to pay again if not order: return request.redirect('/shop/?error=no_order') assert order.partner_id.id != request.website.partner_id.id try: pm_id = int(pm_id) except ValueError: return request.redirect('/shop/?error=invalid_token_id') # We retrieve the token the user want to use to pay if not request.env['payment.token'].sudo().search_count([('id', '=', pm_id)]): return request.redirect('/shop/?error=token_not_found') # Create transaction vals = {'payment_token_id': pm_id, 'return_url': '/shop/payment/validate'} tx = order._create_payment_transaction(vals) pm_ids = request.env['payment.token'].browse(pm_id) if pm_ids.acquirer_id.provider == 'cxpay': if isinstance(tx, dict): url = '/payment_method/add?url=' + tx.get('url') + '&token=' + str(pm_id) return request.redirect(url) PaymentProcessing.add_payment_transaction(tx) return request.redirect('/payment/process')
def hyperpay_shopper_result(self, **post): acq = request.env['payment.acquirer'].sudo().search([('provider', '=', 'hyperpay')]) if acq.state == 'enabled': url = live_domain else: url = test_domain url += '/' + post.get( 'resourcePath') + "?entityId=%s" % (acq.hyperpay_merchant_id) headers = { "Authorization": "Bearer " + acq.hyperpay_authorization, } resp = requests.get(url=url, headers=headers).json() _logger.info( "-----/payment/hyperpay/result-----response------------%r----", resp) payment = request.env['payment.transaction'].sudo() tx = payment.search([('hyperpay_checkout_id', '=', post.get('id', ''))]) tx = resp.get('customParameters', {}).get('SHOPPER_tx_id') or tx and tx.id or '' resp.update({'tx_id': tx}) if tx: PaymentProcessing.add_payment_transaction(payment.browse(int(tx))) res = payment.form_feedback(resp, 'hyperpay') return werkzeug.utils.redirect('/payment/process')
def stripe_create_charge(self, **post): """ Create a payment transaction Expects the result from the user input from checkout.js popup""" TX = request.env['payment.transaction'] tx = None if post.get('tx_ref'): tx = TX.sudo().search([('reference', '=', post['tx_ref'])]) if not tx: tx_id = (post.get('tx_id') or request.session.get('sale_transaction_id') or request.session.get('website_payment_tx_id')) tx = TX.sudo().browse(int(tx_id)) if not tx: raise werkzeug.exceptions.NotFound() stripe_token = post['token'] response = None if tx.type == 'form_save' and tx.partner_id: payment_token_id = request.env['payment.token'].sudo().create({ 'acquirer_id': tx.acquirer_id.id, 'partner_id': tx.partner_id.id, 'stripe_token': stripe_token }) tx.payment_token_id = payment_token_id response = tx._create_stripe_charge(acquirer_ref=payment_token_id.acquirer_ref, email=stripe_token['email']) else: response = tx._create_stripe_charge(tokenid=stripe_token['id'], email=stripe_token['email']) _logger.info('Stripe: entering form_feedback with post data %s', pprint.pformat(response)) if response: request.env['payment.transaction'].sudo().with_context(lang=None).form_feedback(response, 'stripe') # add the payment transaction into the session to let the page /payment/process to handle it PaymentProcessing.add_payment_transaction(tx) return "/payment/process"
def payment_token(self, pm_id=None, **kwargs): """ Method that handles payment using saved tokens :param int pm_id: id of the payment.token that we want to use to pay. """ order = request.website.sale_get_order() # do not crash if the user has already paid and try to pay again if not order: return request.redirect('/shop/?error=no_order') assert order.partner_id.id != request.website.partner_id.id try: pm_id = int(pm_id) except ValueError: return request.redirect('/shop/?error=invalid_token_id') # We retrieve the token the user want to use to pay if not request.env['payment.token'].sudo().search_count( [('id', '=', pm_id)]): return request.redirect('/shop/?error=token_not_found') # Create transaction vals = { 'payment_token_id': pm_id, 'return_url': '/shop/payment/validate' } t_x = order._create_payment_transaction(vals) order.write({'payment_tx_id': t_x.id}) PaymentProcessing.add_payment_transaction(t_x) return request.redirect('/payment/process')
def invoice_pay_token(self, invoice_id, pm_id=None, **kwargs): """ Use a token to perform a s2s transaction """ error_url = kwargs.get('error_url', '/my') success_url = kwargs.get('success_url', '/my') access_token = kwargs.get('access_token') params = {} if access_token: params['access_token'] = access_token invoice_sudo = request.env['account.invoice'].sudo().browse(invoice_id).exists() if not invoice_sudo: params['error'] = 'pay_invoice_invalid_doc' return request.redirect(_build_url_w_params(error_url, params)) try: token = request.env['payment.token'].sudo().browse(int(pm_id)) except (ValueError, TypeError): token = False token_owner = invoice_sudo.partner_id if request.env.user._is_public() else request.env.user.partner_id if not token or token.partner_id != token_owner: params['error'] = 'pay_invoice_invalid_token' return request.redirect(_build_url_w_params(error_url, params)) vals = { 'payment_token_id': token.id, 'type': 'server2server', 'return_url': success_url, } tx = invoice_sudo._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(tx) params['success'] = 'pay_invoice' return request.redirect(_build_url_w_params(success_url, params))
def appoint_pay_form(self, acquirer_id, appoint_id, save_token=False, access_token=None, **kwargs): success_url = kwargs.get('success_url', '/my/appointments') # callback_method = kwargs.get('callback_method', '') appoint_sudo = request.env['appointment'].sudo().browse(appoint_id) if not appoint_sudo: return False try: acquirer = int(acquirer_id) except: return False if request.env.user._is_public(): save_token = False # we avoid to create a token for the public user vals = { 'acquirer_id': acquirer_id, 'return_url': success_url, } if save_token: vals['type'] = 'form_save' transaction = appoint_sudo._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(transaction) return transaction.render_appoint_button( appoint_sudo, submit_txt=_('Pay & Confirm'), render_values={ 'type': 'form_save' if save_token else 'form', 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'), } )
def ogone_s2s_create(self, **post): error = '' acq = request.env['payment.acquirer'].browse( int(post.get('acquirer_id'))) try: token = acq.s2s_process(post) except Exception as e: # synthax error: 'CHECK ERROR: |Not a valid date\n\n50001111: None' token = False error = str(e).splitlines()[0].split('|')[-1] or '' if token and post.get('verify_validity'): baseurl = request.env['ir.config_parameter'].sudo().get_param( 'web.base.url') params = { 'accept_url': baseurl + '/payment/ogone/validate/accept', 'decline_url': baseurl + '/payment/ogone/validate/decline', 'exception_url': baseurl + '/payment/ogone/validate/exception', 'return_url': post.get('return_url', baseurl) } tx = token.validate(**params) if tx and tx.html_3ds: return tx.html_3ds # add the payment transaction into the session to let the page /payment/process to handle it PaymentProcessing.add_payment_transaction(tx) return werkzeug.utils.redirect("/payment/process")
def cx_pay_paymment_approve(self, payment_id=False, token_id=False, **kwargs): payment_id = request.env['payment.transaction'].sudo().browse(payment_id) if kwargs.get('token-id'): payment_id.token_id = kwargs.get('token-id') payment_id.cxpay_s2s_do_transaction_verify() payment_id.payment_token_id.cvv_no = False PaymentProcessing.add_payment_transaction(payment_id) return http.redirect_with_hash('/payment/process')
def payment_transaction(self, acquirer_id, save_token=False, so_id=None, access_token=None, token=None, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button. After having created the transaction, the event continues and the user is redirected to the acquirer website. :param int acquirer_id: id of a payment.acquirer record. If not set the user is redirected to the checkout page """ # Ensure a payment acquirer is selected if not acquirer_id: return False try: acquirer_id = int(acquirer_id) except: return False # Retrieve the sale order if so_id: env = request.env['sale.order'] domain = [('id', '=', so_id)] if access_token: env = env.sudo() domain.append(('access_token', '=', access_token)) order = env.search(domain, limit=1) else: order = request.website.sale_get_order() # Ensure there is something to proceed if not order or (order and not order.order_line): return False assert order.partner_id.id != request.website.partner_id.id # Create transaction vals = {'acquirer_id': acquirer_id, 'return_url': '/shop/payment/validate'} if save_token: vals['type'] = 'form_save' if token: vals['payment_token_id'] = int(token) transaction = order._create_payment_transaction(vals) # store the new transaction into the transaction list and if there's an old one, we remove it # until the day the ecommerce supports multiple orders at the same time last_tx_id = request.session.get('__website_sale_last_tx_id') last_tx = request.env['payment.transaction'].browse(last_tx_id).sudo().exists() if last_tx: PaymentProcessing.remove_payment_transaction(last_tx) PaymentProcessing.add_payment_transaction(transaction) request.session['__website_sale_last_tx_id'] = transaction.id return transaction.render_sale_button(order)
def invoice_pay_form(self, acquirer_id, invoice_id, save_token=False, access_token=None, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button on the payment form. :return html: form containing all values related to the acquirer to redirect customers to the acquirer website """ invoice_sudo = request.env['account.move'].sudo().browse(invoice_id) if not invoice_sudo: return False try: acquirer_id = int(acquirer_id) except: return False if request.env.user._is_public(): save_token = False # we avoid to create a token for the public user success_url = kwargs.get( 'success_url', "%s?%s" % (invoice_sudo.access_url, url_encode( {'access_token': access_token}) if access_token else '')) vals = { 'acquirer_id': acquirer_id, 'return_url': success_url, } if save_token: vals['type'] = 'form_save' transaction = invoice_sudo._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(transaction) return transaction.render_invoice_button( invoice_sudo, submit_txt=_('Pay & Confirm'), render_values={ 'type': 'form_save' if save_token else 'form', 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.' ), })
def stripe_checkout_do_payment(self, acquirer_id=None, order_id=None, invoice_id=None, token=None, **kwargs): order = request.website.sale_get_order() acquirer = request.env['payment.acquirer'].browse(int(acquirer_id)) assert order.partner_id.id != request.website.partner_id.id # tx_obj => object that will use to create transcation record can be sale order or account invoice tx_obj = order vals = { 'payment_token_id': int(token) if token else None, 'return_url': '/shop/payment/validate', 'type': 'server2server' } if not token: vals['acquirer_id'] = int(acquirer_id) if order_id: tx_obj, data = self._get_order_tx_vals(order_id, **kwargs) vals.update(data) elif invoice_id: tx_obj, data = self._get_invoice_tx_vals(invoice_id, **kwargs) vals.update(data) if not token: vals['acquirer_id'] = int(acquirer_id) if not tx_obj: return { 'status': False, 'message': _("Error occurred while processing your transaction.") } transaction = tx_obj._create_payment_transaction(vals) last_tx_id = request.session.get('__website_sale_last_tx_id') last_tx = request.env['payment.transaction'].browse( last_tx_id).sudo().exists() if last_tx: PaymentProcessing.remove_payment_transaction(last_tx) PaymentProcessing.add_payment_transaction(transaction) request.session['__website_sale_last_tx_id'] = transaction.id res = transaction.create_payment(kwargs) return res
def payment_transaction_token(self, acquirer_id, order_id, save_token=False, access_token=None, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button. After having created the transaction, the event continues and the user is redirected to the acquirer website. :param int acquirer_id: id of a payment.acquirer record. If not set the user is redirected to the checkout page """ # Ensure a payment acquirer is selected if not acquirer_id: return False try: acquirer_id = int(acquirer_id) except: return False order = request.env['sale.order'].sudo().browse(order_id) if not order or not order.order_line or not order.has_to_be_paid(): return False # Create transaction vals = { 'acquirer_id': acquirer_id, 'type': order._get_payment_type(), 'return_url': order.get_portal_url(), } transaction = order._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(transaction) return transaction.render_sale_button( order, submit_txt=_('Pay & Confirm'), render_values={ 'type': order._get_payment_type(), 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.' ), })
def api_payment_transaction(self, acquirer_id, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button. After having created the transaction, the event continues and the user is redirected to the acquirer website. :param int acquirer_id: id of a payment.acquirer record. If not set the user is redirected to the checkout page """ # Ensure a payment acquirer is selected if not acquirer_id: return False try: acquirer_id = int(acquirer_id) except: return False order = request.website.sale_get_order() # Ensure there is something to proceed if not order or (order and not order.order_line): return False assert order.partner_id.id != request.website.partner_id.id # Create transaction vals = { 'acquirer_id': acquirer_id, 'return_url': '/shop/payment/validate' } transaction = order._create_payment_transaction(vals) # store the new transaction into the transaction list and if there's an old one, we remove it # until the day the ecommerce supports multiple orders at the same time last_tx_id = request.session.get('__website_sale_last_tx_id') last_tx = request.env['payment.transaction'].browse( last_tx_id).sudo().exists() if last_tx: PaymentProcessing.remove_payment_transaction(last_tx) PaymentProcessing.add_payment_transaction(transaction) request.session['__website_sale_last_tx_id'] = transaction.id return transaction.render_sale_api_values(order)
def payment(self, account_id, uuid=None, **kw): account_res = request.env['sale.subscription'] invoice_res = request.env['account.move'] get_param = '' if uuid: account = account_res.sudo().browse(account_id) if uuid != account.uuid: raise NotFound() else: account = account_res.browse(account_id) # no change if int(kw.get('pm_id', 0)) > 0: account.payment_token_id = int(kw['pm_id']) # if no payment has been selected for this account, then we display redirect to /my/subscription with an error message if len(account.payment_token_id) == 0: get_param = 'message=No payment method have been selected for this subscription.&message_class=alert-danger' return request.redirect('/my/subscription/%s/%s?%s' % (account.id, account.uuid, get_param)) # we can't call _recurring_invoice because we'd miss 3DS, redoing the whole payment here payment_token = account.payment_token_id if payment_token: invoice_values = account.sudo()._prepare_invoice() new_invoice = invoice_res.sudo().create(invoice_values) tx = account.sudo().with_context(off_session=False)._do_payment( payment_token, new_invoice)[0] PaymentProcessing.add_payment_transaction(tx) if tx.html_3ds: return tx.html_3ds get_param = self.payment_succes_msg if tx.renewal_allowed else self.payment_fail_msg if tx.renewal_allowed: account.send_success_mail(tx, new_invoice) msg_body = 'Manual payment succeeded. Payment reference: <a href=# data-oe-model=payment.transaction data-oe-id=%d>%s</a>; Amount: %s. Invoice <a href=# data-oe-model=account.move data-oe-id=%d>View Invoice</a>.' % ( tx.id, tx.reference, tx.amount, new_invoice.id) account.message_post(body=msg_body) elif tx.state != 'pending': # a pending status might indicate that the customer has to authenticate, keep the invoice for post-processing # NOTE: this might cause a lot of draft invoices to stay alive; i'm afraid this can't be helped # since the payment flow is divided in 2 in that case and the draft invoice must survive after the request new_invoice.unlink() return request.redirect('/payment/process')
def yoco_verify_charge(self, **post): """ Verify a payment transaction Expects the result from the user input from flwpbf-inline.js popup""" TX = request.env['payment.transaction'] tx = None data = { 'acquirer_id': post.get('acquirer_id'), 'token': post.get('token'), 'amount': round(post.get('amount'), 2), 'currency': post.get('currency') } if post.get('tx_ref'): tx = TX.sudo().search([('reference', '=', post.get('tx_ref'))]) if not tx: tx_id = (post.get('id') or request.session.get('sale_transaction_id') or request.session.get('website_payment_tx_id')) tx = TX.sudo().browse(int(tx_id)) if not tx: raise werkzeug.exceptions.NotFound() if tx.type == 'form_save' and tx.partner_id: payment_token_id = request.env['payment.token'].sudo().create({ 'acquirer_id': tx.acquirer_id.id, 'partner_id': tx.partner_id.id, }) tx.payment_token_id = payment_token_id response = tx._yoco_verify_charge(data) else: response = tx._yoco_verify_charge(data) _logger.info('Yoco: entering form_feedback with post data %s', pprint.pformat(response)) if response: request.env['payment.transaction'].sudo().with_context( lang=None).form_feedback(post, 'yoco') # add the payment transaction into the session to let the page /payment/process to handle it PaymentProcessing.add_payment_transaction(tx) return "/payment/process"
def invoice_pay_form(self, acquirer_id, invoice_id, save_token=False, access_token=None, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button on the payment form. :return html: form containing all values related to the acquirer to redirect customers to the acquirer website """ success_url = kwargs.get('success_url', '/my') invoice_sudo = request.env['account.invoice'].sudo().browse(invoice_id) if not invoice_sudo: return False try: acquirer_id = int(acquirer_id) except: return False if request.env.user._is_public(): save_token = False # we avoid to create a token for the public user vals = { 'acquirer_id': acquirer_id, 'return_url': success_url, } if save_token: vals['type'] = 'form_save' transaction = invoice_sudo._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(transaction) return transaction.render_invoice_button( invoice_sudo, submit_txt=_('Pay & Confirm'), render_values={ 'type': 'form_save' if save_token else 'form', 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'), } )
def payment_transaction_token(self, acquirer_id, order_id, save_token=False, access_token=None, **kwargs): """ Json method that creates a payment.transaction, used to create a transaction when the user clicks on 'pay now' button. After having created the transaction, the event continues and the user is redirected to the acquirer website. :param int acquirer_id: id of a payment.acquirer record. If not set the user is redirected to the checkout page """ # Ensure a payment acquirer is selected if not acquirer_id: return False try: acquirer_id = int(acquirer_id) except: return False order = request.env['sale.order'].sudo().browse(order_id) if not order or not order.order_line or not order.has_to_be_paid(): return False # Create transaction vals = { 'acquirer_id': acquirer_id, 'type': order._get_payment_type(), 'return_url': order.get_portal_url(), } transaction = order._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(transaction) return transaction.render_sale_button( order, submit_txt=_('Pay & Confirm'), render_values={ 'type': order._get_payment_type(), 'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'), } )
def invoice_pay_token(self, invoice_id, pm_id=None, **kwargs): """ Use a token to perform a s2s transaction """ error_url = kwargs.get('error_url', '/my') access_token = kwargs.get('access_token') params = {} if access_token: params['access_token'] = access_token invoice_sudo = request.env['account.move'].sudo().browse( invoice_id).exists() if not invoice_sudo: params['error'] = 'pay_invoice_invalid_doc' return request.redirect(_build_url_w_params(error_url, params)) success_url = kwargs.get( 'success_url', "%s?%s" % (invoice_sudo.access_url, url_encode( {'access_token': access_token}) if access_token else '')) try: token = request.env['payment.token'].sudo().browse(int(pm_id)) except (ValueError, TypeError): token = False token_owner = invoice_sudo.partner_id if request.env.user._is_public( ) else request.env.user.partner_id if not token or token.partner_id != token_owner: params['error'] = 'pay_invoice_invalid_token' return request.redirect(_build_url_w_params(error_url, params)) vals = { 'payment_token_id': token.id, 'type': 'server2server', 'return_url': _build_url_w_params(success_url, params), } tx = invoice_sudo._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(tx) params['success'] = 'pay_invoice' return request.redirect('/payment/process')
def ogone_s2s_create(self, **post): error = '' acq = request.env['payment.acquirer'].browse(int(post.get('acquirer_id'))) try: token = acq.s2s_process(post) except Exception as e: # synthax error: 'CHECK ERROR: |Not a valid date\n\n50001111: None' token = False error = str(e).splitlines()[0].split('|')[-1] or '' if token and post.get('verify_validity'): baseurl = request.env['ir.config_parameter'].sudo().get_param('web.base.url') params = { 'accept_url': baseurl + '/payment/ogone/validate/accept', 'decline_url': baseurl + '/payment/ogone/validate/decline', 'exception_url': baseurl + '/payment/ogone/validate/exception', 'return_url': post.get('return_url', baseurl) } tx = token.validate(**params) if tx and tx.html_3ds: return tx.html_3ds # add the payment transaction into the session to let the page /payment/process to handle it PaymentProcessing.add_payment_transaction(tx) return werkzeug.utils.redirect("/payment/process")
def payment_token(self, order_id, pm_id=None, **kwargs): order = request.env['sale.order'].sudo().browse(order_id) if not order: return request.redirect("/my/orders") if not order.order_line or pm_id is None or not order.has_to_be_paid(): return request.redirect(order.get_portal_url()) # try to convert pm_id into an integer, if it doesn't work redirect the user to the quote try: pm_id = int(pm_id) except ValueError: return request.redirect(order.get_portal_url()) # Create transaction vals = { 'payment_token_id': pm_id, 'type': 'server2server', 'return_url': order.get_portal_url(), } tx = order._create_payment_transaction(vals) PaymentProcessing.add_payment_transaction(tx) return request.redirect('/payment/process')
def transaction(self, acquirer_id, reference, amount, currency_id, partner_id=False, **kwargs): acquirer = request.env['payment.acquirer'].browse(acquirer_id) order_id = kwargs.get('order_id') reference_values = order_id and { 'sale_order_ids': [(4, order_id)] } or {} reference = request.env['payment.transaction']._compute_reference( values=reference_values, prefix=reference) values = { 'acquirer_id': int(acquirer_id), 'reference': reference, 'amount': float(amount), 'currency_id': int(currency_id), 'partner_id': partner_id, 'type': 'form_save' if acquirer.save_token != 'none' and partner_id else 'form', } if order_id: values['sale_order_ids'] = [(6, 0, [order_id])] reference_values = order_id and { 'sale_order_ids': [(4, order_id)] } or {} reference_values.update(acquirer_id=int(acquirer_id)) values['reference'] = request.env[ 'payment.transaction']._compute_reference(values=reference_values, prefix=reference) tx = request.env['payment.transaction'].sudo().with_context( lang=None).create(values) secret = request.env['ir.config_parameter'].sudo().get_param( 'database.secret') token_str = '%s%s%s' % ( tx.id, tx.reference, float_repr(tx.amount, precision_digits=tx.currency_id.decimal_places)) token = hmac.new(secret.encode('utf-8'), token_str.encode('utf-8'), hashlib.sha256).hexdigest() tx.return_url = '/website_payment/confirm?tx_id=%d&access_token=%s' % ( tx.id, token) PaymentProcessing.add_payment_transaction(tx) render_values = { 'partner_id': partner_id, } if not order_id: acquirer = acquirer.with_context(stripe_fees=True) return acquirer.sudo().render(tx.reference, float(amount), int(currency_id), values=render_values)
def transaction(self, acquirer_id, reference, amount, currency_id, partner_id=False, **kwargs): acquirer = request.env["payment.acquirer"].browse(acquirer_id) order_id = kwargs.get("order_id") # BizzAppDev Customization Start invoice_id = kwargs.get("invoice_id") # BizzAppDev Customization End reference_values = (order_id and { "sale_order_ids": [(4, order_id)] } or {}) # BizzAppDev Customization Start if invoice_id: reference_values.update({"invoice_ids": [(4, int(invoice_id))]}) # BizzAppDev Customization End reference = request.env["payment.transaction"]._compute_reference( values=reference_values, prefix=reference) values = { "acquirer_id": int(acquirer_id), "reference": reference, "amount": float(amount), "currency_id": int(currency_id), "partner_id": partner_id, "type": "form_save" if acquirer.save_token != "none" and partner_id else "form", } if order_id: values["sale_order_ids"] = [(6, 0, [order_id])] # BizzAppDev Customization Start if invoice_id: values["invoice_ids"] = [(6, 0, [invoice_id])] # BizzAppDev Customization End reference_values = (order_id and { "sale_order_ids": [(4, order_id)] } or {}) if invoice_id: reference_values.update({"invoice_ids": [(4, int(invoice_id))]}) reference_values.update(acquirer_id=int(acquirer_id)) values["reference"] = request.env[ "payment.transaction"]._compute_reference(values=reference_values, prefix=reference) tx = (request.env["payment.transaction"].sudo().with_context( lang=None).create(values)) tx = request.env["payment.transaction"].sudo().browse(tx.id) secret = (request.env["ir.config_parameter"].sudo().get_param( "database.secret")) token_str = "%s%s%s" % ( tx.id, tx.reference, round(tx.amount, tx.currency_id.decimal_places), ) token = hmac.new(secret.encode("utf-8"), token_str.encode("utf-8"), hashlib.sha256).hexdigest() tx.return_url = "/website_payment/confirm?tx_id=%d&access_token=%s" % ( tx.id, token, ) PaymentProcessing.add_payment_transaction(tx) render_values = { "partner_id": partner_id, } return acquirer.sudo().render(tx.reference, float(amount), int(currency_id), values=render_values)
def payment_token(self, pm_id=None, **kwargs): """ OVERRIDING METHOD FROM odoo/addons/website_sale/controllers/main.py Method that handles payment using saved tokens :param int pm_id: id of the payment.token that we want to use to pay. This route is requested after payment submission : /shop/payment/solana/submit - it's only called if the buyer doesn't provide an existing payment token """ # order already created, get it sales_order = request.website.sale_get_order() _logger.info(f'received token for sales_order: {sales_order.id}') _logger.info(f'processing token for sales_order: {sales_order.id}') # do not crash if the user has already paid and try to pay again if not sales_order: _logger.error('no order found') return request.redirect('/shop/?error=no_order') # see overriden method assert sales_order.partner_id.id != request.website.partner_id.id try: # pm_id is passed, make sure it's a valid int pm_id = int(pm_id) except ValueError: _logger.error('invalid token id') return request.redirect('/shop/?error=invalid_token_id') # payment token already created, get it token = request.env['payment.token'].sudo().browse(pm_id) if not token: return request.redirect('/shop/?error=token_not_found') # has the transaction already been created? tx_id = request.session["__website_sale_last_tx_id"] if tx_id: # transaction was already established in /shop/payment/solana/submit transaction = request.env['payment.transaction'].sudo().browse( tx_id) PaymentProcessing.add_payment_transaction(transaction) # clear the tx in session, because we're done with it request.session["__website_sale_last_tx_id"] = None return request.redirect('/shop/payment/validate') else: # transaction hasn't been created tx_val = { 'payment_token_id': pm_id, 'return_url': '/shop/payment/validate' } transaction = sales_order._create_payment_transaction(tx_val) _logger.info( f'created transaction: {transaction.id} for payment token: {token.id}' ) _logger.info(f'token.acquirer_ref = {token.acquirer_ref}') if transaction.acquirer_id.is_cryptocurrency: _logger.info( f'Processing cryptocurrency payment acquirer: {transaction.acquirer_id.name}' ) _logger.info( f'setting sales_order state to "sent" for sales_order: {sales_order.id}' ) sales_order.sudo().update({'state': 'sent'}) _logger.info( f'setting transaction state to "pending" for sales_order: {sales_order.id}' ) transaction.sudo().update({'state': 'pending'}) PaymentProcessing.add_payment_transaction(transaction) return request.redirect('/shop/payment/validate') PaymentProcessing.add_payment_transaction(transaction) return request.redirect('/payment/process')
def solana_transaction(self, verify_validity=False, **kwargs): """ Function creates a transaction and payment token using the sessions sales order Calls SolanaSalesOrder.salesorder_payment_sync() :param verify_validity: :param kwargs: :return: """ sales_order = request.website.sale_get_order() _logger.info(f'received sales_order: {sales_order.id}') _logger.info(f'processing sales_order: {sales_order.id}') # Ensure there is something to proceed if not sales_order or (sales_order and not sales_order.order_line): return False assert sales_order.partner_id.id != request.website.partner_id.id payment_acquirer_id = int(kwargs.get('acquirer_id')) payment_partner_id = int(kwargs.get('partner_id')) # TODO verify the wallet_address is a valid solana address # TODO verify that the specified address has the needed amount in it source_wallet_address = kwargs.get('wallet_address') # define payment token payment_token = { 'name': str(source_wallet_address).strip() + ' - ' + kwargs.get('type'), # name = 'source_wallet_address' + ' - payment_type'; eg: ejh98hja... - SOL/BTC/USDC/ETH 'partner_id': payment_partner_id, # partner_id creating sales order 'active': True, 'acquirer_id': payment_acquirer_id, # surrogate key for payment acquirer 'acquirer_ref': 'cryptocurrency' # this should be the tx hash? } # TODO reuse token _logger.info( f'creating payment token for sales_order: {sales_order.id}') token = request.env['payment.token'].sudo().create(payment_token) token_id = token.id token_short_name = token.short_name # assign values for transaction creation tx_val = { 'amount': sales_order.amount_total, 'reference': sales_order.name, 'currency_id': sales_order.currency_id.id, 'partner_id': sales_order.partner_id.id, # Referencing the Sale Order Partner ID 'payment_token_id': token_id, # Associating the Payment Token ID. 'acquirer_id': payment_acquirer_id, # Payment Acquirer - Solana 'state': 'pending', # tx is pending, because the customer will know the address to send the tx to, # but hasn't yet sent it } _logger.info( f'getting the transaction for sales_order: {sales_order.id}') # transaction = sales_order._create_payment_transaction(tx_val) transaction = sales_order.get_portal_last_transaction() if transaction.id is False: transaction = sales_order._create_payment_transaction(tx_val) _logger.info(f'created transaction: {transaction.id}') else: _logger.info(f'retrieved transaction: {transaction.id}') # store the new transaction into the transaction list and if there's an old one, we remove it # until the day the ecommerce supports multiple orders at the same time last_tx_id = request.session.get('__website_sale_last_tx_id') last_tx = request.env['payment.transaction'].browse( last_tx_id).sudo().exists() if last_tx: PaymentProcessing.remove_payment_transaction(last_tx) PaymentProcessing.add_payment_transaction(transaction) request.session['__website_sale_last_tx_id'] = transaction.id # Sale Order is quotation sent # , so the state should be set to "sent" # , until the transaction has been verified _logger.info( f'setting sales_order state to "sent" for sales_order: {sales_order.id}' ) request.env.user.sale_order_ids.sudo().update({'state': 'sent'}) if transaction: res = { 'result': True, 'id': token_id, 'short_name': token_short_name, '3d_secure': False, 'verified': False, } if verify_validity != False: token.validate() res['verified'] = token.verified return res
def monero_transaction(self, verify_validity=False, **kwargs): """ Function creates a transaction and payment token using the sessions sales order Calls MoneroSalesOrder.salesorder_payment_sync() :param verify_validity: :param kwargs: :return: """ sales_order = request.website.sale_get_order() _logger.info(f"received sales_order: {sales_order.id}") _logger.info(f"processing sales_order: {sales_order.id}") # Ensure there is something to proceed if not sales_order or (sales_order and not sales_order.order_line): return False assert sales_order.partner_id.id != request.website.partner_id.id # at this time the sales order has to be in xmr # the user cannot use a fiat pricelist when checking out # this won't be fixed until after a job is added to automatically # update res.currency.rate currency = request.env["res.currency"].sudo().browse( sales_order.currency_id.id) if currency.name != "XMR": raise Exception( "This pricelist is not supported, go back and select the " "Monero Pricelist") payment_acquirer_id = int(kwargs.get("acquirer_id")) payment_partner_id = int(kwargs.get("partner_id")) wallet_sub_address = SubAddress(kwargs.get("wallet_address")) # define payment token payment_token = { "name": wallet_sub_address.__repr__(), "partner_id": payment_partner_id, # partner_id creating sales order "active": False, # token shoudn't be active, the subaddress shouldn't be reused "acquirer_id": payment_acquirer_id, # surrogate key for payment acquirer "acquirer_ref": "payment.payment_acquirer_monero_rpc", } _logger.info(f"creating payment token " f"for sales_order: {sales_order.id}") token = request.env["payment.token"].sudo().create(payment_token) token_id = token.id token_short_name = token.short_name # assign values for transaction creation tx_val = { "amount": sales_order.amount_total, "reference": sales_order.name, "currency_id": sales_order.currency_id.id, "partner_id": sales_order.partner_id.id, # Referencing the Sale Order Partner ID "payment_token_id": token_id, # Associating the Payment Token ID. "acquirer_id": payment_acquirer_id, # Payment Acquirer - Monero "state": "pending", # tx is pending, # because the customer will know the address to send the tx to, # but hasn't yet sent it } _logger.info(f"getting the transaction " f"for sales_order: {sales_order.id}") # transaction = sales_order._create_payment_transaction(tx_val) transaction = sales_order.get_portal_last_transaction() if transaction.id is False: transaction = sales_order._create_payment_transaction(tx_val) _logger.info(f"created transaction: {transaction.id}") else: _logger.info(f"retrieved transaction: {transaction.id}") # store the new transaction into # the transaction list and if there's an old one, we remove it # until the day the ecommerce supports multiple orders at the same time last_tx_id = request.session.get("__website_sale_last_tx_id") last_tx = request.env["payment.transaction"].browse( last_tx_id).sudo().exists() if last_tx: PaymentProcessing.remove_payment_transaction(last_tx) PaymentProcessing.add_payment_transaction(transaction) request.session["__website_sale_last_tx_id"] = transaction.id # Sale Order is quotation sent # , so the state should be set to "sent" # , until the transaction has been verified _logger.info(f'setting sales_order state to "sent" ' f"for sales_order: {sales_order.id}") request.env.user.sale_order_ids.sudo().update({ "require_payment": "true", "state": "sent" }) payment_acquirer = ( request.env["payment.acquirer"].sudo().browse(payment_acquirer_id)) # set queue channel and max_retries settings # for queue depending on num conf settings num_conf_req = int(payment_acquirer.num_confirmation_required) if num_conf_req == 0: queue_channel = "monero_zeroconf_processing" queue_max_retries = 44 else: queue_channel = "monero_secure_processing" queue_max_retries = num_conf_req * 25 # Add payment token and sale order to transaction processing queue sales_order.with_delay( channel=queue_channel, max_retries=queue_max_retries).process_transaction( transaction, token, num_conf_req) if transaction: res = { "result": True, "id": token_id, "short_name": token_short_name, "3d_secure": False, "verified": False, } if verify_validity is not False: token.validate() res["verified"] = token.verified return res
def payment_token(self, pm_id=None, **kwargs): """OVERRIDING METHOD FROM odoo/addons/website_sale/controllers/main.py Method that handles payment using saved tokens :param int pm_id: id of the payment.token that we want to use to pay. This route is requested after payment submission : /shop/payment/monero/submit - it's called everytime, since we will use monero sub addresses as one time addresses """ # order already created, get it sales_order = request.website.sale_get_order() _logger.info(f"received token for sales_order: {sales_order.id}") _logger.info(f"processing token for sales_order: {sales_order.id}") # do not crash if the user has already paid and try to pay again if not sales_order: _logger.error("no order found") return request.redirect("/shop/?error=no_order") # see overriden method assert sales_order.partner_id.id != request.website.partner_id.id try: # pm_id is passed, make sure it's a valid int pm_id = int(pm_id) except ValueError: _logger.error("invalid token id") return request.redirect("/shop/?error=invalid_token_id") # payment token already created, get it token = request.env["payment.token"].sudo().browse(pm_id) if not token: return request.redirect("/shop/?error=token_not_found") # has the transaction already been created? tx_id = request.session["__website_sale_last_tx_id"] if tx_id: # transaction was already # established in /shop/payment/monero/submit transaction = request.env["payment.transaction"].sudo().browse( tx_id) PaymentProcessing.add_payment_transaction(transaction) # clear the tx in session, because we're done with it request.session["__website_sale_last_tx_id"] = None return request.redirect("/shop/payment/validate") else: # transaction hasn't been created tx_val = { "payment_token_id": pm_id, "return_url": "/shop/payment/validate" } transaction = sales_order._create_payment_transaction(tx_val) _logger.info(f"created transaction: {transaction.id} " f"for payment token: {token.id}") if transaction.acquirer_id.is_cryptocurrency: _logger.info( f"Processing cryptocurrency " f"payment acquirer: {transaction.acquirer_id.name}") _logger.info(f"setting sales_order state to " f'"sent" for sales_order: {sales_order.id}') sales_order.sudo().update({"state": "sent"}) _logger.info(f"setting transaction state to " f'"pending" for sales_order: {sales_order.id}') transaction.sudo().update({"state": "pending"}) PaymentProcessing.add_payment_transaction(transaction) return request.redirect("/shop/payment/validate") PaymentProcessing.add_payment_transaction(transaction) return request.redirect("/payment/process")