Merge remote-tracking branch 'odoo/master' into master-wmsstaging3-jco
This commit is contained in:
commit
ef228f273f
|
@ -27,11 +27,11 @@ class project_configuration(osv.osv_memory):
|
|||
_inherit = 'res.config.settings'
|
||||
|
||||
_columns = {
|
||||
'module_project_mrp': fields.boolean('Generate tasks from sale orders',
|
||||
'module_sale_service': fields.boolean('Generate tasks from sale orders',
|
||||
help='This feature automatically creates project tasks from service products in sale orders. '
|
||||
'More precisely, tasks are created for procurement lines with product of type \'Service\', '
|
||||
'procurement method \'Make to Order\', and supply method \'Manufacture\'.\n'
|
||||
'-This installs the module project_mrp.'),
|
||||
'-This installs the module sale_service.'),
|
||||
'module_pad': fields.boolean("Use integrated collaborative note pads on task",
|
||||
help='Lets the company customize which Pad installation should be used to link to new pads '
|
||||
'(for example: http://ietherpad.com/).\n'
|
||||
|
|
|
@ -33,8 +33,8 @@
|
|||
<label for="module_project_timesheet"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="module_project_mrp" class="oe_inline"/>
|
||||
<label for="module_project_mrp"/>
|
||||
<field name="module_sale_service" class="oe_inline"/>
|
||||
<label for="module_sale_service"/>
|
||||
</div>
|
||||
<div>
|
||||
<field name="module_pad" class="oe_inline"/>
|
||||
|
|
|
@ -134,14 +134,15 @@ class Report(osv.Model):
|
|||
website = None
|
||||
if request and hasattr(request, 'website'):
|
||||
website = request.website
|
||||
values.update({
|
||||
'time': time,
|
||||
'translate_doc': translate_doc,
|
||||
'editable': True, # Will active inherit_branding
|
||||
'user': user,
|
||||
'res_company': user.company_id,
|
||||
'website': website,
|
||||
})
|
||||
values.update(
|
||||
time=time,
|
||||
translate_doc=translate_doc,
|
||||
editable=True, # Will active inherit_branding
|
||||
user=user,
|
||||
res_company=user.company_id,
|
||||
website=website,
|
||||
editable_no_editor=True,
|
||||
)
|
||||
return view_obj.render(cr, uid, template, values, context=context)
|
||||
|
||||
#--------------------------------------------------------------------------
|
||||
|
|
|
@ -122,7 +122,7 @@ Example: 10% for retailers, promotion of 5 EUR on this product, etc."""),
|
|||
def onchange_task_work(self, cr, uid, ids, task_work, context=None):
|
||||
return {'value': {
|
||||
'module_project_timesheet': task_work,
|
||||
'module_project_mrp': task_work,
|
||||
'module_sale_service': task_work,
|
||||
}}
|
||||
|
||||
def onchange_timesheet(self, cr, uid, ids, timesheet, context=None):
|
||||
|
|
|
@ -686,7 +686,7 @@ class sale_order(osv.osv):
|
|||
|
||||
def procurement_needed(self, cr, uid, ids, context=None):
|
||||
#when sale is installed only, there is no need to create procurements, that's only
|
||||
#further installed modules (project_mrp, sale_stock) that will change this.
|
||||
#further installed modules (sale_service, sale_stock) that will change this.
|
||||
sale_line_obj = self.pool.get('sale.order.line')
|
||||
res = []
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
|
@ -839,7 +839,7 @@ class sale_order_line(osv.osv):
|
|||
|
||||
def need_procurement(self, cr, uid, ids, context=None):
|
||||
#when sale is installed only, there is no need to create procurements, that's only
|
||||
#further installed modules (project_mrp, sale_stock) that will change this.
|
||||
#further installed modules (sale_service, sale_stock) that will change this.
|
||||
return False
|
||||
|
||||
def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
|
||||
|
|
|
@ -19,6 +19,6 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
import project_mrp
|
||||
import models
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
|
@ -50,8 +50,8 @@ completed.
|
|||
'website': 'http://www.openerp.com',
|
||||
'images': ['images/product.jpeg', 'images/task_from_SO.jpeg'],
|
||||
'depends': ['project', 'procurement', 'sale', 'procurement_jit'],
|
||||
'data': ['project_mrp_view.xml'], #'process/project_mrp_process.xml'
|
||||
'demo': ['project_mrp_demo.xml'],
|
||||
'data': ['views/sale_service_view.xml'],
|
||||
'demo': ['demo/sale_service_demo.xml'],
|
||||
'test': ['test/project_task_procurement.yml'],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
|
@ -0,0 +1 @@
|
|||
import sale_service
|
|
@ -151,7 +151,7 @@ class sale_order_line(osv.osv):
|
|||
_inherit = 'sale.order.line'
|
||||
|
||||
def need_procurement(self, cr, uid, ids, context=None):
|
||||
#when sale is installed alone, there is no need to create procurements, but with project_mrp
|
||||
#when sale is installed alone, there is no need to create procurements, but with sale_service
|
||||
#we must create a procurement for each service that has the auto_create_task boolean set to True.
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
if line.product_id and line.product_id.type == 'service' and line.product_id.auto_create_task:
|
|
@ -14,7 +14,7 @@
|
|||
<record id="view_product_task_form" model="ir.ui.view">
|
||||
<field name="name">product.form.view.inherit</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="stock.view_template_property_form"/>
|
||||
<field name="inherit_id" ref="product.product_template_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<group name="procurement_uom" position="after">
|
||||
<group string="Project Management Information" attrs="{'invisible': [('type', '!=', 'service')]}">
|
||||
|
@ -34,8 +34,8 @@
|
|||
</field>
|
||||
</field>
|
||||
</record>
|
||||
<record id="view_project_mrp_inherit_form2" model="ir.ui.view">
|
||||
<field name="name">project.mrp.form.view.inherit</field>
|
||||
<record id="view_sale_service_inherit_form2" model="ir.ui.view">
|
||||
<field name="name">sale.service.form.view.inherit</field>
|
||||
<field name="model">project.task</field>
|
||||
<field name="inherit_id" ref="project.view_task_form2"/>
|
||||
<field name="arch" type="xml">
|
|
@ -35,7 +35,7 @@ class sale_configuration(osv.osv_memory):
|
|||
help='Lets you transfer the entries under tasks defined for Project Management to '
|
||||
'the Timesheet line entries for particular date and particular user with the effect of creating, editing and deleting either ways '
|
||||
'and to automatically creates project tasks from procurement lines.\n'
|
||||
'-This installs the modules project_timesheet and project_mrp.'),
|
||||
'-This installs the modules project_timesheet and sale_service.'),
|
||||
'default_order_policy': fields.selection(
|
||||
[('manual', 'Invoice based on sales orders'), ('picking', 'Invoice based on deliveries')],
|
||||
'The default invoicing method is', default_model='sale.order',
|
||||
|
@ -50,7 +50,7 @@ class sale_configuration(osv.osv_memory):
|
|||
implied_group='sale.group_mrp_properties',
|
||||
help="Allows you to tag sales order lines with properties."),
|
||||
'module_project_timesheet': fields.boolean("Project Timesheet"),
|
||||
'module_project_mrp': fields.boolean("Project MRP"),
|
||||
'module_sale_service': fields.boolean("Sale Service"),
|
||||
'group_route_so_lines': fields.boolean('Choose MTO, drop shipping,... on sales order lines',
|
||||
implied_group='sale_stock.group_route_so_lines',
|
||||
help="Allows you to choose a delivery route on sales order lines"),
|
||||
|
@ -63,7 +63,7 @@ class sale_configuration(osv.osv_memory):
|
|||
def default_get(self, cr, uid, fields, context=None):
|
||||
res = super(sale_configuration, self).default_get(cr, uid, fields, context)
|
||||
# task_work, time_unit depend on other fields
|
||||
res['task_work'] = res.get('module_project_mrp') and res.get('module_project_timesheet')
|
||||
res['task_work'] = res.get('module_sale_service') and res.get('module_project_timesheet')
|
||||
return res
|
||||
|
||||
def get_default_sale_config(self, cr, uid, ids, context=None):
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
</xpath>
|
||||
<group name='default_options' position="after">
|
||||
<field name="module_project_timesheet" invisible="1"/>
|
||||
<field name="module_project_mrp" invisible="1"/>
|
||||
<field name="module_sale_service" invisible="1"/>
|
||||
</group>
|
||||
<div name='warehouse_features' position='inside'>
|
||||
<div name='default_picking_policy' attrs="{'invisible':[('group_invoice_deli_orders','=',False)]}">
|
||||
|
|
|
@ -78,7 +78,7 @@ class procurement_rule(osv.osv):
|
|||
class procurement_order(osv.osv):
|
||||
_inherit = "procurement.order"
|
||||
_columns = {
|
||||
'location_id': fields.many2one('stock.location', 'Procurement Location'), # not required because task may create procurements that aren't linked to a location with project_mrp
|
||||
'location_id': fields.many2one('stock.location', 'Procurement Location'), # not required because task may create procurements that aren't linked to a location with sale_service
|
||||
'partner_dest_id': fields.many2one('res.partner', 'Customer Address', help="In case of dropshipping, we need to know the destination address more precisely"),
|
||||
'move_ids': fields.one2many('stock.move', 'procurement_id', 'Moves', help="Moves created by the procurement"),
|
||||
'move_dest_id': fields.many2one('stock.move', 'Destination Move', help="Move which caused (created) the procurement"),
|
||||
|
|
|
@ -472,13 +472,14 @@ ul.oe_menu_editor .disclose {
|
|||
right: 0;
|
||||
z-index: 1000;
|
||||
height: 100%;
|
||||
background: #2f3129;
|
||||
color: white;
|
||||
}
|
||||
.oe_ace_view_editor .oe_ace_view_editor_title {
|
||||
width: 100%;
|
||||
padding-top: 0;
|
||||
padding-left: 0;
|
||||
height: 30px;
|
||||
background: #2f3129;
|
||||
}
|
||||
.oe_ace_view_editor .oe_ace_view_editor_title .oe_view_list {
|
||||
width: 50%;
|
||||
|
@ -496,13 +497,16 @@ ul.oe_menu_editor .disclose {
|
|||
}
|
||||
.oe_ace_view_editor .ace_editor {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
.oe_ace_view_editor .ace_editor .ace_gutter {
|
||||
cursor: ew-resize;
|
||||
}
|
||||
.oe_ace_view_editor #ace-view-id {
|
||||
padding: 0 1em;
|
||||
}
|
||||
.oe_ace_view_editor.oe_ace_open {
|
||||
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=97);
|
||||
opacity: 0.97;
|
||||
|
|
|
@ -408,6 +408,7 @@ $highlighted_text_color: #ffffff
|
|||
/* ---- ACE EDITOR ---- {{{ */
|
||||
|
||||
$editorbar_height: 30px
|
||||
$infobar_height: 20px
|
||||
// TODO Fix => might break with themes
|
||||
|
||||
.oe_ace_view_editor
|
||||
|
@ -416,12 +417,13 @@ $editorbar_height: 30px
|
|||
right: 0
|
||||
z-index: 1000
|
||||
height: 100%
|
||||
background: #2F3129
|
||||
color: white
|
||||
.oe_ace_view_editor_title
|
||||
width: 100%
|
||||
padding-top: 0
|
||||
padding-left: 0
|
||||
height: $editorbar_height
|
||||
background: #2F3129
|
||||
.oe_view_list
|
||||
width: 50%
|
||||
height: $editorbar_height
|
||||
|
@ -432,12 +434,14 @@ $editorbar_height: 30px
|
|||
@include editor-font
|
||||
.ace_editor
|
||||
position: absolute
|
||||
top: $editorbar_height
|
||||
top: $editorbar_height + $infobar_height
|
||||
right: 0
|
||||
// bottom property is set programmatically
|
||||
left: 0
|
||||
.ace_gutter
|
||||
cursor: ew-resize
|
||||
#ace-view-id
|
||||
padding: 0 1em
|
||||
&.oe_ace_open
|
||||
+opacity(0.97)
|
||||
&.oe_ace_closed
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
(function () {
|
||||
'use strict';
|
||||
|
||||
var _t = openerp._t;
|
||||
var hash = "#advanced-view-editor";
|
||||
|
||||
var website = openerp.website;
|
||||
|
@ -65,12 +66,11 @@
|
|||
website.ace.ViewOption = openerp.Widget.extend({
|
||||
template: 'website.ace_view_option',
|
||||
init: function (parent, options) {
|
||||
var indent = "- ";
|
||||
this.view_id = options.id;
|
||||
this.view_name = options.name;
|
||||
for (var i = 0; i<options.level; i++) {
|
||||
this.view_name = indent + this.view_name;
|
||||
}
|
||||
|
||||
var indent = _.str.repeat("- ", options.level);
|
||||
this.view_name = _.str.sprintf("%s%s", indent, options.name);
|
||||
this._super(parent);
|
||||
},
|
||||
});
|
||||
|
@ -88,6 +88,7 @@
|
|||
},
|
||||
init: function (parent) {
|
||||
this.buffers = {};
|
||||
this.views = {};
|
||||
this._super(parent);
|
||||
},
|
||||
start: function () {
|
||||
|
@ -162,15 +163,14 @@
|
|||
resizeEditorHeight(this.getParent().get('height'));
|
||||
},
|
||||
loadViews: function (views) {
|
||||
var self = this;
|
||||
var $viewList = self.$('#ace-view-list');
|
||||
var views = this.buildViewGraph(views);
|
||||
_.each(views, function (view) {
|
||||
if (view.id) {
|
||||
new website.ace.ViewOption(self, view).appendTo($viewList);
|
||||
self.loadView(view.id);
|
||||
}
|
||||
});
|
||||
var $viewList = this.$('#ace-view-list');
|
||||
_(this.buildViewGraph(views)).each(function (view) {
|
||||
if (!view.id) { return; }
|
||||
|
||||
this.views[view.id] = view;
|
||||
new website.ace.ViewOption(this, view).appendTo($viewList);
|
||||
this.loadView(view.id);
|
||||
}.bind(this));
|
||||
},
|
||||
buildViewGraph: function (views) {
|
||||
var activeViews = _.uniq(_.filter(views, function (view) {
|
||||
|
@ -242,6 +242,9 @@
|
|||
var editingSession = this.buffers[viewId];
|
||||
if (editingSession) {
|
||||
this.aceEditor.setSession(editingSession);
|
||||
this.$('#ace-view-id').text(_.str.sprintf(
|
||||
_t("Template ID: %s"),
|
||||
this.views[viewId].xml_id));
|
||||
}
|
||||
},
|
||||
displaySelectedView: function () {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
var website = openerp.website;
|
||||
var _t = openerp._t;
|
||||
website.no_editor = !!$(document.documentElement).data('editable-no-editor');
|
||||
|
||||
website.add_template_file('/website/static/src/xml/website.editor.xml');
|
||||
website.dom_ready.done(function () {
|
||||
|
@ -496,6 +497,17 @@
|
|||
this.$('#website-top-edit').hide();
|
||||
this.$('#website-top-view').show();
|
||||
|
||||
var $edit_button = this.$('button[data-action=edit]')
|
||||
.prop('disabled', website.no_editor);
|
||||
if (website.no_editor) {
|
||||
var help_text = $(document.documentElement).data('editable-no-editor');
|
||||
$edit_button.parent()
|
||||
// help must be set on form above button because it does
|
||||
// not appear on disabled button
|
||||
.attr('title', help_text);
|
||||
}
|
||||
|
||||
|
||||
$('.dropdown-toggle').dropdown();
|
||||
this.customize_setup();
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<button data-action="format" type="button" class="btn btn-warning">Format</button>
|
||||
<button data-action="close" type="button" class="btn btn-info">Close</button>
|
||||
</div>
|
||||
<div id="ace-view-id"/>
|
||||
<div id="ace-view-editor"/>
|
||||
</div>
|
||||
</t>
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<form class="navbar-form navbar-left">
|
||||
<button type="button" data-action="edit" class="btn btn-primary hidden">Edit</button>
|
||||
<button type="button" data-action="edit"
|
||||
class="btn btn-primary hidden">Edit</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-edit-collapse">
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
<html t-att-lang="lang and lang.replace('_', '-')"
|
||||
t-att-data-website-id="website.id if editable else None"
|
||||
t-att-data-editable="'1' if editable else None"
|
||||
t-att-data-editable-no-editor="editable_no_editor or None"
|
||||
t-att-data-translatable="'1' if translatable else None"
|
||||
t-att-data-view-xmlid="xmlid if editable else None"
|
||||
t-att-data-main-object="repr(main_object) if editable else None"
|
||||
|
@ -179,8 +180,10 @@
|
|||
<xpath expr="//body" position="inside">
|
||||
<div id="website-top-navbar-placeholder" class="navbar navbar-inverse navbar-fixed-top hidden-xs">
|
||||
<div class="navbar-header">
|
||||
<form class="navbar-form navbar-left">
|
||||
<button type="button" class="btn btn-primary">Edit</button>
|
||||
<form class="navbar-form navbar-left" title="editable_no_editor or None">
|
||||
<button type="button" class="btn btn-primary"
|
||||
disabled="'disabled' if editable_no_editor else None"
|
||||
>Edit</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse navbar-edit-collapse">
|
||||
|
|
|
@ -257,8 +257,13 @@ class QWeb(orm.AbstractModel):
|
|||
uid = qwebcontext.get('request') and qwebcontext['request'].uid or None
|
||||
can_see = self.user_has_groups(cr, uid, groups=attribute_value) if cr and uid else False
|
||||
if not can_see:
|
||||
if qwebcontext.get('editable') and not qwebcontext.get('editable_no_editor'):
|
||||
errmsg = _("Editor disabled because some content can not be seen by a user who does not belong to the groups %s")
|
||||
raise openerp.http.Retry(
|
||||
_("User does not belong to groups %s") % attribute_value, {
|
||||
'editable_no_editor': errmsg % attribute_value
|
||||
})
|
||||
return ''
|
||||
continue
|
||||
|
||||
if isinstance(attribute_value, unicode):
|
||||
attribute_value = attribute_value.encode("utf8")
|
||||
|
@ -302,7 +307,7 @@ class QWeb(orm.AbstractModel):
|
|||
for current_node in element.childNodes:
|
||||
try:
|
||||
g_inner.append(self.render_node(current_node, qwebcontext))
|
||||
except QWebException:
|
||||
except (QWebException, openerp.http.Retry):
|
||||
raise
|
||||
except Exception:
|
||||
template = qwebcontext.get('__template__')
|
||||
|
|
|
@ -221,10 +221,10 @@ class res_config_installer(osv.osv_memory, res_config_module_installation_mixin)
|
|||
|
||||
_install_if = {
|
||||
('sale','crm'): ['sale_crm'],
|
||||
('sale','project'): ['project_mrp'],
|
||||
('sale','project'): ['sale_service'],
|
||||
}
|
||||
|
||||
will install both ``sale_crm`` and ``project_mrp`` if all of
|
||||
will install both ``sale_crm`` and ``sale_service`` if all of
|
||||
``sale``, ``crm`` and ``project`` are selected for installation.
|
||||
|
||||
Hook methods
|
||||
|
|
|
@ -1037,6 +1037,15 @@ mimetypes.add_type('application/font-woff', '.woff')
|
|||
mimetypes.add_type('application/vnd.ms-fontobject', '.eot')
|
||||
mimetypes.add_type('application/x-font-ttf', '.ttf')
|
||||
|
||||
class Retry(RuntimeError):
|
||||
""" Exception raised during QWeb rendering to signal that the rendering
|
||||
should be retried with the provided ``render_updates`` dict merged into
|
||||
the previous rendering context
|
||||
"""
|
||||
def __init__(self, name, render_updates=None):
|
||||
super(Retry, self).__init__(name)
|
||||
self.updates = render_updates or {}
|
||||
|
||||
class Response(werkzeug.wrappers.Response):
|
||||
""" Response object passed through controller route chain.
|
||||
|
||||
|
@ -1077,7 +1086,13 @@ class Response(werkzeug.wrappers.Response):
|
|||
def render(self):
|
||||
view_obj = request.registry["ir.ui.view"]
|
||||
uid = self.uid or request.uid or openerp.SUPERUSER_ID
|
||||
return view_obj.render(request.cr, uid, self.template, self.qcontext, context=request.context)
|
||||
while True:
|
||||
try:
|
||||
return view_obj.render(
|
||||
request.cr, uid, self.template, self.qcontext,
|
||||
context=request.context)
|
||||
except Retry, e:
|
||||
self.qcontext.update(e.updates)
|
||||
|
||||
def flatten(self):
|
||||
self.response.append(self.render())
|
||||
|
|
|
@ -1704,8 +1704,8 @@ class BaseModel(object):
|
|||
:return: True if the current user is a member of one of the
|
||||
given groups
|
||||
"""
|
||||
return any([self.pool.get('res.users').has_group(cr, uid, group_ext_id)
|
||||
for group_ext_id in groups.split(',')])
|
||||
return any(self.pool['res.users'].has_group(cr, uid, group_ext_id)
|
||||
for group_ext_id in groups.split(','))
|
||||
|
||||
def _get_default_form_view(self, cr, user, context=None):
|
||||
""" Generates a default single-line form view using all fields
|
||||
|
|
Loading…
Reference in New Issue