[MERGE] Calendar WIP
bzr revid: fme@openerp.com-20110801124802-hpcbkhpxxc0cu60j
This commit is contained in:
commit
595966fb22
|
@ -1,56 +1,14 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
"name" : "Basic Calendar Functionality",
|
||||
"version" : "1.0",
|
||||
"depends" : ["base"],
|
||||
'complexity': "easy",
|
||||
'description': """
|
||||
This is a full-featured calendar system.
|
||||
========================================
|
||||
|
||||
It supports:
|
||||
- Calendar of events
|
||||
- Alerts (create requests)
|
||||
- Recurring events
|
||||
- Invitations to people""",
|
||||
"author" : "OpenERP SA",
|
||||
'category': 'Tools',
|
||||
'website': 'http://www.openerp.com',
|
||||
"init_xml" : [
|
||||
'base_calendar_data.xml'
|
||||
"name": "Base calendar",
|
||||
"version": "2.0",
|
||||
"depends": ['base'],
|
||||
"js": [
|
||||
'static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.js',
|
||||
'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js',
|
||||
'static/src/js/calendar.js'
|
||||
],
|
||||
"demo_xml" : [],
|
||||
"update_xml" : [
|
||||
'security/calendar_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/base_calendar_invite_attendee_view.xml',
|
||||
'base_calendar_view.xml'
|
||||
],
|
||||
"test" : ['test/base_calendar_test.yml'],
|
||||
"installable" : True,
|
||||
"active" : False,
|
||||
"certificate" : "00694071962960352821",
|
||||
'images': ['images/base_calendar1.jpeg','images/base_calendar2.jpeg','images/base_calendar3.jpeg','images/base_calendar4.jpeg',],
|
||||
"css": ['static/lib/dhtmlxScheduler/codebase/dhtmlxscheduler.css',
|
||||
'static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_ext.css'
|
||||
],
|
||||
'active': True
|
||||
}
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -1,356 +1,10 @@
|
|||
from base.controllers.main import View
|
||||
import openerpweb, time, math, re, datetime as DT, pytz
|
||||
|
||||
COLOR_PALETTE = ['#f57900', '#cc0000', '#d400a8', '#75507b', '#3465a4', '#73d216', '#c17d11', '#edd400',
|
||||
'#fcaf3e', '#ef2929', '#ff00c9', '#ad7fa8', '#729fcf', '#8ae234', '#e9b96e', '#fce94f',
|
||||
'#ff8e00', '#ff0000', '#b0008c', '#9000ff', '#0078ff', '#00ff00', '#e6ff00', '#ffff00',
|
||||
'#905000', '#9b0000', '#840067', '#510090', '#0000c9', '#009b00', '#9abe00', '#ffc900', ]
|
||||
|
||||
_colorline = ['#%02x%02x%02x' % (25 + ((r + 10) % 11) * 23, 5 + ((g + 1) % 11) * 20, 25 + ((b + 4) % 11) * 23) for r in range(11) for g in range(11) for b in range(11) ]
|
||||
|
||||
DT_SERVER_FORMATS = {
|
||||
'datetime' : '%Y-%m-%d %H:%M:%S',
|
||||
'date' : '%Y-%m-%d',
|
||||
'time' : '%H:%M:%S'
|
||||
}
|
||||
|
||||
DT_FORMAT_INFO = {'datetime' : ('%Y-%m-%d %H:%M:%S', DT.datetime, 0, 6),
|
||||
'date': ('%Y-%m-%d', DT.date, 0, 3),
|
||||
'time': ('%H:%M:%S', DT.time, 3, 6)}
|
||||
|
||||
def choice_colors(n):
|
||||
if n > len(COLOR_PALETTE):
|
||||
return _colorline[0:-1:len(_colorline) / (n + 1)]
|
||||
elif n:
|
||||
return COLOR_PALETTE[:n]
|
||||
return []
|
||||
import openerpweb
|
||||
|
||||
class CalendarView(View):
|
||||
_cp_path = "/base_calendar/calendarview"
|
||||
|
||||
mode = 'month'
|
||||
date_start = None
|
||||
date_delay = None
|
||||
date_stop = None
|
||||
color_field = None
|
||||
day_length = 8
|
||||
use_search = False
|
||||
selected_day = None
|
||||
date_format = '%Y-%m-%d'
|
||||
info_fields = []
|
||||
fields = {}
|
||||
events = []
|
||||
|
||||
colors = {}
|
||||
color_values = []
|
||||
|
||||
remote_timezone = 'utc'
|
||||
client_timezone = False
|
||||
|
||||
calendar_fields = {}
|
||||
concurrency_info = None
|
||||
|
||||
ids = []
|
||||
model = ''
|
||||
domain = []
|
||||
context = {}
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def load(self, req, model, view_id):
|
||||
fields_view = self.fields_view_get(req, model, view_id, 'calendar')
|
||||
return {'fields_view':fields_view}
|
||||
|
||||
def convert(self, event):
|
||||
fields = [self.date_start]
|
||||
if self.date_stop:
|
||||
fields.append(self.date_stop)
|
||||
|
||||
for fld in fields:
|
||||
fld_type = self.fields[fld]['type']
|
||||
fmt = DT_SERVER_FORMATS[fld_type]
|
||||
if event[fld] and fmt:
|
||||
event[fld] = time.strptime(event[fld], fmt)
|
||||
|
||||
# default start/stop time is 9:00 AM / 5:00 PM
|
||||
if fld_type == 'date' and event[fld]:
|
||||
ds = list(event[fld])
|
||||
if fld == self.date_start:
|
||||
ds[3] = 9
|
||||
elif fld == self.date_stop:
|
||||
ds[3] = 17
|
||||
event[fld] = tuple(ds)
|
||||
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def schedule_events(self, req, **kw):
|
||||
self.model = kw['model']
|
||||
self.mode = kw.get('mode') or self.mode or 'month'
|
||||
self.fields = kw['fields']
|
||||
self.color_field = kw.get('color_field') or self.color_field or None
|
||||
self.colors = kw.get('colors') or {}
|
||||
self.calendar_fields = kw['calendar_fields']
|
||||
self.info_fields = kw['info_fields']
|
||||
self.date_start = self.calendar_fields['date_start']['name']
|
||||
self.domain = kw.get('domain') or []
|
||||
|
||||
self.remote_timezone = req.session.remote_timezone
|
||||
self.client_timezone = req.session.client_timezone
|
||||
|
||||
if self.calendar_fields.get('date_stop'):
|
||||
self.date_stop = self.calendar_fields['date_stop']['name']
|
||||
|
||||
if self.calendar_fields.get('date_delay'):
|
||||
self.date_delay = self.calendar_fields['date_delay']['name']
|
||||
|
||||
model = req.session.model(self.model)
|
||||
event_ids = model.search(self.domain)
|
||||
|
||||
self.events = model.read(event_ids, self.fields.keys())
|
||||
result = []
|
||||
self.date_format = req.session._lang and req.session._lang['date_format']
|
||||
|
||||
if self.color_field:
|
||||
for evt in self.events:
|
||||
key = evt[self.color_field]
|
||||
name = key
|
||||
value = key
|
||||
if isinstance(key, list): # M2O, XMLRPC returns List instead of Tuple
|
||||
name = key[0]
|
||||
value = key[-1]
|
||||
evt[self.color_field] = key = key[-1]
|
||||
if isinstance(key, tuple): # M2O
|
||||
value, name = key
|
||||
self.colors[key] = (name, value, None)
|
||||
|
||||
colors = choice_colors(len(self.colors))
|
||||
for i, (key, value) in enumerate(self.colors.items()):
|
||||
self.colors[key] = [value[0], value[1], colors[i]]
|
||||
|
||||
for evt in self.events:
|
||||
self.convert(evt)
|
||||
a = self.get_event_widget(evt)
|
||||
result.append(a)
|
||||
|
||||
return {'result':result,'sidebar':self.colors}
|
||||
|
||||
def parsedatetime(self, string):
|
||||
|
||||
kind = 'datetime'
|
||||
|
||||
if '-' in string and ':' in string:
|
||||
kind = 'datetime'
|
||||
elif '-' in string:
|
||||
kind = 'date'
|
||||
elif ':' in string:
|
||||
kind = 'time'
|
||||
|
||||
fmt, obj, i, j = DT_FORMAT_INFO[kind]
|
||||
return obj(*time.strptime(string, fmt)[i:j])
|
||||
|
||||
def parse_datetime(self, value, kind="datetime", as_timetuple=False):
|
||||
server_format = DT_SERVER_FORMATS[kind]
|
||||
local_format = self.date_format
|
||||
if not value:
|
||||
return False
|
||||
|
||||
if isinstance(value, (time.struct_time, tuple)):
|
||||
value = time.strftime(local_format, value)
|
||||
|
||||
try:
|
||||
value = time.strptime(value, local_format)
|
||||
except ValueError:
|
||||
try:
|
||||
# might be in server format already (e.g. filter domain)
|
||||
value = time.strptime(value, server_format)
|
||||
except ValueError:
|
||||
try:
|
||||
dt = list(time.localtime())
|
||||
dt[2] = int(value)
|
||||
value = tuple(dt)
|
||||
except:
|
||||
return False
|
||||
|
||||
if kind == "datetime":
|
||||
try:
|
||||
value = self.tz_convert(value, 'parse')
|
||||
except Exception,e:
|
||||
print "*******************Error in timezone parsing *********",e
|
||||
|
||||
if as_timetuple:
|
||||
return value
|
||||
|
||||
return time.strftime(server_format, value)
|
||||
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def edit_events(self, req,**kw):
|
||||
data = {}
|
||||
ds = self.parsedatetime(kw['start_date'])
|
||||
de = self.parsedatetime(kw['end_date'])
|
||||
data[kw['calendar_fields']['date_start']['name']] = self.parse_datetime(ds.timetuple())
|
||||
|
||||
if 'date_stop' in kw['calendar_fields']:
|
||||
data[kw['calendar_fields']['date_stop']['name']] = self.parse_datetime(de.timetuple())
|
||||
elif 'date_delay' in kw['calendar_fields']:
|
||||
day_length = kw['calendar_fields']['day_length']
|
||||
|
||||
tds = time.mktime(ds.timetuple())
|
||||
tde = time.mktime(de.timetuple())
|
||||
|
||||
n = (tde - tds) / (60 * 60)
|
||||
|
||||
if n > day_length:
|
||||
d = math.floor(n / 24)
|
||||
h = n % 24
|
||||
|
||||
n = d * day_length + h
|
||||
|
||||
data[kw['calendar_fields']['date_delay']['name']] = n
|
||||
error = None
|
||||
try:
|
||||
req.session.model(kw['model']).write([int(kw['id'])], data)
|
||||
except Exception, e:
|
||||
error = e
|
||||
return error
|
||||
|
||||
def tz_convert(self, struct_time, action):
|
||||
# if no client timezone is configured, consider the client is in the same
|
||||
# timezone as the server
|
||||
lzone = pytz.timezone(self.client_timezone or self.remote_timezone)
|
||||
szone = pytz.timezone(self.remote_timezone)
|
||||
dt = DT.datetime.fromtimestamp(time.mktime(struct_time))
|
||||
|
||||
if action == 'parse':
|
||||
fromzone = lzone
|
||||
tozone = szone
|
||||
elif action == 'format':
|
||||
fromzone = szone
|
||||
tozone = lzone
|
||||
else:
|
||||
raise Exception("_tz_convert action should be 'parse' or 'format'. Not '%s'" % (action, ))
|
||||
|
||||
localized_original_datetime = fromzone.localize(dt, is_dst=True)
|
||||
destination_datetime = localized_original_datetime.astimezone(tozone)
|
||||
return destination_datetime.timetuple()
|
||||
|
||||
def format_datetime(self, value, kind="datetime", as_timetuple=False):
|
||||
"""Convert date value to the local datetime considering timezone info.
|
||||
|
||||
@param value: the date value
|
||||
@param kind: type of the date value (date, time or datetime)
|
||||
@param as_timetuple: return timetuple
|
||||
|
||||
@type value: basestring or time.time_tuple)
|
||||
|
||||
@return: string or timetuple
|
||||
"""
|
||||
|
||||
server_format = DT_SERVER_FORMATS[kind]
|
||||
local_format = self.date_format
|
||||
|
||||
if not value:
|
||||
return ''
|
||||
|
||||
if isinstance(value, (time.struct_time, tuple)):
|
||||
value = time.strftime(server_format, value)
|
||||
|
||||
if isinstance(value, DT.datetime):
|
||||
value = value
|
||||
try:
|
||||
value = DT.datetime.strptime(value[:10], server_format)
|
||||
return value.strftime(local_format)
|
||||
except:
|
||||
return ''
|
||||
|
||||
value = value.strip()
|
||||
|
||||
# remove trailing miliseconds
|
||||
value = re.sub("(.*?)(\s+\d{2}:\d{2}:\d{2})(\.\d+)?$", "\g<1>\g<2>", value)
|
||||
|
||||
# add time part in value if missing
|
||||
if kind == 'datetime' and not re.search('\s+\d{2}:\d{2}:\d{2}?$', value):
|
||||
value += ' 00:00:00'
|
||||
|
||||
# remove time part from value
|
||||
elif kind == 'date':
|
||||
value = re.sub('\s+\d{2}:\d{2}:\d{2}(\.\d+)?$', '', value)
|
||||
|
||||
value = time.strptime(value, server_format)
|
||||
|
||||
if kind == "datetime":
|
||||
try:
|
||||
value = self.tz_convert(value, 'format')
|
||||
except Exception, e:
|
||||
print "\n\n\n************ Error in timezone formatting", e
|
||||
|
||||
if as_timetuple:
|
||||
return value
|
||||
|
||||
return time.strftime(local_format, value)
|
||||
|
||||
def get_event_widget(self, event):
|
||||
title = '' # the title
|
||||
description = [] # the description
|
||||
|
||||
if self.info_fields:
|
||||
|
||||
f = self.info_fields[0]
|
||||
s = event[f]
|
||||
|
||||
if isinstance(s, (tuple, list)): s = s[-1]
|
||||
|
||||
title = s
|
||||
for f in self.info_fields[1:]:
|
||||
s = event[f]
|
||||
if isinstance(s, (tuple, list)):
|
||||
s = s[-1]
|
||||
if s:
|
||||
description.append(str(s))
|
||||
|
||||
starts = event.get(self.date_start)
|
||||
ends = event.get(self.date_delay) or 1.0
|
||||
span = 0
|
||||
|
||||
if starts and ends:
|
||||
|
||||
n = 0
|
||||
h = ends
|
||||
|
||||
if ends == self.day_length:
|
||||
span = 1
|
||||
|
||||
elif ends > self.day_length:
|
||||
n = ends / self.day_length
|
||||
h = ends % self.day_length
|
||||
|
||||
n = int(math.floor(n))
|
||||
|
||||
if h > 0:
|
||||
span = n + 1
|
||||
else:
|
||||
span = n
|
||||
ends = time.localtime(time.mktime(starts) + (h * 60 * 60) + (n * 24 * 60 * 60))
|
||||
|
||||
if starts and self.date_stop:
|
||||
|
||||
ends = event.get(self.date_stop)
|
||||
if not ends:
|
||||
ends = time.localtime(time.mktime(starts) + 60 * 60)
|
||||
|
||||
tds = time.mktime(starts)
|
||||
tde = time.mktime(ends)
|
||||
|
||||
if tds >= tde:
|
||||
tde = tds + 60 * 60
|
||||
ends = time.localtime(tde)
|
||||
|
||||
n = (tde - tds) / (60 * 60)
|
||||
|
||||
if n >= self.day_length:
|
||||
span = math.ceil(n / 24)
|
||||
|
||||
starts = self.format_datetime(starts, "datetime", True)
|
||||
ends = self.format_datetime(ends, "datetime", True)
|
||||
title = title.strip()
|
||||
description = ', '.join(description).strip()
|
||||
return {'id': event['id'], 'start_date': str(DT.datetime(*starts[:6])), 'end_date': str(DT.datetime(*ends[:6])), 'text': title, 'title': description, 'color': self.colors[event[self.color_field]][-1]}
|
||||
return {'fields_view': fields_view}
|
||||
|
|
|
@ -7,219 +7,324 @@ QWeb.add_template('/base_calendar/static/src/xml/base_calendar.xml');
|
|||
openerp.base.views.add('calendar', 'openerp.base_calendar.CalendarView');
|
||||
openerp.base_calendar.CalendarView = openerp.base.View.extend({
|
||||
// Dhtmlx scheduler ?
|
||||
init: function(parent, element_id, dataset, view_id) {
|
||||
init: function(parent, element_id, dataset, view_id, options) {
|
||||
this._super(parent, element_id);
|
||||
this.view_manager = parent || new openerp.base.NullViewManager();
|
||||
this.set_default_options();
|
||||
this.dataset = dataset;
|
||||
this.dataset_index = 0;
|
||||
this.model = dataset.model;
|
||||
this.view_id = view_id;
|
||||
this.fields_view = {};
|
||||
this.widgets = {};
|
||||
this.widgets_counter = 0;
|
||||
this.fields = this.dataset.fields ? this.dataset.fields: {};
|
||||
this.datarecord = {};
|
||||
this.name = "";
|
||||
this.date_start = "";
|
||||
this.date_delay = "";
|
||||
this.date_stop = "";
|
||||
this.color_field = "";
|
||||
this.day_lenth = 8;
|
||||
this.colors = [];
|
||||
this.color_values = [];
|
||||
this.calendar_fields = {};
|
||||
this.info_fields = [];
|
||||
this.domain = this.dataset._domain ? this.dataset._domain: [];
|
||||
this.context = {};
|
||||
},
|
||||
start: function() {
|
||||
this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
||||
},
|
||||
on_loaded: function(result) {
|
||||
var self = this;
|
||||
var params = {};
|
||||
this.fields_view = result.fields_view;
|
||||
this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
|
||||
this.view_id = this.fields_view.view_id;
|
||||
|
||||
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;
|
||||
|
||||
this.colors = this.fields_view.arch.attrs.colors;
|
||||
this.day_length = this.fields_view.arch.attrs.day_length || 8;
|
||||
this.color_field = this.fields_view.arch.attrs.color;
|
||||
this.fields = this.fields_view.fields;
|
||||
|
||||
//* Calendar Fields *
|
||||
this.calendar_fields['date_start'] = {'name': this.date_start, 'kind': this.fields[this.date_start]['type']};
|
||||
|
||||
if(this.date_delay)
|
||||
this.calendar_fields['date_delay'] = {'name': this.date_delay, 'kind': this.fields[this.date_delay]['type']};
|
||||
|
||||
if(this.date_stop)
|
||||
this.calendar_fields['date_stop'] = {'name': this.date_stop, 'kind': this.fields[this.date_stop]['type']};
|
||||
|
||||
this.calendar_fields['day_length'] = this.day_length;
|
||||
//* ------- *
|
||||
|
||||
for(var fld=0;fld<this.fields_view.arch.children.length;fld++) {
|
||||
this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
|
||||
}
|
||||
|
||||
|
||||
this.load_scheduler();
|
||||
},
|
||||
|
||||
load_scheduler:function() {
|
||||
var self = this;
|
||||
|
||||
var params = {};
|
||||
|
||||
params['model'] = this.model;
|
||||
params['calendar_fields'] = this.calendar_fields;
|
||||
params['info_fields'] = this.info_fields;
|
||||
params['fields'] = this.fields;
|
||||
params['color_field'] = this.color_field;
|
||||
params['domain'] = this.domain;
|
||||
params['colors'] = this.colors;
|
||||
|
||||
/*
|
||||
* Start dhtmlx Schedular
|
||||
*/
|
||||
scheduler.clearAll();
|
||||
scheduler.config.xml_date="%Y-%m-%d %H:%i";
|
||||
scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views
|
||||
|
||||
this.rpc(
|
||||
'/base_calendar/calendarview/schedule_events',
|
||||
params,
|
||||
function(result) {
|
||||
self.schedule_events(result);
|
||||
}
|
||||
)
|
||||
},
|
||||
|
||||
schedule_events: function(result) {
|
||||
var self = this;
|
||||
var res = result.result;
|
||||
var sidebar = result.sidebar;
|
||||
this.$element.html(QWeb.render("CalendarView", {"view": this, "fields_view": this.fields_view, "sidebar":sidebar, "calendar":this}));
|
||||
|
||||
// Initialize Sceduler
|
||||
scheduler.init('openerp_scheduler',null,"month");
|
||||
scheduler.parse(res,"json");
|
||||
jQuery('#dhx_minical_icon').bind('click', this.mini_calendar);
|
||||
|
||||
|
||||
// To Change Event
|
||||
scheduler.attachEvent(
|
||||
'onEventChanged'
|
||||
,function(event_id, event_object) {
|
||||
self.edit_event(event_id, event_object)
|
||||
});
|
||||
|
||||
/*
|
||||
* Create Sidebar
|
||||
*/
|
||||
jQuery('#calendar-sidebar').append(
|
||||
jQuery('<table>',{'width':'100%','cellspacing': 0, 'cellpadding': 0, 'id':'cal-sidebar-option'})
|
||||
)
|
||||
for(s in sidebar) {
|
||||
jQuery('#cal-sidebar-option').append(
|
||||
jQuery('<tr>').append(
|
||||
jQuery('<td>').append(
|
||||
jQuery('<div>')
|
||||
.append(
|
||||
jQuery('<input>',
|
||||
{
|
||||
'type': 'checkbox',
|
||||
'id':sidebar[s][0],
|
||||
'value':sidebar[s][0]
|
||||
}).bind('click',function(){
|
||||
self.reload_scheduler()
|
||||
}),
|
||||
sidebar[s][1]
|
||||
)
|
||||
.css('background-color',sidebar[s][sidebar[s].length-1])
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
convert_date_format: function(start_date, end_date) {
|
||||
var params = {};
|
||||
params['start_date'] = start_date.getFullYear() +'-' + start_date.getMonth()+'-' + start_date.getDate()+' '+start_date.getHours()+':'+start_date.getMinutes()+':'+start_date.getSeconds();
|
||||
if(end_date) {
|
||||
params['end_date'] = end_date.getFullYear() +'-' + end_date.getMonth()+'-' + end_date.getDate()+' '+end_date.getHours()+':'+end_date.getMinutes()+':'+end_date.getSeconds();
|
||||
}
|
||||
return params;
|
||||
},
|
||||
|
||||
edit_event: function(evt_id, evt_object) {
|
||||
var dates = this.convert_date_format(evt_object.start_date, evt_object.end_date);
|
||||
this.rpc(
|
||||
'/base_calendar/calendarview/edit_events',
|
||||
{
|
||||
'start_date': dates.start_date,
|
||||
'end_date': dates.end_date,
|
||||
'id': evt_id,
|
||||
'model': this.model,
|
||||
'info_fields': this.info_fields,
|
||||
'fields': this.fields,
|
||||
'calendar_fields': this.calendar_fields
|
||||
}
|
||||
);
|
||||
},
|
||||
|
||||
mini_calendar: function() {
|
||||
|
||||
if(scheduler.isCalendarVisible()) {
|
||||
scheduler.destroyCalendar();
|
||||
} else {
|
||||
scheduler.renderCalendar({
|
||||
position:"dhx_minical_icon",
|
||||
date:scheduler._date,
|
||||
navigation:true,
|
||||
handler:function(date,calendar){
|
||||
scheduler.setCurrentView(date);
|
||||
scheduler.destroyCalendar()
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
reload_scheduler: function() {
|
||||
// self.color_field
|
||||
console.log('Reload Scheduler>>>')
|
||||
},
|
||||
do_search: function (domains, contexts, groupbys) {
|
||||
this.notification.notify("Searching caldendar");
|
||||
this.domain = this.dataset.domain || [];
|
||||
this.context = this.dataset.context || {};
|
||||
this.options = options || {};
|
||||
},
|
||||
do_show: function () {
|
||||
start: function() {
|
||||
this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
|
||||
},
|
||||
on_loaded: function(data) {
|
||||
this.calendar_fields = {};
|
||||
this.ids = this.dataset.ids;
|
||||
this.color_values = [];
|
||||
this.info_fields = [];
|
||||
|
||||
this.fields_view = data.fields_view;
|
||||
this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
|
||||
this.view_id = this.fields_view.view_id;
|
||||
|
||||
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;
|
||||
|
||||
this.colors = this.fields_view.arch.attrs.colors;
|
||||
this.day_length = this.fields_view.arch.attrs.day_length || 8;
|
||||
this.color_field = this.fields_view.arch.attrs.color;
|
||||
this.fields = this.fields_view.fields;
|
||||
|
||||
//* Calendar Fields *
|
||||
this.calendar_fields['date_start'] = {'name': this.date_start, 'kind': this.fields[this.date_start]['type']};
|
||||
|
||||
if (this.date_delay) {
|
||||
this.calendar_fields['date_delay'] = {'name': this.date_delay, 'kind': this.fields[this.date_delay]['type']};
|
||||
}
|
||||
|
||||
if (this.date_stop) {
|
||||
this.calendar_fields['date_stop'] = {'name': this.date_stop, 'kind': this.fields[this.date_stop]['type']};
|
||||
}
|
||||
|
||||
for (var fld = 0; fld < this.fields_view.arch.children.length; fld++) {
|
||||
this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
|
||||
}
|
||||
this.$element.html(QWeb.render("CalendarView", {"fields_view": this.fields_view}));
|
||||
this.init_scheduler();
|
||||
this.load_scheduler();
|
||||
},
|
||||
init_scheduler: function() {
|
||||
var self = this;
|
||||
scheduler.config.api_date = "%Y-%m-%d %H:%M:%S";
|
||||
scheduler.config.details_on_dblclick = true;
|
||||
scheduler.config.details_on_create = true;
|
||||
|
||||
if (this.fields[this.date_start]['type'] == 'time') {
|
||||
scheduler.config.xml_date = "%H:%M:%S";
|
||||
} else {
|
||||
scheduler.config.xml_date = "%Y-%m-%d %H:%M:%S";
|
||||
}
|
||||
|
||||
this.mode = this.mode || 'month';
|
||||
|
||||
scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views
|
||||
|
||||
// Initialize Sceduler
|
||||
scheduler.init('openerp_scheduler', null, this.mode);
|
||||
|
||||
this.$element.find('#dhx_minical_icon').bind('click', this.mini_calendar);
|
||||
|
||||
// Event Options Click,edit
|
||||
scheduler.attachEvent('onDblClick', this.popup_event);
|
||||
|
||||
scheduler.attachEvent('onEventCreated', function(event_id, e) {
|
||||
//Replace default Lightbox with Popup Form of new Event
|
||||
scheduler.showLightbox = function() {
|
||||
//Delete Newly created Event,Later we reload Scheduler
|
||||
scheduler.deleteEvent(event_id);
|
||||
self.popup_event();
|
||||
}
|
||||
});
|
||||
|
||||
scheduler.attachEvent('onBeforeEventChanged', function(event_obj, native_event, is_new) {
|
||||
var is_event_exist = $.inArray(event_obj.id, self.dataset.ids);
|
||||
if (is_event_exist >= 0 || !is_new) {
|
||||
// try to save Event.
|
||||
var data = {};
|
||||
self.mode = scheduler._mode;
|
||||
var date_format = self.calendar_fields.date_start.kind == 'time' ? 'HH:mm:ss' : 'yyyy-MM-dd HH:mm:ss';
|
||||
data[self.date_start] = event_obj.start_date.toString(date_format);
|
||||
|
||||
if (self.date_stop) {
|
||||
data[self.date_stop] = event_obj.end_date.toString(date_format);
|
||||
}
|
||||
|
||||
if (self.date_delay) {
|
||||
var tds = (event_obj.start_date.getOrdinalNumber() / 1e3 >> 0) - (event_obj.start_date.getOrdinalNumber() < 0);
|
||||
var tde = (event_obj.end_date.getOrdinalNumber() / 1e3 >> 0) - (event_obj.end_date.getOrdinalNumber() < 0);
|
||||
var n = (tde - tds) / (60 * 60);
|
||||
if (n > self.day_length) {
|
||||
var d = Math.floor(n / 24),
|
||||
h = n % 24;
|
||||
n = d * self.day_length + h;
|
||||
}
|
||||
data[self.date_delay] = n;
|
||||
}
|
||||
self.dataset.write(event_obj.id, data, self.load_scheduler);
|
||||
} else {
|
||||
// new Event.
|
||||
return true;
|
||||
}
|
||||
});
|
||||
},
|
||||
load_scheduler: function() {
|
||||
var self = this;
|
||||
this.dataset.read_slice([], 0, false, function(events) {
|
||||
if (self.session.locale_code) {
|
||||
// TODO: replace $LAB
|
||||
$LAB.setOptions({AlwaysPreserveOrder: true}).script([
|
||||
'/base_calendar/static/lib/dhtmlxScheduler/sources/locale_' + self.session.locale_code + '.js',
|
||||
'/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_' + self.session.locale_code + '.js'
|
||||
]).wait(function() {
|
||||
self.schedule_events(events);
|
||||
});
|
||||
} else {
|
||||
self.schedule_events(events);
|
||||
}
|
||||
});
|
||||
},
|
||||
schedule_events: function(events) {
|
||||
var self = this;
|
||||
scheduler.clearAll();
|
||||
|
||||
//To parse Events we have to convert date Format
|
||||
var res_events = [];
|
||||
for (var e = 0; e < events.length; e++) {
|
||||
var evt = events[e];
|
||||
if (!evt[this.date_start]) {
|
||||
this.notification.warn("Start date is not defined for event :", evt['id']);
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.fields[this.date_start]['type'] == 'date') {
|
||||
evt[this.date_start] = openerp.base.parse_date(evt[this.date_start]).set({hour: 9}).toString('yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
if (this.date_stop && evt[this.date_stop] && this.fields[this.date_stop]['type'] == 'date') {
|
||||
evt[this.date_stop] = openerp.base.parse_date(evt[this.date_stop]).set({hour: 17}).toString('yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
res_events.push(this.convert_event(evt));
|
||||
}
|
||||
|
||||
scheduler.parse(res_events, 'json');
|
||||
},
|
||||
convert_event: function(event) {
|
||||
var starts = event[this.date_start],
|
||||
ends = event[this.date_delay] || 1,
|
||||
span = 0,
|
||||
res_text = '',
|
||||
res_description = [];
|
||||
|
||||
var parse_start_date = openerp.base.parse_datetime(starts);
|
||||
if (event[this.date_stop]) {
|
||||
var parse_end_date = openerp.base.parse_datetime(event[this.date_stop]);
|
||||
}
|
||||
if (this.info_fields) {
|
||||
var fld = event[this.info_fields[0]];
|
||||
|
||||
if (typeof fld == 'object') {
|
||||
res_text = fld[fld.length -1];
|
||||
} else {
|
||||
res_text = fld;
|
||||
}
|
||||
|
||||
var sliced_info_fields = this.info_fields.slice(1);
|
||||
for (sl_fld in sliced_info_fields) {
|
||||
var slc_fld = event[sliced_info_fields[sl_fld]];
|
||||
|
||||
if (typeof slc_fld == 'object') {
|
||||
res_description.push(slc_fld[slc_fld.length - 1]);
|
||||
} else {
|
||||
if(slc_fld) res_description.push(slc_fld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (starts && ends) {
|
||||
var n = 0,
|
||||
h = ends;
|
||||
if (ends == this.day_length) {
|
||||
span = 1;
|
||||
} else if (ends > this.day_length) {
|
||||
n = ends / this.day_length;
|
||||
h = ends % this.day_length;
|
||||
n = parseInt(Math.floor(n));
|
||||
|
||||
if (h > 0) {
|
||||
span = n + 1;
|
||||
} else {
|
||||
span = n;
|
||||
}
|
||||
}
|
||||
var start = parse_start_date.setTime((parse_start_date.getTime() + (h * 60 * 60) + (n * 24 * 60 * 60)));
|
||||
ends = parse_start_date;
|
||||
}
|
||||
|
||||
if (starts && this.date_stop) {
|
||||
ends = parse_end_date;
|
||||
if (event[this.date_stop] == undefined) {
|
||||
var start = parse_start_date.setTime((parse_start_date.getTime() + (h * 60 * 60) + (n * 24 * 60 * 60)));
|
||||
ends = parse_start_date;
|
||||
}
|
||||
var tds = parse_start_date.getTime(),
|
||||
tde = parse_end_date.getTime();
|
||||
|
||||
if (tds >= tde) {
|
||||
tde = tds + 60 * 60;
|
||||
parse_end_date.setTime(tde);
|
||||
ends = parse_end_date;
|
||||
}
|
||||
n = (tde - tds) / (60 * 60);
|
||||
if (n >= this.day_length) {
|
||||
span = Math.ceil(n / 24);
|
||||
}
|
||||
}
|
||||
return {
|
||||
'start_date': parse_start_date.toString('yyyy-MM-dd HH:mm:ss'),
|
||||
'end_date': ends.toString('yyyy-MM-dd HH:mm:ss'),
|
||||
'text': res_text,
|
||||
'id': event['id'],
|
||||
'title': res_description.join()
|
||||
}
|
||||
},
|
||||
mini_calendar: function() {
|
||||
if (scheduler.isCalendarVisible()) {
|
||||
scheduler.destroyCalendar();
|
||||
} else {
|
||||
scheduler.renderCalendar({
|
||||
position:"dhx_minical_icon",
|
||||
date:scheduler._date,
|
||||
navigation:true,
|
||||
handler: function(date, calendar) {
|
||||
scheduler.setCurrentView(date);
|
||||
scheduler.destroyCalendar()
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
do_search: function(domains, contexts, groupbys) {
|
||||
var self = this;
|
||||
this.rpc('/base/session/eval_domain_and_context', {
|
||||
domains: domains,
|
||||
contexts: contexts,
|
||||
group_by_seq: groupbys
|
||||
}, function (results) {
|
||||
// TODO: handle non-empty results.group_by with read_group
|
||||
self.dataset.context = self.context = results.context;
|
||||
self.dataset.domain = self.domain = results.domain;
|
||||
self.dataset.read_slice(_.keys(self.fields), 0, self.limit, function(events) {
|
||||
self.schedule_events(events);
|
||||
});
|
||||
});
|
||||
},
|
||||
do_show: function () {
|
||||
this.$element.show();
|
||||
},
|
||||
|
||||
do_hide: function () {
|
||||
this.$element.hide();
|
||||
},
|
||||
popup_event: function(event_id) {
|
||||
var self = this;
|
||||
if (event_id) event_id = parseInt(event_id, 10);
|
||||
var action = {
|
||||
res_model: this.dataset.model,
|
||||
res_id: event_id,
|
||||
views: [[false, 'form']],
|
||||
type: 'ir.actions.act_window',
|
||||
view_type: 'form',
|
||||
view_mode: 'form',
|
||||
flags : {
|
||||
search_view: false,
|
||||
sidebar : false,
|
||||
views_switcher : false,
|
||||
action_buttons : false,
|
||||
pager: false
|
||||
}
|
||||
}
|
||||
var element_id = _.uniqueId("act_window_dialog");
|
||||
var dialog = $('<div>', {
|
||||
'id': element_id
|
||||
}).dialog({
|
||||
modal: true,
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
$(this).dialog("destroy");
|
||||
},
|
||||
Save: function() {
|
||||
var view_manager = action_manager.viewmanager;
|
||||
var _dialog = this;
|
||||
view_manager.views[view_manager.active_view].controller.do_save(function(r) {
|
||||
$(_dialog).dialog("destroy");
|
||||
// self.start();
|
||||
self.load_scheduler();
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
var action_manager = new openerp.base.ActionManager(this, element_id);
|
||||
action_manager.start();
|
||||
action_manager.do_action(action);
|
||||
//Default_get
|
||||
if (!event_id) {
|
||||
this.dataset.index = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//openerp.base.Action = openerp.base.Action.extend({
|
||||
// do_action_window: function(action) {
|
||||
// this._super.apply(this,arguments);
|
||||
// for(var i = 0; i < action.views.length; i++) {
|
||||
// if(action.views[i][1] == "calendar") {
|
||||
// this.calendar_id = action.views[i][0];
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// // IF there is a view calender
|
||||
// // if(this.calendar_id
|
||||
// },
|
||||
//});
|
||||
|
||||
};
|
||||
|
||||
// DEBUG_RPC:rpc.request:('execute', 'addons-dsh-l10n_us', 1, '*', ('ir.filters', 'get_filters', u'res.partner'))
|
||||
|
|
|
@ -1,15 +1,9 @@
|
|||
<template>
|
||||
<t t-name="CalendarView">
|
||||
<h3 class="title"><t t-esc="view.fields_view.arch.attrs.string"/></h3>
|
||||
<h3 class="title"><t t-esc="fields_view.arch.attrs.string"/></h3>
|
||||
<table class="calendar-view" width="100%" height="100%" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td>
|
||||
<div style="height: 1000px;width: 100%;">
|
||||
<div id="calendar-sidebar">
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td style="width:85%;" align="left">
|
||||
<td style="width:100%;" align="left">
|
||||
<div id="openerp_scheduler" class="dhx_cal_container" style="height: 1000px;width: 100%;">
|
||||
<div class="dhx_cal_navline">
|
||||
<div class="dhx_cal_prev_button"/>
|
||||
|
|
Loading…
Reference in New Issue