diff --git a/addons/portal_hr_employees/static/src/css/portal_hr_employees.css b/addons/portal_hr_employees/static/src/css/portal_hr_employees.css
index 351fd442f20..5fa658de8c1 100644
--- a/addons/portal_hr_employees/static/src/css/portal_hr_employees.css
+++ b/addons/portal_hr_employees/static/src/css/portal_hr_employees.css
@@ -12,3 +12,9 @@
width: 65px;
height: 65px;
}
+
+.openerp .oe_employee_vignette ul, .openerp .oe_employee_vignette li {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
diff --git a/addons/process/__openerp__.py b/addons/process/__openerp__.py
index ef554fe7226..f0ece3704dc 100644
--- a/addons/process/__openerp__.py
+++ b/addons/process/__openerp__.py
@@ -45,5 +45,15 @@ This module shows the basic processes involved in the selected modules and in th
'auto_install': False,
'certificate': '0055447636669',
'images': ['images/process_nodes.jpeg','images/process_transitions.jpeg', 'images/processes.jpeg'],
+ 'js': [
+ 'static/src/js/process.js'
+ ],
+ 'css': [
+ 'static/src/css/process.css'
+ ],
+ 'qweb': [
+ 'static/src/xml/*.xml'
+ ],
+ 'auto_install': True
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/process/process.py b/addons/process/process.py
index f9744608c50..fa7596287a3 100644
--- a/addons/process/process.py
+++ b/addons/process/process.py
@@ -195,8 +195,8 @@ class process_process(osv.osv):
if nodes[nid].get('directory_id', False):
resource['directory'] = self.pool.get('document.directory').get_resource_path(cr, uid, nodes[nid]['directory_id'], ref_model, ref_id)
- resource['name'] = refobj.name_get(context)[0][1]
- resource['perm'] = pool.get(ref_model).perm_read(cr, uid, [ref_id], context)[0]
+ resource['name'] = pool.get(ref_model).name_get(cr, uid, [ref_id], context=context)[0][1]
+ resource['perm'] = pool.get(ref_model).perm_read(cr, uid, [ref_id], context=context)[0]
for r in relatives:
node = nodes[r]
diff --git a/addons/process/static/src/css/process.css b/addons/process/static/src/css/process.css
new file mode 100644
index 00000000000..7442db9bc4a
--- /dev/null
+++ b/addons/process/static/src/css/process.css
@@ -0,0 +1,70 @@
+
+a.cta-a {
+ float: left;
+ padding: 5px 10px;
+ border: 1px solid #ccc;
+ border-radius: 5px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ background: #eeeded url(/process/static/src/img/cta-a.gif) repeat-x;
+ box-shadow: 0 1px 0 #fff;
+ -moz-box-shadow: 0 1px 0 #fff;
+ -webkit-box-shadow: 0 1px 0 #fff;
+ color: #8c8c8c;
+ font-size: 0.9em;
+ text-transform: uppercase;
+ font-weight: bold;
+ text-shadow: #fff 0 1px 0;
+ margin: 2px;
+}
+
+a.cta-a span {
+ float: left;
+ padding: 7px 0 5px 5px;
+ background-position: 0 50%;
+ background-repeat: no-repeat;
+ cursor: pointer;
+}
+
+a.cta-a strong {
+ display: block;
+ color: #393939;
+}
+.process-links {
+ padding: 5px 10px;
+ text-align: center;
+ display: table;
+ margin: auto;
+}
+.process-links a.cta-a {
+ display: table-cell;
+}
+.process_canvas{
+ border: 1px solid #aaa;
+ background-color:#FFF;
+}
+.process_canvas svg{
+ height:500px;!important;
+ padding:15px;
+}
+.oe_process {
+ height: 20px;
+ margin-top:3px;
+ padding: 0;
+ width: 24px;
+ cursor: pointer;
+ display: block;
+ background: url(/web/static/src/img/iconset-a-help.png) no-repeat center center;
+ float: left;
+}
+
+.process-help-text {
+ float: left;
+ padding:5px 10px;
+ min-height:56px;
+ font-size: 120%;
+}
+
+td.process_fields,button.toggle_fields span:last-child {
+ display: none;
+}
diff --git a/addons/process/static/src/img/button-a-a.png b/addons/process/static/src/img/button-a-a.png
new file mode 100644
index 00000000000..bd046bbbef7
Binary files /dev/null and b/addons/process/static/src/img/button-a-a.png differ
diff --git a/addons/process/static/src/img/cta-a.gif b/addons/process/static/src/img/cta-a.gif
new file mode 100644
index 00000000000..daa561e29f5
Binary files /dev/null and b/addons/process/static/src/img/cta-a.gif differ
diff --git a/addons/process/static/src/img/iconset-a-help.gif b/addons/process/static/src/img/iconset-a-help.gif
new file mode 100644
index 00000000000..5400acec57b
Binary files /dev/null and b/addons/process/static/src/img/iconset-a-help.gif differ
diff --git a/addons/process/static/src/img/node-current.png b/addons/process/static/src/img/node-current.png
new file mode 100644
index 00000000000..51f86b04c78
Binary files /dev/null and b/addons/process/static/src/img/node-current.png differ
diff --git a/addons/process/static/src/img/node-gray.png b/addons/process/static/src/img/node-gray.png
new file mode 100644
index 00000000000..972013540cf
Binary files /dev/null and b/addons/process/static/src/img/node-gray.png differ
diff --git a/addons/process/static/src/img/node-subflow-gray.png b/addons/process/static/src/img/node-subflow-gray.png
new file mode 100644
index 00000000000..ffafe1bd681
Binary files /dev/null and b/addons/process/static/src/img/node-subflow-gray.png differ
diff --git a/addons/process/static/src/img/node-subflow.png b/addons/process/static/src/img/node-subflow.png
new file mode 100644
index 00000000000..fd2a480204d
Binary files /dev/null and b/addons/process/static/src/img/node-subflow.png differ
diff --git a/addons/process/static/src/img/node.png b/addons/process/static/src/img/node.png
new file mode 100644
index 00000000000..853ac85cd56
Binary files /dev/null and b/addons/process/static/src/img/node.png differ
diff --git a/addons/process/static/src/js/process.js b/addons/process/static/src/js/process.js
new file mode 100644
index 00000000000..bbf9080de95
--- /dev/null
+++ b/addons/process/static/src/js/process.js
@@ -0,0 +1,249 @@
+openerp.process = function (instance) {
+var QWeb = instance.web.qweb,
+ _t = instance.web._t;
+instance.web.ViewManager.include({
+ start: function() {
+ var self = this;
+ var _super = this._super();
+ this.process_help = this.action ? this.action.help : '';
+ self.process_help = $(this.process_help).text();
+ if(this.action) {
+ this.process_model = this.action.res_model;
+ } else {
+ this.process_model = this.dataset.model;
+ }
+ this.$el.on('click', '.oe_process', function(ev) { self.initialize_process_view(ev);});
+ return _super;
+ },
+ initialize_process_view: function(ev) {
+ var self = this;
+ this.record_id = false;
+ if(this.active_view == 'form') {
+ this.record_id = this.views[this.active_view].controller.datarecord.id;
+ }
+ this.process_get_object().pipe(function(process) {
+ if(process && process.length) {
+ if(process.length > 1) {
+ self.process_selection = process;
+ } else {
+ self.process_id = process[0][0],
+ self.process_title = process[0][1];
+ }
+ }
+ return $.Deferred().resolve();
+ }).pipe(function() {
+ var def = $.Deferred();
+ if(self.process_id) {
+ $.when(self.process_graph_get()).done(function(res) {
+ self.process_notes = res.notes;
+ self.process_title = res.name;
+ self.process_subflows = _(res.nodes).chain()
+ .filter(function (node) { return node['subflow'] !== false; })
+ .uniq(false, function (node) { return node['subflow'][0]; }).value();
+ self.process_related = res.related;
+ def.resolve(res);
+ });
+ } else def.resolve();
+ return def.promise();
+ }).done(function(res) {
+ $.when(self.process_render_view()).done(function() {
+ if(res) {
+ self.process_draw_graph(res);
+ }
+ });
+ });
+ },
+ process_graph_get: function() {
+ var self = this;
+ var def = $.Deferred();
+ this.process_id = parseInt(this.process_id, 10);
+ this.process_dataset
+ .call("graph_get",[self.process_id, self.model || self.dataset.model, self.record_id, [80,80,150,100], self.session.user_context])
+ .done(function(res) {
+ self.process_dataset
+ .call("search_by_model",[self.model || self.dataset.model, self.session.user_context])
+ .done(
+ function(r) {
+ res['related'] = r;
+ def.resolve(res);
+ });
+ });
+ return def.promise();
+ },
+ process_get_object : function() {
+ var self = this,
+ def = $.Deferred();
+ if(this.process_id)
+ return def.resolve().promise();
+ this.process_dataset = new instance.web.DataSet(self, "process.process", self.session.user_context);
+ this.process_dataset
+ .call("search_by_model", [self.process_model,self.session.user_context])
+ .done(function(res) {
+ if (!res.length) {
+ self.process_model = false;
+ self.process_get_object().done(def.resolve);
+ }
+ else {
+ def.resolve(res);
+ }
+ })
+ .fail(def.reject);
+ return def.promise();
+ },
+ process_render_view : function() {
+ var self = this;
+ this.$el.html(QWeb.render("process.ProcessView", this));
+ this.$el.addClass('oe_view_process').css({'background-color':'#F0EEEE'});
+ this.$el.find('#edit_process').click(function() {
+ self.process_edit_view();
+ });
+ var $parent = this.getParent().$el;
+ $parent.find('#change_process').click(function() {
+ self.process_selection = false,
+ self.process_id = $parent.find('#select_process').val(),
+ self.process_title = $.trim($parent.find('#select_process option:selected').text());
+ self.initialize_process_view();
+ });
+ this.$el.find(".process_subflow").click(function() {
+ self.process_id = this.id;
+ self.initialize_process_view();
+ });
+ },
+ process_draw_graph : function(result) {
+ var self = this;
+ var res_nodes = result['nodes'];
+ var res_edges = result['transitions'];
+ var id_to_node = {};
+ var canvas = $('div.process_canvas').empty().get(0);
+ var style = {
+ edge_color: "#A0A0A0",
+ edge_label_font_size: 10,
+ edge_width: 2,
+ edge_spacing: 40,
+ edge_loop_radius: 200,
+
+ node_label_color: "#333",
+ node_label_font_size: 12,
+ node_outline_color: "#333",
+ node_outline_width: 1,
+ node_outline_color: "#F5F5F5",
+ node_outline_width: 0,
+ node_selected_width: 0,
+ node_size_x: 150,
+ node_size_y: 100,
+
+ gray: "#DCDCDC",
+ white: "#FFF",
+ viewport_margin: 50
+ };
+ var r = new Raphael(canvas,'100%','100%');
+ var graph = new CuteGraph(r,style,canvas.parentNode);
+ var render_process = function(r,nodes){
+ //For Image
+ var image_node = nodes.kind == "subflow" ? "node-subflow" : "node";
+ image_node = nodes.gray ? image_node + "-gray" : image_node;
+ image_node = nodes.active ? 'node-current': image_node;
+ var img_src = '/web_process/static/src/img/'+ image_node + '.png';
+ var image = r['image'](img_src, nodes.x-25, nodes.y,150, 100).attr({"cursor": "default"}) .mousedown(function() { return false; });
+ //For Node
+ var process_node = r['rect'](nodes.x, nodes.y, 150, 150).attr({stroke: "none"});
+ // Node text
+ if(nodes.name.length > 18){
+ var text = nodes.name.substr(0,16) + '...'
+ }
+ var node_text = r.text(nodes.x+60, nodes.y+10,(text || nodes.name.substr(0,18))).attr({"fill": "#fff","font-weight": "bold", "cursor": "default","title":nodes.name});
+ //Node Description
+ var new_notes = nodes.notes;
+ if(nodes.notes.length > 25) {
+ var to;
+ var temp_str = new_notes = '';
+ var from = to = 0;
+ while (1) {
+ from = 25;
+ temp_str = nodes.notes.substr(to, 25);
+ if (temp_str.lastIndexOf(" ") < 25 && temp_str.length >= 25) {
+ from = temp_str.lastIndexOf(" ");
+ }
+ new_notes += "\n" + nodes.notes.substr(to, from);
+ if (new_notes.length > 80){
+ break;
+ }
+ to += from;
+ }
+ }
+ if(nodes.res)
+ new_notes = nodes.res.name + '\n' + new_notes;
+ if(nodes.notes.length > 60){
+ var notes = new_notes.substring(0,60) +'..';
+ }
+ r.text(nodes.x+60, nodes.y+30, (notes || new_notes)).attr({"title":nodes.notes,"cursor": "default"});
+ if(nodes.menu) {
+ r['image']('/web/static/src/img/icons/gtk-jump-to.png', nodes.x+100, nodes.y+75, 16, 16)
+ .attr({"cursor": "pointer", "title": nodes.menu.name})
+ .click(function() {
+ self.process_jump_to_view(nodes.res_model, nodes.menu.id);
+ });
+ }
+ var process_set =r.set().push(process_node);
+ process_set.mousedown(function() {
+ return false;
+ });
+ return process_set;
+ }
+ _.each(res_nodes, function(node,id) {
+ node['res_model'] = self.model,
+ node['res_id'] = false,
+ node['color'] = 'gray'
+ var n = new CuteNode(
+ graph,
+ node.x + 50, //FIXME the +50 should be in the layout algorithm
+ node.y + 50,
+ CuteGraph.wordwrap("", 14));
+ n.id = id;
+ id_to_node[id] = n;
+ return render_process(r,node);
+ });
+ _.each(res_edges, function(edge) {
+ var e = new CuteEdge(
+ graph,
+ CuteGraph.wordwrap(" ",0),
+ id_to_node[edge.source],
+ id_to_node[edge.target] || id_to_node[edge.source]);
+ e.id = edge.id;
+ });
+ },
+ process_jump_to_view: function(model,id) {
+ var self = this;
+ var dataset = new instance.web.DataSet(this, 'ir.values', this.session.user_context);
+ var action_manager = new instance.web.ActionManager(self);
+ dataset.call('get',
+ ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
+ function(res) {
+ var action = res[0][res[0].length - 1];
+ self.rpc("/web/action/load", {
+ action_id: action.id,
+ context: dataset.context
+ }, function(result) {
+ action_manager.replace(self.$el);
+ action_manager.do_action(result.result);
+ })
+ });
+ },
+ process_edit_view: function() {
+ var self = this;
+ var pop = new instance.web.form.FormOpenPopup(self);
+ pop.show_element(
+ self.process_dataset.model,
+ self.process_id,
+ self.context || self.dataset.context,
+ {
+ title: _t('Process')
+ });
+ var form_controller = pop.view_form;
+ pop.on_write_completed.add_last(function() {
+ self.initialize_process_view();
+ });
+ }
+});
+};
+// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
diff --git a/addons/process/static/src/xml/process.xml b/addons/process/static/src/xml/process.xml
new file mode 100644
index 00000000000..b1a39aa6ce8
--- /dev/null
+++ b/addons/process/static/src/xml/process.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Process
+
+
+ Notes:
+
+
+ Last modified by: N/A
+
+
+ Subflows:
+
+
+
+
+
+
+
+
+
+
+
+ Related:
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select Process
+
+
+
+
+
+
+
+
+ Select
+
+
+
+
+
+
+
+
+
+
+ Edit Process
+
+
+
+
+
diff --git a/addons/product/product.py b/addons/product/product.py
index 16b08e67cee..c9345a22103 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -509,7 +509,7 @@ class product_product(osv.osv):
def _get_image(self, cr, uid, ids, name, args, context=None):
result = dict.fromkeys(ids, False)
for obj in self.browse(cr, uid, ids, context=context):
- result[obj.id] = tools.image_get_resized_images(obj.image)
+ result[obj.id] = tools.image_get_resized_images(obj.image, avoid_resize_medium=True)
return result
def _set_image(self, cr, uid, id, name, value, args, context=None):
@@ -548,25 +548,24 @@ class product_product(osv.osv):
'pricelist_id': fields.dummy(string='Pricelist', relation='product.pricelist', type='many2one'),
'name_template': fields.related('product_tmpl_id', 'name', string="Name", type='char', size=128, store=True, select=True),
'color': fields.integer('Color Index'),
+ # image: all image fields are base64 encoded and PIL-supported
'image': fields.binary("Image",
- help="This field holds the image used for the product. "\
- "The image is base64 encoded, and PIL-supported. "\
- "It is limited to a 1024x1024 px image."),
+ help="This field holds the image used as image for the product, limited to 1024x1024px."),
'image_medium': fields.function(_get_image, fnct_inv=_set_image,
string="Medium-sized image", type="binary", multi="_get_image",
- store = {
+ store={
'product.product': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
},
help="Medium-sized image of the product. It is automatically "\
- "resized as a 180x180 px image, with aspect ratio preserved. "\
- "Use this field in form views or some kanban views."),
+ "resized as a 128x128px image, with aspect ratio preserved, "\
+ "only when the image exceeds one of those sizes. Use this field in form views or some kanban views."),
'image_small': fields.function(_get_image, fnct_inv=_set_image,
string="Small-sized image", type="binary", multi="_get_image",
- store = {
+ store={
'product.product': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
},
help="Small-sized image of the product. It is automatically "\
- "resized as a 50x50 px image, with aspect ratio preserved. "\
+ "resized as a 64x64px image, with aspect ratio preserved. "\
"Use this field anywhere a small image is required."),
'seller_info_id': fields.function(_calc_seller, type='many2one', relation="product.supplierinfo", multi="seller_info"),
'seller_delay': fields.function(_calc_seller, type='integer', string='Supplier Lead Time', multi="seller_info", help="This is the average delay in days between the purchase order confirmation and the reception of goods for this product and for the default supplier. It is used by the scheduler to order requests based on reordering delays."),
diff --git a/addons/project/board_project_view.xml b/addons/project/board_project_view.xml
index 2023ba5a0b9..931c661d211 100644
--- a/addons/project/board_project_view.xml
+++ b/addons/project/board_project_view.xml
@@ -16,7 +16,7 @@
-
+
diff --git a/addons/project/project.py b/addons/project/project.py
index 241e3a24dc5..9bd939dd4fe 100644
--- a/addons/project/project.py
+++ b/addons/project/project.py
@@ -582,13 +582,17 @@ class task(base_stage, osv.osv):
search_domain = []
project_id = self._resolve_project_id_from_context(cr, uid, context=context)
if project_id:
- search_domain += ['|', '&', ('project_ids', '=', project_id), ('fold', '=', False)]
- search_domain += ['|', ('id', 'in', ids), '&', ('case_default', '=', True), ('fold', '=', False)]
+ search_domain += ['|', ('project_ids', '=', project_id)]
+ search_domain += ['|', ('id', 'in', ids), ('case_default', '=', True)]
stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context)
result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context)
# restore order of the search
result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0])))
- return result
+
+ fold = {}
+ for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context):
+ fold[stage.id] = stage.fold or False
+ return result, fold
def _read_group_user_id(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None):
res_users = self.pool.get('res.users')
@@ -605,7 +609,7 @@ class task(base_stage, osv.osv):
result = res_users.name_get(cr, access_rights_uid, ids, context=context)
# restore order of the search
result.sort(lambda x,y: cmp(ids.index(x[0]), ids.index(y[0])))
- return result
+ return result, {}
_group_by_full = {
'stage_id': _read_group_stage_ids,
@@ -715,7 +719,7 @@ class task(base_stage, osv.osv):
'priority': fields.selection([('4','Very Low'), ('3','Low'), ('2','Medium'), ('1','Important'), ('0','Very important')], 'Priority', select=True),
'sequence': fields.integer('Sequence', select=True, help="Gives the sequence order when displaying a list of tasks."),
'stage_id': fields.many2one('project.task.type', 'Stage',
- domain="['|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
+ domain="['&', ('fold', '=', False), '|', ('project_ids', '=', project_id), ('case_default', '=', True)]"),
'state': fields.related('stage_id', 'state', type="selection", store=True,
selection=_TASK_STATE, string="State", readonly=True,
help='The state is set to \'Draft\', when a case is created.\
diff --git a/addons/project/project_view.xml b/addons/project/project_view.xml
index d359cdbf458..a4ba5a233a1 100644
--- a/addons/project/project_view.xml
+++ b/addons/project/project_view.xml
@@ -232,7 +232,7 @@
-