Files
odoo_source/addons/website_quote/controllers/main.py
T
Denis Ledoux dd28f9bf78 [FIX] website_quote: /quote/ redirects to login when not signed in and no token
When the route /quote/<order_id>
is accessed without token
e.g. through the `View sales Order` button
in the headers of thread mails

the user must be redirected to the login screen
if he's not signed in.

In other words, you must be signed in to access
this route without token.

opw-687931
2016-09-29 15:06:38 +02:00

233 lines
13 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import SUPERUSER_ID
from openerp.addons.web import http
from openerp.addons.web.http import request
import werkzeug
import datetime
import time
from openerp.tools.translate import _
from openerp.addons.website_mail.controllers.main import _message_post_helper
class sale_quote(http.Controller):
@http.route("/quote/<int:order_id>", type='http', auth="user", website=True)
def view_user(self, *args, **kwargs):
return self.view(*args, **kwargs)
@http.route("/quote/<int:order_id>/<token>", type='http', auth="public", website=True)
def view(self, order_id, pdf=None, token=None, message=False, **post):
# use SUPERUSER_ID allow to access/view order for public user
# only if he knows the private token
order = request.registry.get('sale.order').browse(request.cr, token and SUPERUSER_ID or request.uid, order_id, request.context)
now = time.strftime('%Y-%m-%d')
dummy, action = request.registry.get('ir.model.data').get_object_reference(request.cr, request.uid, 'sale', 'action_quotations')
if token:
if token != order.access_token:
return request.website.render('website.404')
# Log only once a day
if request.session.get('view_quote',False)!=now:
request.session['view_quote'] = now
body=_('Quotation viewed by customer')
_message_post_helper(res_model='sale.order', res_id=order.id, message=body, token=token, token_field="access_token", message_type='notification', subtype="mail.mt_note", partner_ids=order.user_id.partner_id.ids)
days = 0
if order.validity_date:
days = (datetime.datetime.strptime(order.validity_date, '%Y-%m-%d') - datetime.datetime.now()).days + 1
if pdf:
report_obj = request.registry['report']
pdf = report_obj.get_pdf(request.cr, SUPERUSER_ID, [order_id], 'website_quote.report_quote', data=None, context=dict(request.context, set_viewport_size=True))
pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))]
return request.make_response(pdf, headers=pdfhttpheaders)
user = request.registry['res.users'].browse(request.cr, SUPERUSER_ID, request.uid, context=request.context)
tx_id = request.session.get('quote_%s_transaction_id' % order.id)
if not tx_id:
tx_id = request.registry['payment.transaction'].search(request.cr, SUPERUSER_ID, [('reference', '=', order.name)], context=request.context)
tx = request.registry['payment.transaction'].browse(request.cr, SUPERUSER_ID, tx_id, context=request.context) if tx_id else False
values = {
'quotation': order,
'message': message and int(message) or False,
'option': bool(filter(lambda x: not x.line_id, order.options)),
'order_valid': (not order.validity_date) or (now <= order.validity_date),
'days_valid': days,
'action': action,
'breadcrumb': user.partner_id == order.partner_id,
'tx_id': tx_id,
'tx_state': tx.state if tx else False,
'tx_post_msg': tx.acquirer_id.post_msg if tx else False,
'need_payment': order.invoice_status == 'to invoice' and (not tx or tx.state in ['draft', 'cancel', 'error']),
'token': token,
}
if order.require_payment or values['need_payment']:
payment_obj = request.registry.get('payment.acquirer')
acquirer_ids = payment_obj.search(request.cr, SUPERUSER_ID, [('website_published', '=', True), ('company_id', '=', order.company_id.id)], context=request.context)
values['acquirers'] = list(payment_obj.browse(request.cr, token and SUPERUSER_ID or request.uid, acquirer_ids, context=request.context))
render_ctx = dict(request.context, submit_class='btn btn-primary', submit_txt=_('Pay & Confirm'))
for acquirer in values['acquirers']:
acquirer.button = payment_obj.render(
request.cr, SUPERUSER_ID, acquirer.id,
'/',
order.amount_total,
order.pricelist_id.currency_id.id,
values={
'return_url': '/quote/%s/%s' % (order_id, token) if token else '/quote/%s' % order_id,
'type': 'form',
'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'),
'partner_id': order.partner_id.id,
},
context=render_ctx)
return request.website.render('website_quote.so_quotation', values)
@http.route(['/quote/accept'], type='json', auth="public", website=True)
def accept(self, order_id, token=None, signer=None, sign=None, **post):
order_obj = request.registry.get('sale.order')
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
if token != order.access_token:
return request.website.render('website.404')
if order.require_payment:
return request.website.render('website.404')
if order.state != 'sent':
return False
attachments=sign and [('signature.png', sign.decode('base64'))] or []
order_obj.action_confirm(request.cr, SUPERUSER_ID, [order_id], context=request.context)
message = _('Order signed by %s') % (signer,)
_message_post_helper(message=message, res_id=order_id, res_model='sale.order', attachments=attachments, **({'token': token, 'token_field': 'access_token'} if token else {}))
return True
@http.route(['/quote/<int:order_id>/<token>/decline'], type='http', auth="public", methods=['POST'], website=True)
def decline(self, order_id, token, **post):
order_obj = request.registry.get('sale.order')
order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
if token != order.access_token:
return request.website.render('website.404')
if order.state != 'sent':
return werkzeug.utils.redirect("/quote/%s/%s?message=4" % (order_id, token))
request.registry.get('sale.order').action_cancel(request.cr, SUPERUSER_ID, [order_id])
message = post.get('decline_message')
if message:
_message_post_helper(message=message, res_id=order_id, res_model='sale.order', **{'token': token, 'token_field': 'access_token'} if token else {})
return werkzeug.utils.redirect("/quote/%s/%s?message=2" % (order_id, token))
@http.route(['/quote/update_line'], type='json', auth="public", website=True)
def update(self, line_id, remove=False, unlink=False, order_id=None, token=None, **post):
order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, int(order_id))
if token != order.access_token:
return request.website.render('website.404')
if order.state not in ('draft','sent'):
return False
line_id=int(line_id)
if unlink:
request.registry.get('sale.order.line').unlink(request.cr, SUPERUSER_ID, [line_id], context=request.context)
return False
number=(remove and -1 or 1)
order_line_obj = request.registry.get('sale.order.line')
order_line_val = order_line_obj.read(request.cr, SUPERUSER_ID, [line_id], [], context=request.context)[0]
quantity = order_line_val['product_uom_qty'] + number
order_line_obj.write(request.cr, SUPERUSER_ID, [line_id], {'product_uom_qty': (quantity)}, context=request.context)
return [str(quantity), str(order.amount_total)]
@http.route(["/quote/template/<model('sale.quote.template'):quote>"], type='http', auth="user", website=True)
def template_view(self, quote, **post):
values = { 'template': quote }
return request.website.render('website_quote.so_template', values)
@http.route(["/quote/add_line/<int:option_id>/<int:order_id>/<token>"], type='http', auth="public", website=True)
def add(self, option_id, order_id, token, **post):
vals = {}
order = request.registry.get('sale.order').browse(request.cr, SUPERUSER_ID, order_id)
if token != order.access_token:
return request.website.render('website.404')
if order.state not in ['draft', 'sent']:
return request.website.render('website.http_error', {'status_code': 'Forbidden', 'status_message': _('You cannot add options to a confirmed order.')})
option_obj = request.registry.get('sale.order.option')
option = option_obj.browse(request.cr, SUPERUSER_ID, option_id)
vals = {
'price_unit': option.price_unit,
'website_description': option.website_description,
'name': option.name,
'order_id': order.id,
'product_id': option.product_id.id,
'product_uom_qty': option.quantity,
'product_uom': option.uom_id.id,
'discount': option.discount,
}
line = request.registry.get('sale.order.line').create(request.cr, SUPERUSER_ID, vals, context=request.context)
request.registry.get('sale.order.line')._compute_tax_id(request.cr, SUPERUSER_ID, [line], context=request.context)
option_obj.write(request.cr, SUPERUSER_ID, [option.id], {'line_id': line}, context=request.context)
return werkzeug.utils.redirect("/quote/%s/%s#pricing" % (order.id, token))
# note dbo: website_sale code
@http.route(['/quote/<int:order_id>/transaction/<int:acquirer_id>'], type='json', auth="public", website=True)
def payment_transaction(self, acquirer_id, order_id):
return self.payment_transaction_token(acquirer_id, order_id, None)
@http.route(['/quote/<int:order_id>/transaction/<int:acquirer_id>/<token>'], type='json', auth="public", website=True)
def payment_transaction_token(self, acquirer_id, order_id, token):
""" 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
"""
cr, uid, context = request.cr, request.uid, request.context
payment_obj = request.registry.get('payment.acquirer')
transaction_obj = request.registry.get('payment.transaction')
order = request.registry.get('sale.order').browse(cr, SUPERUSER_ID, order_id, context=context)
if not order or not order.order_line or acquirer_id is None:
return request.redirect("/quote/" + str(order_id))
# find an already existing transaction
tx_id = transaction_obj.search(cr, SUPERUSER_ID, [('reference', '=', order.name)], context=context)
tx = transaction_obj.browse(cr, SUPERUSER_ID, tx_id, context=context)
if tx:
if tx.sale_order_id.id != order.id or tx.state in ['error', 'cancel'] or tx.acquirer_id.id != acquirer_id:
tx = False
tx_id = False
elif tx.state == 'draft':
tx.write({
'amount': order.amount_total,
})
if not tx:
tx_id = transaction_obj.create(cr, SUPERUSER_ID, {
'acquirer_id': acquirer_id,
'type': order._get_payment_type(),
'amount': order.amount_total,
'currency_id': order.pricelist_id.currency_id.id,
'partner_id': order.partner_id.id,
'reference': transaction_obj.get_next_reference(cr, uid, order.name, context=context),
'sale_order_id': order.id,
'callback_eval': "self.env['sale.order']._confirm_online_quote(self.sale_order_id.id, self)"
}, context=context)
request.session['quote_%s_transaction_id' % order.id] = tx_id
tx = transaction_obj.browse(cr, SUPERUSER_ID, tx_id, context=context)
# update quotation
request.registry['sale.order'].write(
cr, SUPERUSER_ID, [order.id], {
'payment_acquirer_id': acquirer_id,
'payment_tx_id': tx_id
}, context=context)
# confirm the quotation
if tx.acquirer_id.auto_confirm == 'at_pay_now':
request.registry['sale.order'].action_confirm(cr, SUPERUSER_ID, [order.id], context=dict(request.context, send_email=True))
return payment_obj.render(
request.cr, SUPERUSER_ID, tx.acquirer_id.id,
tx.reference,
order.amount_total,
order.pricelist_id.currency_id.id,
values={
'return_url': '/quote/%s/%s' % (order_id, token) if token else '/quote/%s' % order_id,
'type': order._get_payment_type(),
'alias_usage': _('If we store your payment information on our server, subscription payments will be made automatically.'),
'partner_id': order.partner_shipping_id.id or order.partner_invoice_id.id,
'billing_partner_id': order.partner_invoice_id.id,
},
context=dict(context, submit_class='btn btn-primary', submit_txt=_('Pay & Confirm')))