2011-04-07 12:13:31 +00:00
|
|
|
/*---------------------------------------------------------
|
2011-09-05 12:28:15 +00:00
|
|
|
* OpenERP web_gantt
|
2011-04-07 12:13:31 +00:00
|
|
|
*---------------------------------------------------------*/
|
2011-09-05 12:28:15 +00:00
|
|
|
openerp.web_gantt = function (openerp) {
|
2011-11-03 10:51:41 +00:00
|
|
|
var _t = openerp.web._t;
|
2011-09-07 09:37:43 +00:00
|
|
|
var QWeb = openerp.web.qweb;
|
2011-09-05 12:28:15 +00:00
|
|
|
openerp.web.views.add('gantt', 'openerp.web_gantt.GanttView');
|
|
|
|
openerp.web_gantt.GanttView = openerp.web.View.extend({
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-09-15 09:49:44 +00:00
|
|
|
init: function(parent, dataset, view_id) {
|
|
|
|
this._super(parent);
|
2011-09-05 12:28:15 +00:00
|
|
|
this.view_manager = parent || new openerp.web.NullViewManager();
|
2011-04-07 12:13:31 +00:00
|
|
|
this.dataset = dataset;
|
|
|
|
this.model = dataset.model;
|
|
|
|
this.view_id = view_id;
|
2011-11-03 10:51:41 +00:00
|
|
|
this.domain = this.dataset.domain || [];
|
2011-08-02 05:52:16 +00:00
|
|
|
this.context = this.dataset.context || {};
|
2011-11-03 10:51:41 +00:00
|
|
|
this.has_been_loaded = $.Deferred();
|
2011-04-07 12:13:31 +00:00
|
|
|
},
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-04-07 12:13:31 +00:00
|
|
|
start: function() {
|
2011-09-15 09:42:46 +00:00
|
|
|
this._super();
|
2011-11-03 10:51:41 +00:00
|
|
|
return this.rpc("/web/view/load", {"model": this.model, "view_id": this.view_id, "view_type": "gantt"}, this.on_loaded);
|
2011-04-07 12:13:31 +00:00
|
|
|
},
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-04-07 12:13:31 +00:00
|
|
|
on_loaded: function(data) {
|
2011-11-03 10:51:41 +00:00
|
|
|
this.fields_view = data,
|
|
|
|
this.name = this.fields_view.arch.attrs.string,
|
|
|
|
this.view_id = this.fields_view.view_id,
|
|
|
|
this.fields = this.fields_view.fields;
|
|
|
|
|
|
|
|
this.date_start = this.fields_view.arch.attrs.date_start,
|
|
|
|
this.date_delay = this.fields_view.arch.attrs.date_delay,
|
|
|
|
this.date_stop = this.fields_view.arch.attrs.date_stop,
|
2011-04-07 12:13:31 +00:00
|
|
|
this.day_length = this.fields_view.arch.attrs.day_length || 8;
|
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
this.color_field = this.fields_view.arch.attrs.color,
|
|
|
|
this.colors = this.fields_view.arch.attrs.colors;
|
|
|
|
|
|
|
|
var level = this.fields_view.arch.children[0];
|
|
|
|
this.parent = level.attrs.link,
|
|
|
|
this.text = level.children.length ? level.children[0].attrs.name : level.attrs.name;
|
|
|
|
|
2011-11-03 12:02:52 +00:00
|
|
|
if (!this.date_start) {
|
|
|
|
return self.do_warn(_t("date_start is not defined "))
|
|
|
|
}
|
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
this.$element.html(QWeb.render("GanttView", {'height': $('.oe-application-container').height(), 'width': $('.oe-application-container').width()}));
|
|
|
|
this.has_been_loaded.resolve();
|
|
|
|
},
|
|
|
|
|
|
|
|
on_project_loaded: function(projects) {
|
|
|
|
|
|
|
|
if(!projects.length) return;
|
|
|
|
var self = this,
|
2011-11-03 12:02:52 +00:00
|
|
|
started_projects = _.filter(projects, function(res) {
|
|
|
|
return res[self.date_start];
|
2011-11-03 10:51:41 +00:00
|
|
|
});
|
|
|
|
|
2011-11-04 13:02:08 +00:00
|
|
|
this.database_projects = started_projects;
|
2011-11-08 07:35:28 +00:00
|
|
|
if(!started_projects.length)
|
|
|
|
return self.do_warn(_t("date_start is not defined"));
|
|
|
|
|
2011-11-08 07:14:15 +00:00
|
|
|
if(!self.name && started_projects.length) {
|
2011-11-03 13:15:51 +00:00
|
|
|
var name = started_projects[0][self.parent];
|
|
|
|
self.name = name instanceof Array? name[name.length - 1] : name;
|
|
|
|
}
|
2011-11-16 13:38:44 +00:00
|
|
|
this.$element.find('#add_task').click(function(){
|
|
|
|
self.editTask();
|
|
|
|
});
|
2011-11-04 13:02:08 +00:00
|
|
|
$.when(this.project_starting_date(), this.get_project_duration(), this.calculate_difference())
|
2011-11-03 13:15:51 +00:00
|
|
|
.then(function() {
|
2011-11-03 12:26:35 +00:00
|
|
|
if(self.ganttChartControl) {
|
|
|
|
self.ganttChartControl.clearAll();
|
|
|
|
self.$element.find('#GanttView').empty();
|
|
|
|
}
|
2011-11-03 13:15:51 +00:00
|
|
|
})
|
2011-11-04 13:02:08 +00:00
|
|
|
.then(this.group_projects())
|
|
|
|
.then(this.generate_projects())
|
|
|
|
.then(this.add_tasks())
|
|
|
|
.done(this.init_gantt_view());
|
2011-11-03 13:15:51 +00:00
|
|
|
},
|
|
|
|
|
2011-11-08 07:14:15 +00:00
|
|
|
group_projects: function() {
|
|
|
|
var def = $.Deferred(),
|
|
|
|
self = this,
|
|
|
|
projects = this.database_projects;
|
|
|
|
|
2011-11-16 13:38:44 +00:00
|
|
|
if (!this.group_by.length) return def.resolve().promise();
|
2011-11-21 09:15:12 +00:00
|
|
|
this.data_groups = _.groupBy(projects, function(project) {
|
|
|
|
return _.map(self.group_by, function(group) {
|
2011-11-16 13:38:44 +00:00
|
|
|
if(!project[group]) project[group] = 'Undefined';
|
|
|
|
else if(project[group] instanceof Array) project[group] = project[group][1];
|
|
|
|
return project[group];
|
2011-11-08 07:14:15 +00:00
|
|
|
});
|
2011-11-16 13:38:44 +00:00
|
|
|
});
|
2011-11-21 09:15:12 +00:00
|
|
|
|
|
|
|
this.group_keys = _.map(this.group_by, function(group, index) {
|
|
|
|
return _.map(projects, function(project){return project[group]});
|
|
|
|
});
|
2011-11-08 07:14:15 +00:00
|
|
|
return def.resolve().promise();
|
|
|
|
},
|
2011-11-04 13:02:08 +00:00
|
|
|
generate_projects : function() {
|
|
|
|
var projects = this.database_projects,
|
2011-11-03 13:15:51 +00:00
|
|
|
self = this;
|
2011-11-04 13:02:08 +00:00
|
|
|
|
|
|
|
this.GanttTasks = [];
|
2011-11-05 04:42:51 +00:00
|
|
|
if(this.group_by.length) {
|
2011-11-21 09:15:12 +00:00
|
|
|
|
2011-11-04 13:02:08 +00:00
|
|
|
} else {
|
|
|
|
this.GanttTasks.push(new GanttTaskInfo(0, self.name, self.project_start_date, self.total_duration, 100, ""));
|
|
|
|
}
|
2011-11-05 04:42:51 +00:00
|
|
|
this.GanttProjects = new GanttProjectInfo(0, self.name, self.project_start_date);
|
2011-11-04 13:02:08 +00:00
|
|
|
return $.Deferred().resolve().promise();
|
|
|
|
},
|
|
|
|
|
2011-11-08 07:14:15 +00:00
|
|
|
add_tasks: function() {
|
|
|
|
var self = this,
|
|
|
|
tasks = this.database_projects;
|
|
|
|
if (this.group_by.length) {
|
2011-11-16 13:38:44 +00:00
|
|
|
|
2011-11-08 07:14:15 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
_.each(tasks, function(task, index){
|
|
|
|
var name = task[self.text];
|
|
|
|
if (task[self.text] instanceof Array) {
|
|
|
|
name = task[self.text][1];
|
|
|
|
}
|
|
|
|
self.GanttTasks[0].addChildTask(new GanttTaskInfo(task.id, name, self.format_date(task[self.date_start]), self.project_duration[index], 100, ""));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return $.Deferred().resolve().promise();
|
2011-11-03 10:51:41 +00:00
|
|
|
},
|
|
|
|
|
2011-11-04 13:02:08 +00:00
|
|
|
get_project_duration: function() {
|
2011-11-03 10:51:41 +00:00
|
|
|
|
2011-11-04 13:02:08 +00:00
|
|
|
var self = this,
|
|
|
|
projects = this.database_projects;
|
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
this.project_duration = [];
|
|
|
|
|
|
|
|
_.each(projects, function(project, index) {
|
2011-11-03 12:26:35 +00:00
|
|
|
if (self.date_stop && project[self.date_stop]) {
|
2011-11-08 07:35:28 +00:00
|
|
|
self.project_duration.push(self.duration_difference(project[self.date_start], project[self.date_stop]));
|
2011-11-03 10:51:41 +00:00
|
|
|
} else if(self.date_delay && project[self.date_delay]) {
|
|
|
|
self.project_duration.push(project[self.date_delay]);
|
|
|
|
} else {
|
|
|
|
self.project_duration.push(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.max_project_duration = _.max(this.project_duration);
|
|
|
|
return $.Deferred().resolve().promise();
|
|
|
|
},
|
|
|
|
|
2011-11-08 07:35:28 +00:00
|
|
|
duration_difference: function(start_date, end_date) {
|
|
|
|
|
|
|
|
var DAY = 1000 * 60 * 60 * 24,
|
|
|
|
date1_ms = openerp.web.auto_str_to_date(start_date).getTime(),
|
|
|
|
date2_ms = openerp.web.auto_str_to_date(end_date).getTime(),
|
|
|
|
difference_ms = Math.abs(date1_ms - date2_ms);
|
|
|
|
|
|
|
|
var d = Math.floor(difference_ms / DAY),
|
|
|
|
h = (difference_ms % DAY)/(1000 * 60 * 60),
|
|
|
|
num = (d * this.day_length) + h;
|
|
|
|
return parseFloat(num.toFixed(2));
|
|
|
|
|
|
|
|
},
|
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
calculate_difference: function() {
|
|
|
|
var extend_end_date_day = Math.floor(this.max_project_duration / this.day_length),
|
|
|
|
extend_end_date_hours = this.max_project_duration % this.day_length;
|
|
|
|
|
|
|
|
this.project_end_date = this.project_end_date.add({days: extend_end_date_day, hours: extend_end_date_hours})
|
|
|
|
|
|
|
|
var DAY = 1000 * 60 * 60 * 24,
|
|
|
|
difference = Math.abs(this.project_start_date.getTime() - this.project_end_date.getTime()),
|
|
|
|
day = Math.ceil(difference / DAY),
|
|
|
|
hour = (difference % DAY)/(1000 * 60 * 60),
|
|
|
|
DiffHour = (day * this.day_length) + hour;
|
|
|
|
|
|
|
|
this.total_duration = parseFloat(DiffHour.toFixed(2));
|
|
|
|
return $.Deferred().resolve().promise();
|
|
|
|
},
|
|
|
|
|
2011-11-04 13:02:08 +00:00
|
|
|
project_starting_date : function() {
|
|
|
|
var self = this,
|
|
|
|
projects = this.database_projects,
|
|
|
|
min_date = _.min(projects, function(prj) {
|
|
|
|
return new Date(prj[self.date_start]);
|
|
|
|
}),
|
|
|
|
max_date = _.max(projects, function(prj) {
|
|
|
|
return self.format_date(prj[self.date_start]);
|
|
|
|
});
|
2011-11-03 10:51:41 +00:00
|
|
|
this.project_end_date = this.format_date(max_date[self.date_start]);
|
|
|
|
if (min_date) this.project_start_date = this.format_date(min_date[self.date_start]);
|
|
|
|
else
|
|
|
|
this.project_start_date = Date.today();
|
|
|
|
return $.Deferred().resolve().promise();
|
2011-04-07 12:13:31 +00:00
|
|
|
},
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-11-04 13:02:08 +00:00
|
|
|
init_gantt_view: function() {
|
2011-11-03 12:26:35 +00:00
|
|
|
var self = this;
|
|
|
|
|
2011-11-05 04:42:51 +00:00
|
|
|
if (this.group_by.length) {
|
|
|
|
}
|
|
|
|
else {
|
2011-11-21 09:15:12 +00:00
|
|
|
_.each(this.GanttTasks, function(tsk, index) {
|
2011-11-05 04:42:51 +00:00
|
|
|
self.GanttProjects.addTask(tsk);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2011-11-03 12:26:35 +00:00
|
|
|
var ganttChartControl = this.ganttChartControl = new GanttChart();
|
2011-04-15 09:32:53 +00:00
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
// Setup paths and behavior
|
2011-09-05 13:44:57 +00:00
|
|
|
ganttChartControl.setImagePath("/web_gantt/static/lib/dhtmlxGantt/codebase/imgs/");
|
2011-04-28 11:57:03 +00:00
|
|
|
ganttChartControl.setEditable(true);
|
|
|
|
ganttChartControl.showTreePanel(true);
|
2011-10-24 10:10:15 +00:00
|
|
|
ganttChartControl.showContextMenu(false);
|
2011-04-28 11:57:03 +00:00
|
|
|
ganttChartControl.showDescTask(true,'d,s-f');
|
|
|
|
ganttChartControl.showDescProject(true,'n,d');
|
2011-11-04 13:02:08 +00:00
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
// Load data structure
|
2011-11-05 04:42:51 +00:00
|
|
|
ganttChartControl.addProject(this.GanttProjects);
|
|
|
|
|
2011-11-03 10:51:41 +00:00
|
|
|
// Create Gantt control
|
2011-11-04 13:02:08 +00:00
|
|
|
ganttChartControl.create('GanttView');
|
2011-11-03 12:02:52 +00:00
|
|
|
|
|
|
|
// Setup Events
|
|
|
|
ganttChartControl.attachEvent("onTaskStartDrag", function(task) {
|
2011-11-08 09:00:08 +00:00
|
|
|
if (task.parentTask) {
|
|
|
|
var task_date = task.getEST();
|
|
|
|
if (task_date.getHours()) {
|
|
|
|
task_date.set({
|
|
|
|
hour: task_date.getHours(),
|
|
|
|
minute: task_date.getMinutes(),
|
|
|
|
second: 0
|
|
|
|
});
|
|
|
|
}
|
2011-11-03 12:02:52 +00:00
|
|
|
}
|
|
|
|
});
|
2011-11-08 09:00:08 +00:00
|
|
|
|
2011-11-03 12:02:52 +00:00
|
|
|
ganttChartControl.attachEvent("onTaskEndResize", function(task) {return self.ResizeTask(task);});
|
|
|
|
ganttChartControl.attachEvent("onTaskEndDrag", function(task) {return self.ResizeTask(task);});
|
2011-11-03 10:51:41 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
format_date : function(date) {
|
|
|
|
var datetime_regex = /^(\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)(?:\.\d+)?$/,
|
|
|
|
date_regex = /^\d\d\d\d-\d\d-\d\d$/,
|
|
|
|
time_regex = /^(\d\d:\d\d:\d\d)(?:\.\d+)?$/,
|
|
|
|
def = $.Deferred();
|
|
|
|
if(date_regex.exec(date)) {
|
|
|
|
this.date_format = "yyyy-MM-dd";
|
|
|
|
} else if(time_regex.exec(date)) {
|
|
|
|
this.date_format = "HH:mm:ss";
|
|
|
|
} else {
|
|
|
|
this.date_format = "yyyy-MM-dd HH:mm:ss";
|
|
|
|
}
|
|
|
|
return openerp.web.auto_str_to_date(date);
|
2011-04-15 09:32:53 +00:00
|
|
|
},
|
2011-11-03 12:02:52 +00:00
|
|
|
|
|
|
|
ResizeTask: function(task) {
|
2011-11-08 09:00:08 +00:00
|
|
|
var self = this,
|
|
|
|
event_id = task.getId();
|
2011-11-03 12:02:52 +00:00
|
|
|
|
2011-11-08 09:00:08 +00:00
|
|
|
if(!event_id || !task.parentTask)
|
2011-11-03 12:02:52 +00:00
|
|
|
return this.do_warn(_t("Project can not be resized"));
|
|
|
|
|
|
|
|
var data = {};
|
|
|
|
data[this.date_start] = task.getEST().toString(this.date_format);
|
|
|
|
|
|
|
|
if(this.date_stop) {
|
|
|
|
var diff = task.getDuration() % this.day_length,
|
|
|
|
finished_date = task.getFinishDate().add({hours: diff});
|
|
|
|
data[this.date_stop] = finished_date.toString(this.date_format);
|
|
|
|
} else {
|
|
|
|
data[this.date_delay] = task.getDuration();
|
2011-08-10 08:45:28 +00:00
|
|
|
}
|
2011-11-03 12:02:52 +00:00
|
|
|
this.dataset
|
|
|
|
.write(event_id, data, {})
|
|
|
|
.done(function() {
|
2011-11-21 09:15:12 +00:00
|
|
|
var get_project = _.find(self.database_projects, function(project){ return project.id == event_id});
|
|
|
|
_.extend(get_project,data);
|
2011-11-03 12:02:52 +00:00
|
|
|
self.reloadView();
|
|
|
|
});
|
2011-08-10 08:45:28 +00:00
|
|
|
},
|
2011-11-03 12:02:52 +00:00
|
|
|
|
|
|
|
editTask: function(task) {
|
2011-11-16 13:38:44 +00:00
|
|
|
var self = this,
|
|
|
|
event_id;
|
|
|
|
if (!task)
|
|
|
|
event_id = null;
|
|
|
|
else {
|
|
|
|
event_id = task.getId();
|
|
|
|
if(!event_id || !task.parentTask)
|
|
|
|
return false;
|
|
|
|
}
|
2011-07-18 06:17:22 +00:00
|
|
|
if(event_id) event_id = parseInt(event_id, 10);
|
2011-09-23 06:52:51 +00:00
|
|
|
var action_manager = new openerp.web.ActionManager(this);
|
|
|
|
|
|
|
|
var dialog = new openerp.web.Dialog(this, {
|
|
|
|
width: 800,
|
|
|
|
height: 600,
|
|
|
|
buttons : {
|
|
|
|
Cancel : function() {
|
|
|
|
$(this).dialog('destroy');
|
|
|
|
},
|
|
|
|
Save : function() {
|
|
|
|
var form_view = action_manager.inner_viewmanager.views.form.controller;
|
|
|
|
|
|
|
|
form_view.do_save(function() {
|
2011-11-03 12:02:52 +00:00
|
|
|
self.reloadView();
|
2011-09-23 06:52:51 +00:00
|
|
|
});
|
|
|
|
$(this).dialog('destroy');
|
2011-07-18 06:17:22 +00:00
|
|
|
}
|
2011-09-23 06:52:51 +00:00
|
|
|
}
|
|
|
|
}).start().open();
|
|
|
|
action_manager.appendTo(dialog.$element);
|
|
|
|
action_manager.do_action({
|
|
|
|
res_model : this.dataset.model,
|
|
|
|
res_id: event_id,
|
|
|
|
views : [[false, 'form']],
|
|
|
|
type : 'ir.actions.act_window',
|
|
|
|
auto_search : false,
|
|
|
|
flags : {
|
|
|
|
search_view: false,
|
|
|
|
sidebar : false,
|
|
|
|
views_switcher : false,
|
|
|
|
action_buttons : false,
|
|
|
|
pager: false
|
|
|
|
}
|
2011-07-18 06:17:22 +00:00
|
|
|
});
|
2011-05-02 06:32:56 +00:00
|
|
|
},
|
2011-11-03 12:02:52 +00:00
|
|
|
|
|
|
|
reloadView: function() {
|
2011-11-16 13:38:44 +00:00
|
|
|
this.on_project_loaded(this.database_projects);
|
2011-04-15 09:32:53 +00:00
|
|
|
},
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-04-15 09:32:53 +00:00
|
|
|
do_show: function () {
|
2011-04-28 11:57:03 +00:00
|
|
|
this.$element.show();
|
2011-04-15 09:32:53 +00:00
|
|
|
},
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-04-15 09:32:53 +00:00
|
|
|
do_hide: function () {
|
|
|
|
this.$element.hide();
|
|
|
|
},
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-04-15 09:32:53 +00:00
|
|
|
do_search: function (domains, contexts, groupbys) {
|
|
|
|
var self = this;
|
2011-11-03 10:51:41 +00:00
|
|
|
this.group_by = groupbys;
|
|
|
|
$.when(this.has_been_loaded).then(function() {
|
2011-11-16 13:38:44 +00:00
|
|
|
self.dataset.read_slice([], {
|
2011-11-03 10:51:41 +00:00
|
|
|
domain: domains,
|
2011-11-08 07:35:28 +00:00
|
|
|
context: contexts
|
2011-11-16 13:38:44 +00:00
|
|
|
}).done(function(projects){
|
2011-11-03 10:51:41 +00:00
|
|
|
self.on_project_loaded(projects);
|
|
|
|
});
|
2011-11-21 09:15:12 +00:00
|
|
|
});
|
2011-04-13 14:20:01 +00:00
|
|
|
}
|
2011-04-28 11:57:03 +00:00
|
|
|
|
2011-04-07 12:13:31 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
// here you may tweak globals object, if any, and play with on_* or do_* callbacks on them
|
|
|
|
|
|
|
|
};
|
|
|
|
// vim:et fdc=0 fdl=0:
|