diff --git a/addons/purchase_requisition/purchase_requisition.py b/addons/purchase_requisition/purchase_requisition.py
index ada65b7a187..09fd6d0eff9 100644
--- a/addons/purchase_requisition/purchase_requisition.py
+++ b/addons/purchase_requisition/purchase_requisition.py
@@ -19,9 +19,6 @@
# along with this program. If not, see .
#
##############################################################################
-from datetime import datetime
-from dateutil.relativedelta import relativedelta
-import time
from openerp.osv import fields, osv
from openerp.tools.translate import _
@@ -55,7 +52,7 @@ class purchase_requisition(osv.osv):
'procurement_id': fields.many2one('procurement.order', 'Procurement', ondelete='set null'),
'warehouse_id': fields.many2one('stock.warehouse', 'Warehouse'),
'state': fields.selection([('draft', 'Draft'), ('in_progress', 'Confirmed'), ('open', 'Bid Selection'), ('done', 'PO Created'), ('cancel', 'Cancelled')],
- 'Status', track_visibility='onchange', required=True),
+ 'Status', track_visibility='onchange', required=True),
'multiple_rfq_per_supplier': fields.boolean('Multiple RFQ per supplier'),
'account_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account'),
'picking_type_id': fields.many2one('stock.picking.type', 'Picking Type', required=True),
@@ -63,7 +60,7 @@ class purchase_requisition(osv.osv):
def _get_picking_in(self, cr, uid, context=None):
obj_data = self.pool.get('ir.model.data')
- return obj_data.get_object_reference(cr, uid, 'stock','picking_type_in')[1]
+ return obj_data.get_object_reference(cr, uid, 'stock', 'picking_type_in')[1]
_defaults = {
'state': 'draft',
@@ -85,14 +82,11 @@ class purchase_requisition(osv.osv):
def tender_cancel(self, cr, uid, ids, context=None):
purchase_order_obj = self.pool.get('purchase.order')
- #try to set all associated quotations to cancel state
- purchase_ids = []
+ # try to set all associated quotations to cancel state
for tender in self.browse(cr, uid, ids, context=context):
for purchase_order in tender.purchase_ids:
purchase_order_obj.action_cancel(cr, uid, [purchase_order.id], context=context)
purchase_order_obj.message_post(cr, uid, [purchase_order.id], body=_('Cancelled by the tender associated to this quotation.'), context=context)
- procurement_ids = self.pool['procurement.order'].search(cr, uid, [('requisition_id', 'in', ids)], context=context)
- self.pool['procurement.order'].action_done(cr, uid, procurement_ids)
return self.write(cr, uid, ids, {'state': 'cancel'})
def tender_in_progress(self, cr, uid, ids, context=None):
@@ -110,8 +104,6 @@ class purchase_requisition(osv.osv):
return True
def tender_done(self, cr, uid, ids, context=None):
- procurement_ids = self.pool['procurement.order'].search(cr, uid, [('requisition_id', 'in', ids)], context=context)
- self.pool['procurement.order'].action_done(cr, uid, procurement_ids)
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
def open_product_line(self, cr, uid, ids, context=None):
@@ -167,8 +159,11 @@ class purchase_requisition(osv.osv):
date_order = requisition.ordering_date or fields.date.context_today(self, cr, uid, context=context)
qty = product_uom._compute_qty(cr, uid, requisition_line.product_uom_id.id, requisition_line.product_qty, default_uom_po_id)
supplier_pricelist = supplier.property_product_pricelist_purchase and supplier.property_product_pricelist_purchase.id or False
- vals = po_line_obj.onchange_product_id(cr, uid, [], supplier_pricelist, product.id, qty, default_uom_po_id,
- supplier.id, date_order=date_order, fiscal_position_id=supplier.property_account_position, date_planned=requisition_line.schedule_date,
+ vals = po_line_obj.onchange_product_id(
+ cr, uid, [], supplier_pricelist, product.id, qty, default_uom_po_id,
+ supplier.id, date_order=date_order,
+ fiscal_position_id=supplier.property_account_position,
+ date_planned=requisition_line.schedule_date,
name=False, price_unit=False, state='draft', context=context)['value']
vals.update({
'order_id': purchase_id,
@@ -237,8 +232,6 @@ class purchase_requisition(osv.osv):
"""
Generate all purchase order based on selected lines, should only be called on one tender at a time
"""
- if context is None:
- contex = {}
po = self.pool.get('purchase.order')
poline = self.pool.get('purchase.order.line')
id_per_supplier = {}
@@ -271,8 +264,7 @@ class purchase_requisition(osv.osv):
id_per_supplier[po_line.partner_id.id] = [po_line]
#generate po based on supplier and cancel all previous RFQ
- ctx = context.copy()
- ctx['force_requisition_id'] = True
+ ctx = dict(context or {}, force_requisition_id=True)
for supplier, product_line in id_per_supplier.items():
#copy a quotation for this supplier and change order_line then validate it
quotation_id = po.search(cr, uid, [('requisition_id', '=', tender.id), ('partner_id', '=', supplier)], limit=1)[0]
@@ -356,10 +348,6 @@ class purchase_order(osv.osv):
proc_obj.write(cr, uid, proc_ids, {'purchase_id': po.id})
self.signal_purchase_cancel(cr, uid, [order.id])
po.requisition_id.tender_done(context=context)
- if po.requisition_id and all(purchase_id.state in ['draft', 'cancel'] for purchase_id in po.requisition_id.purchase_ids if purchase_id.id != po.id):
- procurement_ids = self.pool['procurement.order'].search(cr, uid, [('requisition_id', '=', po.requisition_id.id)], context=context)
- for procurement in proc_obj.browse(cr, uid, procurement_ids, context=context):
- procurement.move_id.write({'location_id': procurement.move_id.location_dest_id.id})
return res
def copy(self, cr, uid, id, default=None, context=None):
@@ -437,12 +425,9 @@ class procurement_order(osv.osv):
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
def _check(self, cr, uid, procurement, context=None):
- requisition_obj = self.pool.get('purchase.requisition')
if procurement.rule_id and procurement.rule_id.action == 'buy' and procurement.product_id.purchase_requisition:
if procurement.requisition_id.state == 'done':
if any([purchase.shipped for purchase in procurement.requisition_id.purchase_ids]):
return True
return False
return super(procurement_order, self)._check(cr, uid, procurement, context=context)
-
-# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/website/models/ir_http.py b/addons/website/models/ir_http.py
index 56194dd34fe..7c7ad354cdc 100644
--- a/addons/website/models/ir_http.py
+++ b/addons/website/models/ir_http.py
@@ -87,7 +87,6 @@ class ir_http(orm.AbstractModel):
# to url without language so google doesn't see duplicate content
return request.redirect(path + '?' + request.httprequest.query_string)
return self.reroute(path)
- return self._handle_exception(code=404)
return super(ir_http, self)._dispatch()
def reroute(self, path):
@@ -115,8 +114,8 @@ class ir_http(orm.AbstractModel):
try:
_, path = rule.build(arguments)
assert path is not None
- except Exception:
- return self._handle_exception(werkzeug.exceptions.NotFound())
+ except Exception, e:
+ return self._handle_exception(e, code=404)
if getattr(request, 'website_multilang', False) and request.httprequest.method in ('GET', 'HEAD'):
generated_path = werkzeug.url_unquote_plus(path)
@@ -148,55 +147,70 @@ class ir_http(orm.AbstractModel):
if response.status_code == 304:
return response
- response.mimetype = attach[0]['mimetype']
+ response.mimetype = attach[0]['mimetype'] or 'application/octet-stream'
response.data = datas.decode('base64')
return response
- def _handle_exception(self, exception=None, code=500):
- try:
+ def _handle_exception(self, exception, code=500):
+ # This is done first as the attachment path may
+ # not match any HTTP controller, so the request
+ # may not be website-enabled.
+ attach = self._serve_attachment()
+ if attach:
+ return attach
+
+ is_website_request = bool(getattr(request, 'website_enabled', False) and request.website)
+ if not is_website_request:
+ # Don't touch non website requests exception handling
return super(ir_http, self)._handle_exception(exception)
- except Exception:
+ else:
+ try:
+ response = super(ir_http, self)._handle_exception(exception)
+ if isinstance(response, Exception):
+ exception = response
+ else:
+ # if parent excplicitely returns a plain response, then we don't touch it
+ return response
+ except Exception, e:
+ exception = e
- attach = self._serve_attachment()
- if attach:
- return attach
+ values = dict(
+ exception=exception,
+ traceback=traceback.format_exc(exception),
+ )
+ code = getattr(exception, 'code', code)
- if getattr(request, 'website_enabled', False) and request.website:
- values = dict(
- exception=exception,
- traceback=traceback.format_exc(exception),
- )
- if exception:
- code = getattr(exception, 'code', code)
- if isinstance(exception, ir_qweb.QWebException):
- values.update(qweb_exception=exception)
- if isinstance(exception.qweb.get('cause'), openerp.exceptions.AccessError):
- code = 403
- if code == 500:
- logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
- if 'qweb_exception' in values:
- view = request.registry.get("ir.ui.view")
- views = view._views_get(request.cr, request.uid, exception.qweb['template'], request.context)
- to_reset = [v for v in views if v.model_data_id.noupdate is True]
- values['views'] = to_reset
- elif code == 403:
- logger.warn("403 Forbidden:\n\n%s", values['traceback'])
+ if isinstance(exception, openerp.exceptions.AccessError):
+ code = 403
- values.update(
- status_message=werkzeug.http.HTTP_STATUS_CODES[code],
- status_code=code,
- )
+ if isinstance(exception, ir_qweb.QWebException):
+ values.update(qweb_exception=exception)
+ if isinstance(exception.qweb.get('cause'), openerp.exceptions.AccessError):
+ code = 403
- if not request.uid:
- self._auth_method_public()
+ if code == 500:
+ logger.error("500 Internal Server Error:\n\n%s", values['traceback'])
+ if 'qweb_exception' in values:
+ view = request.registry.get("ir.ui.view")
+ views = view._views_get(request.cr, request.uid, exception.qweb['template'], request.context)
+ to_reset = [v for v in views if v.model_data_id.noupdate is True]
+ values['views'] = to_reset
+ elif code == 403:
+ logger.warn("403 Forbidden:\n\n%s", values['traceback'])
- try:
- html = request.website._render('website.%s' % code, values)
- except Exception:
- html = request.website._render('website.http_error', values)
- return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
+ values.update(
+ status_message=werkzeug.http.HTTP_STATUS_CODES[code],
+ status_code=code,
+ )
- raise
+ if not request.uid:
+ self._auth_method_public()
+
+ try:
+ html = request.website._render('website.%s' % code, values)
+ except Exception:
+ html = request.website._render('website.http_error', values)
+ return werkzeug.wrappers.Response(html, status=code, content_type='text/html;charset=utf-8')
class ModelConverter(ir.ir_http.ModelConverter):
def __init__(self, url_map, model=False, domain='[]'):
diff --git a/addons/website_forum/controllers/main.py b/addons/website_forum/controllers/main.py
index aa4123d039a..0d27f70e486 100644
--- a/addons/website_forum/controllers/main.py
+++ b/addons/website_forum/controllers/main.py
@@ -208,12 +208,16 @@ class WebsiteForum(http.Controller):
}, context=context)
return werkzeug.utils.redirect("/forum/%s/question/%s" % (slug(forum), new_question_id))
- @http.route(['''/forum//question/'''], type='http', auth="public", website=True)
+ @http.route(['''/forum//question/'''], type='http', auth="public", website=True)
def question(self, forum, question, **post):
cr, uid, context = request.cr, request.uid, request.context
# increment view counter
request.registry['forum.post'].set_viewed(cr, SUPERUSER_ID, [question.id], context=context)
+ if question.parent_id:
+ redirect_url = "/forum/%s/question/%s" % (slug(forum), slug(question.parent_id))
+ return werkzeug.utils.redirect(redirect_url, 301)
+
filters = 'question'
values = self._prepare_forum_values(forum=forum, searches=post)
values.update({
diff --git a/openerp/http.py b/openerp/http.py
index fcbd2581350..d8c1874dd79 100644
--- a/openerp/http.py
+++ b/openerp/http.py
@@ -1266,7 +1266,10 @@ class Root(object):
request = self.get_request(httprequest)
def _dispatch_nodb():
- func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match()
+ try:
+ func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match()
+ except werkzeug.exceptions.HTTPException, e:
+ return request._handle_exception(e)
request.set_handler(func, arguments, "none")
result = request.dispatch()
return result