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 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 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 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 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 payment_validate(self, transaction_id=None, sale_order_id=None, **post): """ Method that should be called by the server when receiving an update for a transaction. State at this point : - UDPATE ME """ if sale_order_id is None: order = request.website.sale_get_order() else: order = request.env['sale.order'].sudo().browse(sale_order_id) assert order.id == request.session.get('sale_last_order_id') if transaction_id: tx = request.env['payment.transaction'].sudo().browse(transaction_id) assert tx in order.transaction_ids() elif order: tx = order.get_portal_last_transaction() else: tx = None if not order or (order.amount_total and not tx): return request.redirect('/shop') # clean context and session, then redirect to the confirmation page request.website.sale_reset() if tx and tx.state == 'draft': return request.redirect('/shop') PaymentProcessing.remove_payment_transaction(tx) return request.redirect('/shop/confirmation')
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 payment_validate(self, transaction_id=None, sale_order_id=None, **post): """ Method that should be called by the server when receiving an update for a transaction. State at this point : - UDPATE ME """ if sale_order_id is None: order = request.website.sale_get_order() else: order = request.env['sale.order'].sudo().browse(sale_order_id) assert order.id == request.session.get('sale_last_order_id') if transaction_id: tx = request.env['payment.transaction'].sudo().browse( transaction_id) assert tx in order.transaction_ids() elif order: tx = order.get_portal_last_transaction() else: tx = None if not order or (order.amount_total and not tx): return request.redirect('/shop') if order and not order.amount_total and not tx: order.with_context(send_email=True).action_confirm() return request.redirect(order.get_portal_url()) # clean context and session, then redirect to the confirmation page request.website.sale_reset() if tx and tx.state == 'draft': return request.redirect('/shop') PaymentProcessing.remove_payment_transaction(tx) values = {} if order.state == 'sale' and tx.state == 'done': partner = request.env.user.partner_id for line in order.order_line: partner_sale_line = request.env['website.sale.detail'].sudo( ).create({ 'product_tree_name': line.product_id.id, 'is_gift': False, 'qty': line.product_uom_qty, 'res_partner_id': partner.id }) print(partner_sale_line) partner.write({'sale_detail_ids': [(4, partner_sale_line.id)]}) values.update({'tree_id': partner_sale_line}) # return request.redirect('/shop/confirmation') # return request.redirect('/shopping-thankyou', {'tree_id': partner_sale_line.tree_id}) return request.render('shop.shop_thank', values)
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, 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 portal_my_invoice_detail(self, invoice_id, access_token=None, report_type=None, download=False, **kw): # fmt: on # override in order to not retrieve release capital request as invoices try: invoice_sudo = self._document_check_access("account.invoice", invoice_id, access_token) except (AccessError, MissingError): return request.redirect("/my") if invoice_sudo.release_capital_request: report_ref = "easy_my_coop.action_cooperator_invoices" else: report_ref = "account.account_invoices" if report_type in ("html", "pdf", "text"): return self._show_report( model=invoice_sudo, report_type=report_type, report_ref=report_ref, download=download, ) values = self._invoice_get_page_view_values(invoice_sudo, access_token, **kw) PaymentProcessing.remove_payment_transaction( invoice_sudo.transaction_ids) return request.render("account.portal_invoice_page", values)
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 payment_validate(self, transaction_id=None, sale_order_id=None, **post): """ Method that should be called by the server when receiving an update for a transaction. State at this point : - UDPATE ME """ if sale_order_id is None: order = request.website.sale_get_order() else: order = request.env['sale.order'].sudo().browse(sale_order_id) assert order.id == request.session.get('sale_last_order_id') if transaction_id: tx = request.env['payment.transaction'].sudo().browse(transaction_id) assert tx in order.transaction_ids() elif order: tx = order.get_portal_last_transaction() else: tx = None if not order or (order.amount_total and not tx): return request.redirect('/shop') #added by sagar if order: values = { 'sale_id':order.id, } for line in order.order_line: order_date = datetime.datetime.strftime(order.date_order, '%d-%m-%Y') end_date = order.date_order + timedelta(days=line.product_id.no_of_days) end_date = datetime.datetime.strftime(end_date, '%d-%m-%Y') values.update({ 'plan':line.product_id.id, 'days':line.product_id.no_of_days, 'amount':line.price_total, 'start_date':order_date, 'end_date':end_date, 'payment_date':order_date, 'partner_id':order.partner_id.id }) if values: new_transaction_history_id = request.env['transaction.history'].sudo().create(values) ################ # clean context and session, then redirect to the confirmation page request.website.sale_reset() if tx and tx.state == 'draft': return request.redirect('/shop') PaymentProcessing.remove_payment_transaction(tx) return request.redirect('/shop/confirmation')
def portal_my_invoice_detail(self, invoice_id, access_token=None, report_type=None, download=False, **kw): try: invoice_sudo = self._document_check_access('account.invoice', invoice_id, access_token) except (AccessError, MissingError): return request.redirect('/my') if report_type in ('html', 'pdf', 'text'): return self._show_report(model=invoice_sudo, report_type=report_type, report_ref='account.account_invoices', download=download) values = self._invoice_get_page_view_values(invoice_sudo, access_token, **kw) PaymentProcessing.remove_payment_transaction(invoice_sudo.transaction_ids) return request.render("account.portal_invoice_page", values)
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 payment_validate(self, transaction_id=None, sale_order_id=None, **post): if sale_order_id is None: order = request.website.sale_get_order() else: order = request.env['sale.order'].sudo().browse(sale_order_id) assert order.id == request.session.get('sale_last_order_id') if transaction_id: tx = request.env['payment.transaction'].sudo().browse( transaction_id) assert tx in order.transaction_ids() elif order: tx = order.get_portal_last_transaction() else: tx = None if not order or (order.amount_total and not tx): return request.redirect('/shop') if order and not order.amount_total and not tx: return request.redirect(order.get_portal_url()) # clean context and session, then redirect to the confirmation page request.website.sale_reset() if tx and tx.state == 'draft': return request.redirect('/shop') PaymentProcessing.remove_payment_transaction(tx) order.message_subscribe(partner_ids=[3], subtype_ids=[1, 7, 8]) order.message_post( body=_('A new order has been placed using %s payment method.') % order.transaction_ids[0].acquirer_id.name, partner_ids=[3], record_name=order.display_name, res_id=order.id, model='sale.order', subtype_id=1, notif_layout='mail.mail_notification_light') return request.redirect('/shop/confirmation')
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 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 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 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") # 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 confirm_order(self, **post): order = request.website.sale_get_order() user_id = request.env.user redirection = self.checkout_redirection(order) if redirection: return redirection transaction_id = None if transaction_id: tx = request.env['payment.transaction'].sudo().browse( transaction_id) assert tx in order.transaction_ids() elif order: tx = order.get_portal_last_transaction() else: tx = None email = post.get('email') name = post.get('name') phone = post.get('phone') pickup_type = post.get('pickup_type') city = post.get('city') street = post.get('street') zip1 = post.get('zip') state_id = post.get('state_id') country_id = post.get('country_id') if pickup_type in ['pickup_paystore', 'pickup_paynow']: if email and name and phone: partner = request.env['res.partner'].search( [('email', '=', post.get('email'))], limit=1) if request.website.is_public_user(): if not partner: partner = request.env['res.partner'].sudo().create({ 'name': post.get('name'), 'email': post.get('email'), 'phone': post.get('phone'), }) order.write({ 'partner_id': partner.id, 'partner_invoice_id': partner.id, 'partner_shipping_id': partner.id, }) if not partner: partner = request.env['res.partner'].sudo().create({ 'name': post.get('name'), 'email': post.get('email'), 'phone': post.get('phone'), 'type': 'other', 'parent_id': user_id.partner_id.id }) order.write({ 'checkout_option': post.get('pickup_type'), 'pickup_id': partner.id, }) order.onchange_partner_shipping_id() order.order_line._compute_tax_id() request.session['sale_last_order_id'] = order.id request.website.sale_get_order(update_pricelist=True) if pickup_type == 'pickup_paystore': order.with_context(send_email=True).action_confirm() request.website.sale_reset() PaymentProcessing.remove_payment_transaction(tx) return request.render("website_sale.confirmation", {'order': order}) if pickup_type == 'pickup_paynow': extra_step = request.website.viewref( 'website_sale.extra_info_option') if extra_step.active: return request.redirect("/shop/extra_info") return request.redirect("/shop/payment") elif pickup_type in ['paynow_delivery', 'payon_delivery']: if email and name and phone and city and street and country_id: partner = request.env['res.partner'].search( [('email', '=', email)], limit=1) if request.website.is_public_user(): if not partner: partner = request.env['res.partner'].sudo().create({ 'name': name, 'email': email, 'phone': phone, 'city': city, 'street': street, 'zip': zip1, 'state_id': int(state_id) or False, 'country_id': int(country_id) or False, }) order.write({ 'partner_id': partner.id, 'partner_invoice_id': partner.id, 'partner_shipping_id': partner.id, }) if not partner: partner = request.env['res.partner'].sudo().create({ 'name': name, 'email': email, 'phone': phone, 'type': 'other', 'parent_id': user_id.partner_id.id, 'city': city, 'street': street, 'zip': zip1, 'state_id': int(state_id) or False, 'country_id': int(country_id) or False, }) order.write({ 'checkout_option': post.get('pickup_type'), 'pickup_id': partner.id, }) order.onchange_partner_shipping_id() order.order_line._compute_tax_id() request.session['sale_last_order_id'] = order.id request.website.sale_get_order(update_pricelist=True) if pickup_type == 'paynow_delivery': extra_step = request.website.viewref( 'website_sale.extra_info_option') if extra_step.active: return request.redirect("/shop/extra_info") return request.redirect("/shop/payment") if pickup_type == 'payon_delivery': order.with_context(send_email=True).action_confirm() request.website.sale_reset() PaymentProcessing.remove_payment_transaction(tx) return request.render("website_sale.confirmation", {'order': order}) else: order = request.website.sale_get_order() redirection = self.checkout_redirection(order) if redirection: return redirection order.onchange_partner_shipping_id() order.order_line._compute_tax_id() request.session['sale_last_order_id'] = order.id request.website.sale_get_order(update_pricelist=True) extra_step = request.website.viewref( 'website_sale.extra_info_option') if extra_step.active: return request.redirect("/shop/extra_info") return request.redirect("/shop/payment")
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 payment_validate(self, transaction_id=None, sale_order_id=None, **post): """ Method that should be called by the server when receiving an update for a transaction. State at this point : - UDPATE ME """ if sale_order_id is None: order = request.website.sale_get_order() else: order = request.env['sale.order'].sudo().browse(sale_order_id) assert order.id == request.session.get('sale_last_order_id') if transaction_id: tx = request.env['payment.transaction'].sudo().browse(transaction_id) assert tx in order.transaction_ids() elif order: tx = order.get_portal_last_transaction() else: tx = None if not order or (order.amount_total and not tx): return request.redirect('/shop') if tx.acquirer_id.provider == 'cod': payment_acquirer_obj = request.env['payment.acquirer'].sudo().search([('id','=', tx.acquirer_id.id)]) order = request.website.sale_get_order() product_obj = request.env['product.product'].browse() extra_fees_product = request.env['ir.model.data'].get_object_reference('bi_website_cash_on_delivery', 'product_product_fees')[1] product_ids = product_obj.sudo().search([('product_tmpl_id.id', '=', extra_fees_product)]) order_line_obj = request.env['sale.order.line'].sudo().search([]) flag = 0 for i in order_line_obj: if i.product_id.id == product_ids.id and i.order_id.id == order.id: flag = flag + 1 if flag == 0: order_line_obj.sudo().create({ 'product_id': product_ids.id, 'name': 'Extra Fees', 'price_unit': payment_acquirer_obj.delivery_fees, 'order_id': order.id, 'product_uom':product_ids.uom_id.id, }) #order.force_quotation_send() order.with_context(send_email=True).action_confirm() request.website.sale_reset() return request.render("website_sale.confirmation", {'order': order}) if (not order.amount_total and not tx) or tx.state in ['pending', 'done', 'authorized']: if (not order.amount_total and not tx): # Orders are confirmed by payment transactions, but there is none for free orders, # (e.g. free events), so confirm immediately order.with_context(send_email=True).action_confirm() elif tx and tx.state == 'cancel': # cancel the quotation order.action_cancel() # clean context and session, then redirect to the confirmation page request.website.sale_reset() if tx and tx.state == 'draft': return request.redirect('/shop') PaymentProcessing.remove_payment_transaction(tx) return request.redirect('/shop/confirmation')
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")