Guest User

Untitled

a guest
Dec 16th, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.07 KB | None | 0 0
  1. ## -*- coding: utf-8 -*-
  2. import itertools
  3. import time
  4. import xml.dom.minidom
  5.  
  6. from openobject.i18n import format
  7. from openobject.widgets import JSLink, CSSLink
  8. from openobject.i18n.format import format_date_custom
  9.  
  10. from openerp.utils import rpc, node_attributes
  11. from openerp.widgets import TinyWidget, ConcurrencyInfo
  12.  
  13. from view_calendar.widgets._base import ICalendar, TinyCalendar, TinyEvent, choice_colors
  14. from view_calendar.widgets.utils import Day, Week, Month, Year
  15. from view_calendar.widgets import GanttCalendar
  16. from view_calendar.widgets.widgets import _get_selection_day, MiniCalendar, GroupBox, Sidebar
  17.  
  18. from mitr.widgets.utils import ProjectWeek
  19. from mitr.utils.weeks import weeks_from, parse_datetime2date
  20. from calendar import timegm
  21. from mitr.utils.weeks import fmt_striftime_th
  22. from datetime import timedelta, datetime
  23. from random import randrange
  24. from mitr.settings import COLOR_KEYS
  25.  
  26. ACTUAL_FACTOR = 0.1
  27. ACTUAL_COLOR = "#666666"
  28.  
  29. class OsTinyEvent(TinyEvent):
  30.  
  31. params = ['starts', 'ends', 'title', 'description', 'color', 'record_id', 'create_date', 'create_uid', 'write_uid', 'write_date', 'actual', 'plan', 'progress' ]
  32.  
  33. def __init__(self, record, starts, ends, title='', description='', dayspan=0, color=None, classes=None, actual=0, plan=0, progress=0):
  34.  
  35. super(OsTinyEvent, self).__init__(record, starts, ends, title=title, description=description, dayspan=dayspan, color=color, classes=classes)
  36.  
  37. self.actual = actual
  38. self.plan = plan
  39. self.progress = progress
  40.  
  41.  
  42. class MitrGanttCalendar(ICalendar):
  43.  
  44. template = 'mitr/widgets/templates/gantt.mako'
  45.  
  46. params = ['title', 'level', 'groups', 'days', 'events', 'calendar_fields', 'date_format',
  47. 'selected_day', 'mode', 'headers', 'subheaders', 'model', 'ids']
  48. member_widgets = ['sidebar']
  49.  
  50. level = None
  51. groups = None
  52. title = None
  53. days = None
  54. headers = None
  55. subheaders = None
  56. mode = 'week'
  57.  
  58. sidebar = None
  59.  
  60. css = [CSSLink("view_calendar", 'css/calendar.css'),
  61. CSSLink("view_calendar", 'css/screen.css'),
  62. CSSLink("view_calendar", 'css/calendar_gantt.css'),
  63. CSSLink("mitr", 'css/gantt.css')]
  64. javascript = [JSLink("view_calendar", 'javascript/calendar_date.js'),
  65. JSLink("view_calendar", 'javascript/calendar_utils.js'),
  66. JSLink("view_calendar", 'javascript/calendar_box.js'),
  67. JSLink("view_calendar", 'javascript/calendar_month.js'),
  68. JSLink("view_calendar", 'javascript/calendar_week.js'),
  69. #JSLink("view_calendar", 'javascript/calendar_gantt.js'),
  70. JSLink("mitr", 'javascript/mitr_calendar_gantt.js')
  71. ]
  72.  
  73. def __init__(self, model, ids, view, domain=[], context={}, options=None, conditions=[]):
  74.  
  75. self.level = None
  76. self.groups = []
  77. self.days = []
  78. self.headers = []
  79.  
  80. super(MitrGanttCalendar, self).__init__(model, ids, view, domain, context, options)
  81.  
  82. # y, m, d = time.localtime()[:3]
  83. # if options:
  84. # y, m, d = options.date1[:3]
  85. # if ids:
  86. proxy = rpc.RPCProxy(self.model)
  87.  
  88. if not self.ids:
  89. self.ids = proxy.search(conditions, order="date_start")
  90. ctx = rpc.session.context.copy()
  91. start_week_id = proxy.search(conditions, order='date_start', limit=1)
  92. if not start_week_id:
  93. return None
  94. start_week = time.strptime(proxy.read(start_week_id)[0]['date_start'], "%Y-%m-%d %H:%M:%S")
  95. y = start_week.tm_year
  96. m = start_week.tm_mon
  97. d = start_week.tm_mday
  98. end_week = time.strptime(proxy.read(proxy.search(conditions, order='date_end DESC', limit=1))[0]['date_end'], "%Y-%m-%d %H:%M:%S")
  99. weeks = weeks_from(start_week, end_week) + 2
  100. #y, m, d = time.strptime(self._result[0]['date_start'], "%y-%m-%d ")
  101. #raise Exception(weeks)
  102. day = Day(y, m, d)
  103.  
  104. w = ProjectWeek(day, weeks)
  105. # wp = w - 1
  106. # wn = w + 1
  107. #self.days = wp.days + w.days + wn.days
  108. self.days = w.days
  109. self.title = _(u"%s - %s") % (ustr(self.days[0]), ustr(self.days[-1]))
  110. self.selected_day = _get_selection_day(day, self.selected_day, 'week')
  111.  
  112. self.headers = [(7, _("สัปดาห์ที่ %s") % fmt_striftime_th(w[0]+(w1*7), '%W (%b %Y)', ['%b'])) for w1 in range(0,weeks)]
  113. #self.headers = [(7, _("สัปดาห์ที่ %s") % (w[0]+(w1*7)).strftime('%W (%b %Y)')) for w1 in range(0,weeks)]
  114. self.subheaders = [format_date_custom(x, "E d") for x in itertools.chain(w)]
  115.  
  116.  
  117. if self.level:
  118. field = self.level['link']
  119. fields = rpc.RPCProxy(self.model).fields_get([field], rpc.session.context)
  120. self.fields.update(fields)
  121.  
  122. self.events = self.get_events(self.days)
  123. self.groups = self.get_groups(self.events)
  124.  
  125. minical = MiniCalendar(day)
  126. groupbox = GroupBox(self.colors, self.color_values, day,
  127. group_relation=self.fields[self.color_field],
  128. title=(self.color_field or None) and self.fields[self.color_field]['string'], mode=self.mode)
  129.  
  130. self.sidebar = Sidebar(minical, groupbox, self.use_search)
  131.  
  132. def parse(self, root, fields):
  133.  
  134. info_fields = []
  135. attrs = node_attributes(root)
  136.  
  137. for node in root.childNodes:
  138. attrs = node_attributes(node)
  139.  
  140. if node.localName == 'field':
  141. info_fields.append(attrs['name'])
  142.  
  143. if node.localName == 'level':
  144. self.level = attrs
  145. info_fields += self.parse(node, fields)
  146.  
  147. return info_fields
  148.  
  149. def get_event_widget(self, event):
  150. title = '' # the title
  151. description = [] # the description
  152. if self.info_fields:
  153.  
  154. f = self.info_fields[0]
  155. s = event[f]
  156.  
  157. if isinstance(s, (tuple, list)): s = s[-1]
  158.  
  159. title = ustr(s)
  160.  
  161. for f in self.info_fields[1:]:
  162. s = event[f]
  163. if isinstance(s, (tuple, list)):
  164. s = s[-1]
  165. if s:
  166. description.append(ustr(s))
  167. starts = event.get(self.date_start)
  168. ends = event.get(self.date_stop)
  169. #ends = event.get(self.date_delay) or 1.0
  170. span = 0
  171.  
  172. """if starts and ends:
  173.  
  174. n = 0
  175. h = ends
  176.  
  177. if ends == self.day_length:
  178. span = 1
  179.  
  180. elif ends > self.day_length:
  181. n = ends / self.day_length
  182. h = ends % self.day_length
  183.  
  184. n = int(math.floor(n))
  185.  
  186. if h > 0:
  187. span = n + 1
  188. else:
  189. span = n
  190.  
  191. ends = time.localtime(time.mktime(starts) + (h * 60 * 60) + (n * 24 * 60 * 60))
  192.  
  193. if starts and self.date_stop:
  194.  
  195. ends = event.get(self.date_stop)
  196. if not ends:
  197. ends = time.localtime(time.mktime(starts) + 60 * 60)
  198.  
  199. tds = time.mktime(starts)
  200. tde = time.mktime(ends)
  201.  
  202. if tds >= tde:
  203. tde = tds + 60 * 60
  204. ends = time.localtime(tde)
  205.  
  206. n = (tde - tds) / (60 * 60)
  207.  
  208. if n >= self.day_length:
  209. span = math.ceil(n / 24)"""
  210.  
  211. starts = format.format_datetime(starts, "datetime", True)
  212. ends = format.format_datetime(ends, "datetime", True)
  213. color_key = event.get(self.color_field)
  214. #color = self.colors.get(color_key)
  215. color = (rpc.session['user_name'], rpc.session['uid'], COLOR_KEYS[event['color']])
  216. classes = self._get_classes(event)
  217. title = title.strip()
  218. description = ', '.join(description).strip()
  219.  
  220. timesheet_res = rpc.RPCProxy('os.res.timesheet')
  221. task_week_res = rpc.RPCProxy('os.task.week')
  222.  
  223. actual = timesheet_res.sum_actual_by_task(event['id'])
  224. plan = task_week_res.sum_plan_by_task(event['id'])
  225. progress = 0
  226. if plan != 0:
  227. progress = (actual/plan) * 100
  228. if isinstance(event['id'], int):
  229. event_log = rpc.session.execute('object', 'execute', self.model, 'perm_read', [event['id']])[0]
  230.  
  231. event['create_date'] = event_log['create_date']
  232. event['create_uid'] = event_log['create_uid'][1]
  233. if isinstance(event_log['write_uid'], tuple):
  234. event_log['write_uid'] = event_log['write_uid'][1]
  235. event['write_uid'] = event_log['write_uid']
  236. event['write_date'] = event_log['write_date']
  237.  
  238. else:
  239. color = (rpc.session['user_name'], rpc.session['uid'], ACTUAL_COLOR)
  240.  
  241. return OsTinyEvent(event, starts, ends, title, description, dayspan=span, color=(color or None) and color[-1], classes=classes, actual=actual, plan=plan, progress=progress)
  242.  
  243. def get_events(self, days):
  244. proxy = rpc.RPCProxy(self.model)
  245.  
  246. """if self.date_stop:
  247. # use the correct algorithm:
  248. domain = self.domain + [(self.date_stop, '<=', days[-1].isoformat() + ' 23:59:59'),
  249. (self.date_start, '>=', days[0].isoformat() + ' 00:00:00')]
  250. else:
  251. # cannot use the correct algorithm, use the old one:
  252. first = days[0].month2.prev()[0] #HACK: add prev month
  253. domain = self.domain + [(self.date_start, '>', first.isoformat()),
  254. (self.date_start, '<', days[-1].next().isoformat())]"""
  255. domain = self.domain
  256.  
  257.  
  258. # convert color values from string to python values
  259. if self.color_values and self.color_field in self.fields:
  260. try:
  261. atr = self.fields[self.color_field]
  262. atr['required'] = False
  263. wid = get_widget(atr['type'])(**atr)
  264. vals = self.color_values[:]
  265. for i, v in enumerate(vals):
  266. try:
  267. vals[i] = wid.validator.to_python(v)
  268. except:
  269. pass
  270. domain.append((self.color_field, "in", vals))
  271. except Exception:
  272. pass
  273.  
  274. if self.options and self.options.use_search:
  275. domain += self.options.search_domain
  276.  
  277. ctx = rpc.session.context.copy()
  278. ctx.update(self.context)
  279.  
  280. order_by = ('sequence' in self.fields or 0) and 'sequence'
  281.  
  282. if self.color_field and self.fields[self.color_field].get('relation') and self.color_field not in [item[0] for item in domain]:
  283. if self.options and self.options.get('_terp_color_filters'):
  284. clr_field = self.options['_terp_color_filters']
  285. else:
  286. search_limit = 10
  287. need_to_add_the_user_to_the_list_of_users = False
  288. if self.context and self.color_field and \
  289. self.context.get('search_default_user_id') and \
  290. self.color_field == 'user_id' and \
  291. self.fields[self.color_field].get('relation') == 'res.users':
  292. need_to_add_the_user_to_the_list_of_users = True
  293. clr_field = rpc.RPCProxy(self.fields[self.color_field]['relation']).search([], 0, search_limit, 0, ctx)
  294. if need_to_add_the_user_to_the_list_of_users and self.context.get('search_default_user_id') not in clr_field:
  295. clr_field[search_limit-1] = self.context.get('search_default_user_id')
  296.  
  297. domain.append((self.color_field, 'in', clr_field))
  298. if not self.ids:
  299. ids = proxy.search(domain, 0, 0, order_by, ctx)
  300. else:
  301. ids = self.ids
  302.  
  303. result = proxy.read(ids, self.fields.keys()+['__last_update', 'color'], ctx)
  304. ConcurrencyInfo.update(self.model, result)
  305. self.concurrency_info = ConcurrencyInfo(self.model, ids)
  306. if self.color_field:
  307. for evt in result:
  308. key = evt[self.color_field]
  309. name = key
  310. value = key
  311. if isinstance(key, list): # M2O, XMLRPC returns List instead of Tuple
  312. evt[self.color_field] = key = tuple(key)
  313.  
  314. if isinstance(key, tuple): # M2O
  315. value, name = key
  316.  
  317. self.colors[key] = (name, value, None)
  318.  
  319. colors = choice_colors(len(self.colors))
  320. for i, (key, value) in enumerate(self.colors.items()):
  321. self.colors[key] = (value[0], value[1], colors[i])
  322.  
  323. events = []
  324.  
  325. for evt in result:
  326. self.convert(evt)
  327. events.append(self.get_event_widget(evt))
  328. # add the actual data
  329. evt2 = self.get_actual_data(evt)
  330. events.append(self.get_event_widget(evt2))
  331.  
  332. if self.date_stop:
  333. result = events
  334. else:
  335. # filter out the events which are not in the range
  336. result = []
  337. for e in events:
  338. if e.starts is None:
  339. continue
  340. if e.dayspan > 0 and days[0] - e.dayspan < e.starts:
  341. result.append(e)
  342. if e.dayspan == 0 and days[0] <= e.starts:
  343. result.append(e)
  344. return result
  345.  
  346. def get_groups(self, events):
  347.  
  348. if not self.level:
  349. return []
  350.  
  351. obj = self.level['object']
  352. field = self.level['link']
  353.  
  354. keys = []
  355. groups = {}
  356. for evt in events:
  357. group_id = evt.record[field]
  358. group_title = 'None'
  359.  
  360. if not group_id: # create dummy group
  361. group_id = 0
  362.  
  363. if isinstance(group_id, (list, tuple)):
  364. group_id, group_title = evt.record[field]
  365. elif group_id:
  366. group_id, group_title = rpc.RPCProxy(obj).name_get([group_id], rpc.session.context)[0]
  367.  
  368. group = groups.setdefault(group_id, {'id': str(group_id), 'title': group_title, 'model': obj, 'items': [], 'actual':0, 'plan':0, 'progress':0})
  369.  
  370. group['items'].append(str(evt.record_id))
  371. # get all event in this group and sum actual and planed then progress
  372. group['actual'] += evt.actual
  373. group['plan'] += evt.plan
  374. group['progress'] += evt.progress
  375. if group_id not in keys:
  376. keys.append(group_id)
  377.  
  378. return [groups[i] for i in keys]
  379.  
  380. def get_actual_data(self, evt):
  381. data = evt.copy()
  382. data['name'] = ""
  383. # get timesheets which contain task id
  384. # find first and last order by date
  385. timesheet_res = rpc.RPCProxy('os.res.timesheet')
  386. args = [('task_id', '=', int(data['id'])), "!", ('hour', '=', 0)]
  387. first_ids = timesheet_res.search(args, order="date", limit=1)
  388. last_ids = timesheet_res.search(args, order='date DESC', limit=1)
  389.  
  390. new_date_start = new_date_end = None
  391. if first_ids and last_ids:
  392. first = timesheet_res.read(first_ids[0], ('date',))
  393. last = timesheet_res.read(last_ids[0], ('date',))
  394. new_date_start = first['date']
  395. new_date_end = last['date']
  396. data['id'] += ACTUAL_FACTOR
  397. if new_date_start is not None:
  398. data[self.date_start] = parse_datetime2date(new_date_start).timetuple()
  399. else:
  400. start = data[self.date_start]
  401. new_date = datetime(start.tm_year-5, start.tm_mon, start.tm_mday, start.tm_hour, start.tm_min, start.tm_sec)
  402. data[self.date_start] = datetime(day=new_date.day, month=new_date.month, year=new_date.year, hour=new_date.hour, minute=new_date.minute, second=new_date.second).timetuple()
  403. if new_date_end is not None:
  404. data[self.date_stop] = parse_datetime2date(new_date_end).timetuple()
  405. else:
  406. end = data[self.date_start]
  407. new_date = datetime(end.tm_year-5, end.tm_mon, end.tm_mday, end.tm_hour, end.tm_min, end.tm_sec)
  408. data[self.date_stop] = datetime(day=new_date.day, month=new_date.month, year=new_date.year, hour=new_date.hour, minute=new_date.minute, second=new_date.second).timetuple()
  409. """data['id'] += ACTUAL_FACTOR
  410. start = data[self.date_start]
  411. new_date = datetime(start.tm_year, start.tm_mon, start.tm_mday, start.tm_hour, start.tm_min, start.tm_sec) + timedelta(days=randrange(0,2))
  412. data[self.date_start] = datetime(day=new_date.day, month=new_date.month, year=new_date.year, hour=new_date.hour, minute=new_date.minute, second=new_date.second).timetuple()
  413. end = evt[self.date_stop]
  414. new_date = datetime(end.tm_year, end.tm_mon, end.tm_mday, end.tm_hour, end.tm_min, end.tm_sec) + timedelta(days=randrange(0,2))
  415. data[self.date_stop] = datetime(day=new_date.day, month=new_date.month, year=new_date.year, hour=new_date.hour, minute=new_date.minute, second=new_date.second ).timetuple()"""
  416.  
  417. return data
Add Comment
Please, Sign In to add comment