Merge lp:~openerp-dev/openobject-addons/trunk-project-onboarding into lp:openobject-addons

Proposed by Thibault Delavallée (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-project-onboarding
Merge into: lp:openobject-addons
Diff against target: 1059 lines (+528/-140)
12 files modified
project/__openerp__.py (+7/-3)
project/project.py (+102/-15)
project/project_onboarding_data.xml (+159/-0)
project/project_view.xml (+122/-66)
project/static/src/css/project.css (+12/-48)
project/static/src/js/project.js (+1/-0)
project/static/src/js/project_graph.js (+30/-0)
project/views/project.xml (+1/-0)
project_issue/project_issue.py (+44/-3)
project_issue/project_issue_data.xml (+25/-1)
project_issue/project_issue_view.xml (+20/-2)
project_timesheet/project_timesheet_view.xml (+5/-2)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-project-onboarding
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+218955@code.launchpad.net

Description of the change

[TO UPDATE]

To post a comment you must log in.
9416. By Turkesh Patel (openERP)

[MRG] merge with lp:openobject-addons

9417. By Turkesh Patel (openERP)

[IMP] remove priority from tour task

9418. By Turkesh Patel (openERP)

[IMP] improved data of task and added data for issue.

9419. By Turkesh Patel (openERP)

[IMP] add new data for worklogs,analticaaccount and contract related help task.

9420. By Turkesh Patel (openERP)

[ADD] added two new users to make graph attractive

9421. By Turkesh Patel (openERP)

[MRG] merge with lp:openobject-addons

9422. By Turkesh Patel (openERP)

[FIX] add methods back to do not break test casse.

Unmerged revisions

9422. By Turkesh Patel (openERP)

[FIX] add methods back to do not break test casse.

9421. By Turkesh Patel (openERP)

[MRG] merge with lp:openobject-addons

9420. By Turkesh Patel (openERP)

[ADD] added two new users to make graph attractive

9419. By Turkesh Patel (openERP)

[IMP] add new data for worklogs,analticaaccount and contract related help task.

9418. By Turkesh Patel (openERP)

[IMP] improved data of task and added data for issue.

9417. By Turkesh Patel (openERP)

[IMP] remove priority from tour task

9416. By Turkesh Patel (openERP)

[MRG] merge with lp:openobject-addons

9415. By Turkesh Patel (openERP)

[MRG] merge with lp:openobject-addons

9414. By Turkesh Patel (openERP)

[MRG] merge with lp:openobject-addons

9413. By Turkesh Patel (openERP)

[IMP] improved code

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'project/__openerp__.py'
2--- project/__openerp__.py 2014-04-29 15:41:04 +0000
3+++ project/__openerp__.py 2014-05-15 11:32:23 +0000
4@@ -44,7 +44,8 @@
5 'board',
6 'mail',
7 'resource',
8- 'web_kanban'
9+ 'web_kanban',
10+ 'web_kanban_sparkline',
11 ],
12 'description': """
13 Track multi-level projects, tasks, work done on tasks
14@@ -72,8 +73,11 @@
15 'report/project_cumulative.xml',
16 'res_config_view.xml',
17 'views/project.xml',
18- ],
19- 'demo': ['project_demo.xml'],
20+ 'project_onboarding_data.xml',
21+ ],
22+ 'demo': [
23+ 'project_demo.xml'
24+ ],
25 'test': [
26 ],
27 'installable': True,
28
29=== modified file 'project/project.py'
30--- project/project.py 2014-05-13 11:18:37 +0000
31+++ project/project.py 2014-05-15 11:32:23 +0000
32@@ -22,7 +22,8 @@
33 from datetime import datetime, date
34 from lxml import etree
35 import time
36-
37+import calendar
38+from dateutil import relativedelta
39 from openerp import SUPERUSER_ID
40 from openerp import tools
41 from openerp.addons.resource.faces import task as Task
42@@ -65,6 +66,7 @@
43 _inherits = {'account.analytic.account': "analytic_account_id",
44 "mail.alias": "alias_id"}
45 _inherit = ['mail.thread', 'ir.needaction_mixin']
46+ _period_number = 5
47
48 def _auto_init(self, cr, context=None):
49 """ Installation hook: aliases, project.project """
50@@ -219,6 +221,64 @@
51 'limit': 80,
52 'context': "{'default_res_model': '%s','default_res_id': %d}" % (self._name, res_id)
53 }
54+
55+ def __get_bar_values(self, cr, uid, obj, domain, read_fields, value_field, groupby_field, context=None):
56+ """ Generic method to generate data for bar chart values using SparklineBarWidget.
57+ This method performs obj.read_group(cr, uid, domain, read_fields, groupby_field).
58+
59+ :param obj: the target model (i.e. project_project)
60+ :param domain: the domain applied to the read_group
61+ :param list read_fields: the list of fields to read in the read_group
62+ :param str value_field: the field used to compute the value of the bar slice
63+ :param str groupby_field: the fields used to group
64+
65+ :return list section_result: a list of dicts: [
66+ { 'value': (int) bar_column_value,
67+ 'tootip': (str) bar_column_tooltip,
68+ }
69+ ]
70+ """
71+ month_begin = date.today().replace(day=1)
72+ section_result = [{
73+ 'value': 0,
74+ 'tooltip': (month_begin + relativedelta.relativedelta(months=-i)).strftime('%B %Y'),
75+ } for i in range(self._period_number - 1, -1, -1)]
76+ group_obj = obj.read_group(cr, uid, domain, read_fields, groupby_field, context=context)
77+ pattern = tools.DEFAULT_SERVER_DATE_FORMAT if obj.fields_get(cr, uid, groupby_field)[groupby_field]['type'] == 'date' else tools.DEFAULT_SERVER_DATETIME_FORMAT
78+ for group in group_obj:
79+ group_begin_date = datetime.strptime(group['__domain'][0][2], pattern)
80+ month_delta = relativedelta.relativedelta(month_begin, group_begin_date)
81+ section_result[self._period_number - (month_delta.months + 1)] = {'value': group.get(value_field, 0), 'tooltip': group.get(groupby_field, 0)}
82+ return section_result
83+
84+ def _get_task_data(self, cr, uid, ids, field_name, arg, context=None):
85+ """ Get task-related data for project kanban view
86+ monthly_open_task: number of open task during the last months
87+ """
88+ Task = self.pool.get('project.task')
89+ res = dict.fromkeys(ids, False)
90+ month_begin = date.today().replace(day=1)
91+ date_begin = month_begin - relativedelta.relativedelta(months=self._period_number - 1)
92+ date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1])
93+ project_pre_domain = [('create_date', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)),
94+ ('create_date', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
95+ ]
96+ for id in ids:
97+ res[id] = dict()
98+ project_domain = project_pre_domain + [('project_id', '=', id)]
99+ res[id] = self.__get_bar_values(cr, uid, Task, project_domain, ['create_date'], 'create_date_count', 'create_date', context=context)
100+ return res
101+
102+ def _get_tasks_per_user(self, cr, uid, ids, field_name, arg, context=None):
103+ Task = self.pool['project.task']
104+ res = dict.fromkeys(ids, False)
105+ for project in self.browse(cr, uid, ids, context=context):
106+ data = []
107+ group_obj = Task.read_group(cr, uid, [('project_id','=',project.id)], ['user_id'], 'user_id', context=context)
108+ for group in group_obj:
109+ data.append({'label' : group['user_id'] and group['user_id'][1] or 'Unassigned', 'value': group['user_id_count']})
110+ res[project.id] = data
111+ return res
112
113 # Lambda indirection method to avoid passing a copy of the overridable method when declaring the field
114 _alias_models = lambda self, *args, **kwargs: self._get_alias_models(*args, **kwargs)
115@@ -256,6 +316,8 @@
116 }),
117 'resource_calendar_id': fields.many2one('resource.calendar', 'Working Time', help="Timetable working hours to adjust the gantt diagram report", states={'close':[('readonly',True)]} ),
118 'type_ids': fields.many2many('project.task.type', 'project_task_type_rel', 'project_id', 'type_id', 'Tasks Stages', states={'close':[('readonly',True)], 'cancelled':[('readonly',True)]}),
119+ 'monthly_task':fields.function(_get_task_data,type='string',string="monthly task",readonly=True),
120+
121 'task_count': fields.function(_task_count, type='integer', string="Tasks",),
122 'task_ids': fields.one2many('project.task', 'project_id',
123 domain=[('stage_id.fold', '=', False)]),
124@@ -267,19 +329,21 @@
125 help="The kind of document created when an email is received on this project's email alias"),
126 'privacy_visibility': fields.selection(_visibility_selection, 'Privacy / Visibility', required=True,
127 help="Holds visibility of the tasks or issues that belong to the current project:\n"
128- "- Public: everybody sees everything; if portal is activated, portal users\n"
129- " see all tasks or issues; if anonymous portal is activated, visitors\n"
130- " see all tasks or issues\n"
131- "- Portal (only available if Portal is installed): employees see everything;\n"
132- " if portal is activated, portal users see the tasks or issues followed by\n"
133+ "- Public Project: everybody sees everything; if portal is activated, portal users\n"
134+ " can see all tasks or issues; if anonymous portal is activated, visitors\n"
135+ " can see all tasks or issues\n"
136+ "-Customer Related Project: employees can see everything;\n"
137+ " if portal is activated, portal users can see the tasks or issues followed by\n"
138 " them or by someone of their company\n"
139- "- Employees Only: employees see all tasks or issues\n"
140- "- Followers Only: employees see only the followed tasks or issues; if portal\n"
141+ "- Internal Project: employees can see all tasks or issues\n"
142+ "- Private Project: employees see only the followed tasks or issues; if portal\n"
143 " is activated, portal users see the followed tasks or issues."),
144- 'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'), ('cancelled', 'Cancelled'),('pending','Pending'),('close','Closed')], 'Status', required=True,),
145+ 'state': fields.selection([('template', 'Template'),('draft','New'),('open','In Progress'),('pending','Pending'),('close','Closed'),('cancelled', 'Cancelled')], 'Status', required=True,),
146 'doc_count': fields.function(
147 _get_attached_docs, string="Number of documents attached", type='integer'
148- )
149+ ),
150+ 'task_per_user':fields.function(_get_tasks_per_user,type='string',string="monthly issue",readonly=True),
151+
152 }
153
154 def _get_type_common(self, cr, uid, context):
155@@ -310,7 +374,7 @@
156 ]
157
158 def set_template(self, cr, uid, ids, context=None):
159- return self.setActive(cr, uid, ids, value=False, context=context)
160+ return self.setActive(cr, uid, ids, value=False, state=False, context=context)
161
162 def set_done(self, cr, uid, ids, context=None):
163 return self.write(cr, uid, ids, {'state': 'close'}, context=context)
164@@ -325,7 +389,15 @@
165 return self.write(cr, uid, ids, {'state': 'open'}, context=context)
166
167 def reset_project(self, cr, uid, ids, context=None):
168- return self.setActive(cr, uid, ids, value=True, context=context)
169+ return self.setActive(cr, uid, ids, value=True, state=False, context=context)
170+
171+ def set_inactive(self, cr, uid, ids, context=None):
172+ self.write(cr, uid, ids, {'active': False}, context=context)
173+ return self.setActive(cr, uid, ids, value=False, state=True, context=context)
174+
175+ def set_active(self, cr, uid, ids, context=None):
176+ self.write(cr, uid, ids, {'active': True}, context=context)
177+ return self.setActive(cr, uid, ids, value=True, state=True, context=context)
178
179 def map_tasks(self, cr, uid, old_project_id, new_project_id, context=None):
180 """ copy and map tasks from old to new project """
181@@ -412,17 +484,17 @@
182 }
183
184 # set active value for a project, its sub projects and its tasks
185- def setActive(self, cr, uid, ids, value=True, context=None):
186+ def setActive(self, cr, uid, ids, value=True, state=False, context=None):
187 task_obj = self.pool.get('project.task')
188 for proj in self.browse(cr, uid, ids, context=None):
189- self.write(cr, uid, [proj.id], {'state': value and 'open' or 'template'}, context)
190+ self.write(cr, uid, [proj.id], {'state': state and 'close' or value and 'open' or 'template'}, context)
191 cr.execute('select id from project_task where project_id=%s', (proj.id,))
192 tasks_id = [x[0] for x in cr.fetchall()]
193 if tasks_id:
194 task_obj.write(cr, uid, tasks_id, {'active': value}, context=context)
195 child_ids = self.search(cr, uid, [('parent_id','=', proj.analytic_account_id.id)])
196 if child_ids:
197- self.setActive(cr, uid, child_ids, value, context=None)
198+ self.setActive(cr, uid, child_ids, value, state, context=None)
199 return True
200
201 def _schedule_header(self, cr, uid, ids, force_members=True, context=None):
202@@ -737,6 +809,20 @@
203 if work.task_id: result[work.task_id.id] = True
204 return result.keys()
205
206+ def _get_attachments(self, cr, uid, ids, field_name, arg, context):
207+ res = {}
208+ allow_extensions = ['.jpg','.png','jpeg','.gif']
209+ message_obj = self.pool['mail.message']
210+ #show only image type attachments order by votes.
211+ for result in self.browse(cr, uid, ids, context=context):
212+ messages = message_obj.search(cr, uid, [('res_id','=',result.id),('model','=','project.task'),('attachment_ids', '!=', False)], context=context)
213+ attacments = []
214+ for message in message_obj.browse(cr, uid, messages, context=context):
215+ attacments += [(attachment.id,len(message.vote_user_ids)) for attachment in message.attachment_ids if attachment.datas_fname[-4:].lower() in allow_extensions]
216+ attachment_ids = sorted(attacments, key=lambda element: (element[1]), reverse=True)
217+ res[result.id] = [attachment[0] for attachment in attachment_ids]
218+ return res
219+
220 _columns = {
221 'active': fields.function(_is_template, store=True, string='Not a Template Task', type='boolean', help="This field is computed automatically and have the same behavior than the boolean 'active' field: if the task is linked to a template or unactivated project, it will be hidden unless specifically asked."),
222 'name': fields.char('Task Summary', track_visibility='onchange', size=128, required=True, select=True),
223@@ -794,6 +880,7 @@
224 'id': fields.integer('ID', readonly=True),
225 'color': fields.integer('Color Index'),
226 'user_email': fields.related('user_id', 'email', type='char', string='User Email', readonly=True),
227+ 'attachment_ids':fields.function(_get_attachments, type='many2many', relation="ir.attachment", string="Attachments", readonly=True),
228 }
229 _defaults = {
230 'stage_id': _get_default_stage_id,
231
232=== added file 'project/project_onboarding_data.xml'
233--- project/project_onboarding_data.xml 1970-01-01 00:00:00 +0000
234+++ project/project_onboarding_data.xml 2014-05-15 11:32:23 +0000
235@@ -0,0 +1,159 @@
236+<?xml version="1.0" encoding="utf-8"?>
237+<openerp>
238+ <data noupdate="1">
239+ <!-- Users -->
240+ <record id="project_onboarding_user1" model="res.users">
241+ <field name="name">Stefi</field>
242+ <field name="login">stefi</field>
243+ </record>
244+ <record id="project_onboarding_user2" model="res.users">
245+ <field name="name">Jyan</field>
246+ <field name="login">jyan</field>
247+ </record>
248+
249+ <!-- Onboarding Project-->
250+ <record id="project_project_onboard" model="project.project">
251+ <field name="sequence">1</field>
252+ <field name="name">Let's Discover the app: Click to enter in project</field>
253+ <field name="alias_model">project.task</field>
254+ <field name="privacy_visibility">followers</field>
255+ <field name="date" eval="DateTime.today()"/>
256+ <field name="members" eval="[(6, 0, [ ref('base.user_root'), ref('project_onboarding_user1'), ref('project_onboarding_user2')])]"/>
257+ </record>
258+
259+ <!-- Tasks -->
260+ <record id="project_onboard_task_1" model="project.task">
261+ <field name="project_id" ref="project.project_project_onboard"/>
262+ <field name="name">Drag the sticker anyway</field>
263+ <field name="description">Edit column to match your project process. You can edit or delete column directly from the column view. Then drag and drop any task through your process.</field>
264+ <field name="stage_id" ref="project_tt_analysis"/>
265+ <field name="planned_hours">1</field>
266+ <field name="user_id" ref="project_onboarding_user1"/>
267+ <field name="color">3</field>
268+ </record>
269+
270+ <!-- Attachment in comment -->
271+ <record id="message_onboard_task_1_attachment" model="ir.attachment">
272+ <field name="datas_fname">project_dragdrop.jpeg</field>
273+ <field name="name">project_dragdrop</field>
274+ <field name="datas" type="base64" file="project/static/src/img/project_dragdrop.jpeg"/>
275+ <field name="res_id" ref="project_onboard_task_1"/>
276+ <field name="res_model">project.task</field>
277+ </record>
278+
279+ <record id="message_onboard_task_1" model="mail.message">
280+ <field name="model">project.task</field>
281+ <field name="res_id" ref="project_onboard_task_1"/>
282+ <field name="type">comment</field>
283+ <field name="author_id" ref="base.partner_root"/>
284+ <field name="attachment_ids" eval="[(6, 0, [ref('message_onboard_task_1_attachment')])]"/>
285+ </record>
286+
287+ <record id="project_onboard_task_2" model="project.task">
288+ <field name="project_id" ref="project.project_project_onboard"/>
289+ <field name="name">Invite people to your project</field>
290+ <field name="description">invite people to your project by just adding them as the follower of the project</field>
291+ <field name="stage_id" ref="project_tt_analysis"/>
292+ <field name="planned_hours">1</field>
293+ <field name="color">3</field>
294+ </record>
295+
296+ <record id="project_onboard_task_3" model="project.task">
297+ <field name="project_id" ref="project.project_project_onboard"/>
298+ <field name="name">Collaborate with your team and track history</field>
299+ <field name="description">By following the project, you follow each task of this project. You never loose the information and discussion. Add some note to remember what to do at a next stage. And keep your customer informed about the project advancement. </field>
300+ <field name="stage_id" ref="project_tt_specification"/>
301+ <field name="planned_hours">1</field>
302+ <field name="user_id" ref="project_onboarding_user1"/>
303+ <field name="color">3</field>
304+ </record>
305+
306+ <record id="project_onboard_task_4" model="project.task">
307+ <field name="project_id" ref="project.project_project_onboard"/>
308+ <field name="name">Track blocking state</field>
309+ <field name="description">If one of your collaborator is blocked as well as ready to chnage the stage of the task, the little collored bullet allow him to tell he is blocking and the history let him write the reason. </field>
310+ <field name="stage_id" ref="project_tt_specification"/>
311+ <field name="planned_hours">1</field>
312+ <field name="color">3</field>
313+ </record>
314+
315+ <record id="project_onboard_task_5" model="project.task">
316+ <field name="project_id" ref="project.project_project_onboard"/>
317+ <field name="name">Add some features from Settings -> Configuration -> Project</field>
318+ <field name="description">The application allows you to organize your work process. You can also track time, invoice project and describe the work in a collaborative note pad.</field>
319+ <field name="stage_id" ref="project_tt_development"/>
320+ <field name="user_id" ref="project_onboarding_user2"/>
321+ <field name="planned_hours">1</field>
322+ <field name="color">3</field>
323+ </record>
324+
325+ <!-- Attachment in comment -->
326+ <record id="message_onboard_task_5_attachment" model="ir.attachment">
327+ <field name="datas_fname">project_dragdrop.jpeg</field>
328+ <field name="name">project_dragdrop</field>
329+ <field name="datas" type="base64" file="project/static/src/img/more_feature.jpeg"/>
330+ <field name="res_id" ref="project_onboard_task_5"/>
331+ <field name="res_model">project.task</field>
332+ </record>
333+
334+ <record id="message_onboard_task_5" model="mail.message">
335+ <field name="model">project.task</field>
336+ <field name="res_id" ref="project_onboard_task_5"/>
337+ <field name="type">comment</field>
338+ <field name="author_id" ref="base.partner_root"/>
339+ <field name="attachment_ids" eval="[(6, 0, [ref('message_onboard_task_5_attachment')])]"/>
340+ </record>
341+
342+ <record id="project_onboard_task_6" model="project.task">
343+ <field name="project_id" ref="project.project_project_onboard"/>
344+ <field name="name">Create your own project</field>
345+ <field name="description">Quick start to create new project and easily mange it.</field>
346+ <field name="stage_id" ref="project_tt_development"/>
347+ <field name="planned_hours">1</field>
348+ <field name="user_id" ref="project_onboarding_user1"/>
349+ <field name="color">3</field>
350+ </record>
351+
352+ <record id="project_onboard_task_7" model="project.task">
353+ <field name="project_id" ref="project.project_project_onboard"/>
354+ <field name="name">Desactivate a project</field>
355+ <field name="description">When your project is completed then Desactivate the Project.</field>
356+ <field name="stage_id" ref="project_tt_testing"/>
357+ <field name="planned_hours">1</field>
358+ <field name="color">3</field>
359+ </record>
360+
361+ <record id="project_onboard_task_8" model="project.task">
362+ <field name="project_id" ref="project.project_project_onboard"/>
363+ <field name="name">Worklog entry</field>
364+ <field name="description">Users can do worklog entrys on task and issue from which you can create direct invoice.</field>
365+ <field name="stage_id" ref="project_tt_design"/>
366+ <field name="planned_hours">1</field>
367+ <field name="user_id" ref="project_onboarding_user2"/>
368+ <field name="sequence">10</field>
369+ <field name="color">3</field>
370+ </record>
371+
372+ <record id="project_onboard_task_9" model="project.task">
373+ <field name="project_id" ref="project.project_project_onboard"/>
374+ <field name="name">Manage accounting based on work entrys</field>
375+ <field name="description">When you will create new project new analytic account for that project will be create to simply manage accounting. you can directly create invoice from worklog entrys.</field>
376+ <field name="stage_id" ref="project_tt_design"/>
377+ <field name="user_id" ref="project_onboarding_user1"/>
378+ <field name="planned_hours">20</field>
379+ <field name="sequence">1</field>
380+ <field name="color">3</field>
381+ </record>
382+
383+ <record id="project_onboard_task_10" model="project.task">
384+ <field name="project_id" ref="project.project_project_onboard"/>
385+ <field name="name">Contract with customer</field>
386+ <field name="description">You can directly create contract with your customer and mange task,issue and timesheets.</field>
387+ <field name="stage_id" ref="project_tt_design"/>
388+ <field name="planned_hours">1</field>
389+ <field name="sequence">30</field>
390+ <field name="color">3</field>
391+ </record>
392+
393+ </data>
394+</openerp>
395
396=== modified file 'project/project_view.xml'
397--- project/project_view.xml 2014-05-08 15:34:32 +0000
398+++ project/project_view.xml 2014-05-15 11:32:23 +0000
399@@ -23,6 +23,8 @@
400 <separator/>
401 <filter string="My Tasks" domain="[('user_id','=',uid)]"/>
402 <separator/>
403+ <filter string="Task(s) Following" name="following" domain="[('message_is_follower','=',True)]" help="Tasks which I am following" icon="terp-personal"/>
404+ <separator/>
405 <filter string="Unread Messages" name="message_unread" domain="[('message_unread','=',True)]"/>
406 <separator/>
407 <filter string="Deadlines" context="{'deadline_visible': False}" domain="[('date_deadline','&lt;&gt;',False)]"
408@@ -63,6 +65,17 @@
409 </field>
410 </record>
411
412+ <record id="act_project_project_create_project_task" model="ir.actions.act_window">
413+ <field name="name">Tasks</field>
414+ <field name="res_model">project.task</field>
415+ <field name="view_mode">form,kanban,tree,calendar,gantt,graph</field>
416+ <field name="context">{'search_default_project_id': [active_id],
417+ 'default_project_id': active_id,
418+ 'active_test': False,
419+ }</field>
420+ <field name="search_view_id" ref="view_task_search_form"/>
421+ </record>
422+
423 <!-- Project -->
424 <record id="edit_project" model="ir.ui.view">
425 <field name="name">project.project.form</field>
426@@ -70,49 +83,43 @@
427 <field name="arch" type="xml">
428 <form string="Project" version="7.0">
429 <header>
430- <button name="set_open" string="Re-open project" type="object" states="pending" class="oe_highlight" groups="base.group_user"/>
431- <button name="set_done" string="Close Project" type="object" states="open,pending" groups="base.group_user"/>
432- <button name="set_open" string="Re-open project" type="object" states="cancelled,close" groups="base.group_user"/>
433- <button name="set_pending" string="Pending" type="object" states="open" groups="base.group_user"/>
434- <button name="set_template" string="Set as Template" type="object" states="open" groups="base.group_user"/>
435 <button string="New Project Based on Template" name="duplicate_template" type="object" states="template" context="{'parent_id':parent_id}" class="oe_highlight" groups="base.group_user"/>
436- <button name="reset_project" string="Reset as Project" type="object" states="template" class="oe_highlight" groups="base.group_user"/>
437- <button name="set_cancel" string="Cancel Project" type="object" states="open,pending" groups="base.group_user"/>
438- <field name="state" widget="statusbar" statusbar_visible="open,close" statusbar_colors='{"pending":"blue"}' readonly="1"/>
439+ <field name="state" widget="statusbar" clickable="True" attrs="{'invisible':[('state','=','template')]}" statusbar_visible="draft,open,pending,close,cancelled"/>
440 </header>
441 <sheet string="Project">
442+ <div name="Success" class="alert alert-success" attrs="{'invisible':['|',('state','=','template'),('task_count','!=',0)]}">
443+ Till You have not created any Task, <button name="%(act_project_project_create_project_task)d" type="action" string="Click here" class="oe_link"/> to create.
444+ </div>
445 <field name="analytic_account_id" invisible="1" required="0"/>
446 <div class="oe_title">
447 <label for="name" class="oe_edit_only" string="Project Name"/>
448 <h1>
449 <field name="name" string="Project Name"/>
450 </h1>
451- <div name="options_active">
452+ <div name="options_active" invisible="1">
453 <field name="use_tasks" class="oe_inline"/>
454 <label for="use_tasks"/>
455 </div>
456 </div>
457 <div class="oe_right oe_button_box" name="buttons" groups="base.group_user">
458- <button class="oe_inline oe_stat_button" type="action" attrs="{'invisible':[('use_tasks','=', 0)]}"
459+ <button class="oe_inline oe_stat_button" type="action" attrs="{'invisible':[('use_tasks','=', 0)]}"
460 name="%(act_project_project_2_project_task_all)d" icon="fa-tasks">
461 <field string="Tasks" name="task_count" widget="statinfo"/>
462 </button>
463- <button class="oe_inline oe_stat_button" name="attachment_tree_view" type="object" icon="fa-files-o">
464+ <button class="oe_inline oe_stat_button" name="attachment_tree_view" type="object" icon="fa-files-o">
465 <field string="Documents" name="doc_count" widget="statinfo"/>
466 </button>
467+ <button class="oe_inline oe_stat_button" name="set_inactive" string="Deactivate" type="object" icon="fa-edit" attrs="{'invisible':['|',('state','!=','close'),('active','=', False)]}"/>
468+ <button class="oe_inline oe_stat_button" name="set_active" string="Activate" type="object" icon="fa-edit" attrs="{'invisible':['|',('state','!=','close'),('active','=', True)]}"/>
469+ <button class="oe_inline oe_stat_button" name="set_template" icon="fa-code-fork" string="Set as Template" type="object" states="open" groups="base.group_user"/>
470+ <button class="oe_inline oe_stat_button oe_highlight" name="reset_project" icon="fa-external-link" string="Reset as Project" type="object" states="template" groups="base.group_user"/>
471 </div>
472 <group>
473 <group col="4">
474 <field name="user_id" string="Project Manager"
475 attrs="{'readonly':[('state','in',['close', 'cancelled'])]}"
476 context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'project.group_project_manager']}"/>
477- <newline/>
478- <field name="partner_id" on_change="onchange_partner_id(partner_id)"/>
479 </group>
480- <p attrs="{'invisible': [('analytic_account_id','=',False)]}">
481- To invoice or setup invoicing and renewal options, go to the related contract:
482- <field name="analytic_account_id" readonly="1" required="0" class="oe_inline" nolabel="1"/>.
483- </p>
484 <group name="group_alias"
485 attrs="{'invisible': [('alias_domain', '=', False)]}">
486 <label for="alias_name" string="Email Alias"/>
487@@ -130,7 +137,7 @@
488 </group>
489 </group>
490 <notebook>
491- <page string="Team" name="team">
492+ <page string="Team Members" name="team">
493 <field colspan="4" name="members" widget="many2many_kanban" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'group_project_user']}">
494 <kanban quick_create="false" create="true" delete="true">
495 <field name="name"/>
496@@ -152,26 +159,47 @@
497 </page>
498 <page string="Other Info">
499 <group string="Administration">
500- <field name="privacy_visibility" widget="radio"/>
501- <field name="planned_hours" widget="float_time"
502- groups="project.group_time_work_estimation_tasks"/>
503- <field name="effective_hours" widget="float_time"
504- groups="project.group_time_work_estimation_tasks"/>
505- <field name="resource_calendar_id"
506- groups="project.group_time_work_estimation_tasks"/>
507+ <group>
508+ <field name="planned_hours" widget="float_time"
509+ groups="project.group_time_work_estimation_tasks"/>
510+ <field name="effective_hours" widget="float_time"
511+ groups="project.group_time_work_estimation_tasks"/>
512+ <field name="resource_calendar_id"
513+ groups="project.group_time_work_estimation_tasks"/>
514+ </group>
515+ <group>
516+ <field name="privacy_visibility" widget="radio"/>
517+ </group>
518 </group>
519 <group string="Miscellaneous" name="misc">
520- <field name="date_start"/>
521- <field name="date" string="End Date"/>
522- <field name="sequence" groups="base.group_no_one"/>
523- <field name="active" attrs="{'invisible':[('state','in',['open', 'pending', 'template'])]}"/>
524- <field name="currency_id" groups="base.group_multi_currency" required="1"/>
525- <field name="parent_id" string="Parent" help="Append this project to another one using analytic accounts hierarchy" domain="[('id','!=',analytic_account_id)]" context="{'current_model': 'project.project'}" />
526+ <group>
527+ <field name="date_start"/>
528+ <field name="date" string="End Date"/>
529+ </group>
530+ <group>
531+ <field name="sequence" groups="base.group_no_one"/>
532+ <field name="active" attrs="{'invisible':[('state','in',['open', 'pending', 'template'])]}"/>
533+ <field name="currency_id" groups="base.group_multi_currency" required="1"/>
534+ <field name="parent_id" string="Parent" help="Append this project to another one using analytic accounts hierarchy" domain="[('id','!=',analytic_account_id)]" context="{'current_model': 'project.project'}" />
535+ </group>
536 </group>
537 </page>
538 <page string="Project Stages" attrs="{'invisible': [('use_tasks', '=', False)]}" name="project_stages">
539 <field name="type_ids"/>
540 </page>
541+ <page string="Billing" name="bill">
542+ <group>
543+ <group>
544+ <field name="partner_id" on_change="onchange_partner_id(partner_id)" />
545+ </group>
546+ </group>
547+ <group>
548+ <p attrs="{'invisible': [('analytic_account_id','=',False)]}">
549+ To invoice or setup invoicing and renewal options, go to the related contract:
550+ <field name="analytic_account_id" readonly="1" required="0" class="oe_inline" nolabel="1"/>.
551+ </p>
552+ </group>
553+ </page>
554 </notebook>
555 </sheet>
556 <div class="oe_chatter">
557@@ -193,10 +221,13 @@
558 <filter icon="terp-check" string="Open" name="Current" domain="[('state', '=','open')]" help="Open Projects"/>
559 <filter icon="gtk-media-pause" string="Pending" name="Pending" domain="[('state', '=','pending')]" help="Pending Projects"/>
560 <filter icon="gtk-media-pause" string="Template" name="Template" domain="[('state', '=','template')]" help="Templates of Projects"/>
561+ <filter string="Deactive" name="deactive" domain="[('active', '=',False)]" help="Deactive Projects"/>
562 <separator/>
563 <filter icon="terp-personal+" string="Member" domain="['|',('user_id', '=', uid),('members', '=', uid)]" help="Projects in which I am a member."/>
564 <separator/>
565- <filter string="Project(s) Manager" domain="[('user_id','=',uid)]" help="Projects in which I am a manager" icon="terp-personal"/>
566+ <filter string="Project(s) Manager" name="manager" domain="[('user_id','=',uid)]" help="Projects in which I am a manager" icon="terp-personal"/>
567+ <separator/>
568+ <filter string="Project(s) Following" name="following" domain="[('message_is_follower','=',True)]" help="Projects which I am following" icon="terp-personal"/>
569 <field name="user_id" string="Project Manager"/>
570 <field name="partner_id" string="Contact" filter_domain="[('partner_id', 'child_of', self)]"/>
571 <group expand="0" string="Group By...">
572@@ -247,6 +278,7 @@
573 <field name="task_ids"/>
574 <field name="alias_id"/>
575 <field name="doc_count"/>
576+ <field name="task_per_user"/>
577 <templates>
578 <t t-name="kanban-box">
579 <div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_project oe_kanban_global_click">
580@@ -258,21 +290,15 @@
581 <li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
582 </ul>
583 </div>
584- <div class="oe_kanban_content">
585- <h4><field name="name"/></h4>
586- <div class="oe_kanban_alias" t-if="record.alias_id.value">
587- <span class="oe_e oe_e_alias">%%</span><small><field name="alias_id"/></small>
588- </div>
589- <div class="oe_kanban_project_list">
590- <a t-if="record.use_tasks.raw_value" name="%(act_project_project_2_project_task_all)d" type="action" style="margin-right: 10px">
591- <t t-raw="record.task_ids.raw_value.length"/> Tasks
592- </a>
593- </div>
594- <div class="oe_kanban_project_list">
595- <a t-if="record.doc_count.raw_value" name="attachment_tree_view" type="object" style="margin-right: 10px"> <field name="doc_count"/> Documents</a>
596- </div>
597- <div class="oe_kanban_footer_left">
598- <span groups="project.group_time_work_estimation_tasks">
599+ <div class="project_kanban_content">
600+ <div class="row">
601+ <h4><field name="name"/></h4>
602+ <div class="oe_kanban_alias" t-if="record.alias_id.value">
603+ <span class="oe_e oe_e_alias">%%</span><small><field name="alias_id"/></small>
604+ </div>
605+ </div>
606+ <div class="row oe_kanban_footer_left">
607+ <span groups="project.group_time_work_estimation_tasks" t-if="record.planned_hours.raw_value != 0">
608 <span class="oe_e">R</span>
609 <t t-esc="Math.round(record.effective_hours.raw_value)"/>/<t t-esc="Math.round(record.planned_hours.raw_value)"/> <field name="company_uom_id"/>
610 </span>
611@@ -281,10 +307,30 @@
612 <field name="date"/>
613 </span>
614 </div>
615- <div class="oe_kanban_project_avatars">
616- <t t-foreach="record.members.raw_value.slice(0,11)" t-as="member">
617- <img t-att-src="kanban_image('res.users', 'image_small', member)" t-att-data-member_id="member"/>
618- </t>
619+ <div class="row" name="docs" style="margin-top: 6px">
620+ <a t-if="record.doc_count.raw_value" name="attachment_tree_view" type="object" style="margin-right: 10px"> <field name="doc_count"/> Documents</a>
621+ </div>
622+ <div class="row oe_kanban_project_list">
623+ <a t-if="record.use_tasks.raw_value and record.task_ids.raw_value.length >= 1" name="%(act_project_project_2_project_task_all)d" type="action" class="row col-md-5">
624+ <t t-raw="record.task_ids.raw_value.length"/>
625+ <span t-if="record.task_ids.raw_value.length == 1">Task</span>
626+ <span t-if="record.task_ids.raw_value.length > 1">Tasks</span>
627+ <a class="row col-md-3">
628+ <field name="monthly_task" widget="sparkline_bar"
629+ options="{'height': '20px', 'barWidth': 4, 'barSpacing': 1, 'delayIn': '3000', 'tooltip_suffix': ' Task'}">Created Task per Month</field>
630+ </a>
631+ </a>
632+ </div>
633+ <div class="row">
634+ <div t-if="record.use_tasks.raw_value and record.task_ids.raw_value.length >= 1" class="row col-md-7">
635+ <div class="oe_project_graph">
636+ <field name="task_per_user" class="oe_project_graph" widget="project_graph"/>
637+ </div>
638+ <div class="row text-center">
639+ <strong><span>Tasks Per User</span></strong>
640+ </div>
641+ </div>
642+ <div class="oe_issue_graph row col-md-6"/>
643 </div>
644 </div>
645 </div>
646@@ -311,7 +357,7 @@
647 <field name="view_mode">kanban,tree,form,gantt</field>
648 <field name="view_id" ref="view_project_kanban"/>
649 <field name="search_view_id" ref="view_project_project_filter"/>
650- <field name="context">{'search_default_Current': 1}</field>
651+ <field name="context">{'search_default_manager': 1,'search_default_following': 1}</field>
652 <field name="help" type="html">
653 <p class="oe_view_nocontent_create">
654 Click to start a new project.
655@@ -486,6 +532,7 @@
656 <field name="date_deadline"/>
657 <field name="message_summary"/>
658 <field name="categ_ids"/>
659+ <field name="attachment_ids"/>
660 <templates>
661 <t t-name="kanban-box">
662 <div t-attf-class="oe_kanban_color_#{kanban_getcolor(record.color.raw_value)} oe_kanban_card oe_kanban_global_click">
663@@ -507,30 +554,38 @@
664 </ul>
665 </div>
666
667- <div class="oe_kanban_content">
668- <div><b><field name="name"/></b></div>
669- <div>
670- <field name="project_id"/><br/>
671+ <div class="project_kanban_content">
672+ <div class="row"><b><field name="name"/></b></div>
673+ <div class="row">
674+ <field name="project_id" invisible="context.get('search_default_project_id', False)"/>
675 <t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kanban_text_red</t>
676 <span t-attf-class="#{red || ''}"><i><field name="date_deadline"/></i></span>
677 </div>
678- <div class="oe_kanban_footer_left">
679- <span groups="project.group_time_work_estimation_tasks" title="Remaining hours">
680+ <div class="row oe_kanban_bottom_right">
681+ <t groups="base.group_user">
682+ <a t-if="record.kanban_state.raw_value === 'normal'" type="object" string="In Progress" name="set_kanban_state_done" class="oe_kanban_status"> </a>
683+ <a t-if="record.kanban_state.raw_value === 'done'" type="object" string="Ready for next stage" name="set_kanban_state_blocked" class="oe_kanban_status oe_kanban_status_green"> </a>
684+ <a t-if="record.kanban_state.raw_value === 'blocked'" type="object" string="Blocked" name="set_kanban_state_normal" class="oe_kanban_status oe_kanban_status_red"> </a>
685+ <a t-if="record.priority.raw_value > 0" type="object" string="Normal" name="set_high_priority" class="oe_e oe_star_off">7</a>
686+ <a t-if="record.priority.raw_value == 0" type="object" string="Very Important" name="set_normal_priority" class="oe_e oe_star_on">7</a>
687+ </t>
688+ <img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar"/>
689+ </div>
690+ <div class="row oe_kanban_footer_left">
691+ <span groups="project.group_time_work_estimation_tasks" title="Remaining hours" t-if="record.remaining_hours.raw_value != 0">
692 <span class="oe_e">N</span>
693 <t t-esc="Math.round(record.remaining_hours.raw_value)"/>
694 </span>
695 </div>
696- <div class="oe_kanban_footer_left" style="margin-top:5px;">
697+ <div class="row oe_kanban_footer_left" style="margin-top:-5px;">
698 <t t-raw="record.message_summary.raw_value"/>
699 <field name="categ_ids"/>
700 </div>
701- <div class="oe_kanban_bottom_right">
702- <img t-att-src="kanban_image('res.users', 'image_small', record.user_id.raw_value)" t-att-title="record.user_id.value" width="24" height="24" class="oe_kanban_avatar pull-right"/>
703- <div class="pull-left" groups="base.group_user">
704- <field name="kanban_state" widget="kanban_state_selection"/>
705- <field name="priority" widget="priority"/>
706- </div>
707- </div>
708+ <div class="row">
709+ <t t-foreach="record.attachment_ids.raw_value.slice(0,3)" t-as="attachment_img">
710+ <img t-att-src="kanban_image('ir.attachment', 'datas', attachment_img)" class="oe_kanban_image" t-att-data-member_id="attachment_img"/>
711+ </t>
712+ </div>
713 </div>
714 <div class="oe_clear"></div>
715 </div>
716@@ -616,6 +671,7 @@
717 <field name="res_model">project.task</field>
718 <field name="view_mode">kanban,tree,form,calendar,gantt,graph</field>
719 <field name="search_view_id" ref="view_task_search_form"/>
720+ <field name="context">{'search_default_following': 1}</field>
721 <field name="help" type="html">
722 <p>
723 OpenERP's project management allows you to manage the pipeline
724
725=== modified file 'project/static/src/css/project.css'
726--- project/static/src/css/project.css 2013-10-27 12:31:04 +0000
727+++ project/static/src/css/project.css 2014-05-15 11:32:23 +0000
728@@ -1,65 +1,29 @@
729 .oe_kanban_project {
730- width: 220px;
731- min-height: 160px;
732+ width: 320px;
733+ min-height: 300px !important;
734+}
735+
736+.oe_kanban_project_list {
737+ margin-top: 5px;
738 }
739
740 .oe_kanban_project_list > a > span:hover{
741- margin: 4px 0;
742 text-decoration: underline;
743 }
744
745-.openerp .oe_kanban_content h4 {
746- margin: 0 0 8px;
747-}
748-
749-.oe_kanban_content > table {
750- width: 100%;
751-}
752-
753-.oe_kanban_content > table > th {
754- padding: 0;
755- border-right: 1px solid #DDD;
756- vertical-align: top;
757- font-weight: normal;
758-}
759-
760-.oe_kanban_content > table > td {
761- padding: 2px 0 2px 8px;
762- color: #888;
763-}
764-
765-.oe_kanban_content .oe_ellipsis {
766- overflow: hidden;
767- text-overflow: ellipsis;
768- max-height: 100px;
769-}
770-
771-.oe_kanban_project_fields div:nth-child(odd) {
772- border-right: 1px solid #dddddd;
773- vertical-align: top;
774- padding-right: 8px;
775-}
776-
777-.oe_kanban_project_fields div:nth-child(even) {
778- padding-left: 8px;
779- color: #888888;
780-}
781-
782-.oe_kanban_project_avatars {
783- margin-top: 8px;
784+.openerp .project_kanban_content{
785+ margin-right: 15px;
786+ margin-left: 15px;
787 }
788
789 .oe_kanban_project_avatars img {
790 width: 30px;
791- height: 30px;
792- padding-left: 0px;
793- margin-top: 3px;
794- -moz-border-radius: 2px;
795- -webkit-border-radius: 2px;
796 border-radius: 2px;
797 -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
798 -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
799 -box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
800 }
801
802-
803+.oe_project_graph {
804+ margin-left: -12px;
805+}
806
807=== added file 'project/static/src/img/more_feature.jpeg'
808Binary files project/static/src/img/more_feature.jpeg 1970-01-01 00:00:00 +0000 and project/static/src/img/more_feature.jpeg 2014-05-15 11:32:23 +0000 differ
809=== added file 'project/static/src/img/project_dragdrop.jpeg'
810Binary files project/static/src/img/project_dragdrop.jpeg 1970-01-01 00:00:00 +0000 and project/static/src/img/project_dragdrop.jpeg 2014-05-15 11:32:23 +0000 differ
811=== modified file 'project/static/src/js/project.js'
812--- project/static/src/js/project.js 2014-04-17 09:05:15 +0000
813+++ project/static/src/js/project.js 2014-05-15 11:32:23 +0000
814@@ -1,4 +1,5 @@
815 openerp.project = function(openerp) {
816+ openerp.project.GraphKanban(openerp);
817 openerp.web_kanban.KanbanView.include({
818 project_display_members_names: function() {
819 /*
820
821=== added file 'project/static/src/js/project_graph.js'
822--- project/static/src/js/project_graph.js 1970-01-01 00:00:00 +0000
823+++ project/static/src/js/project_graph.js 2014-05-15 11:32:23 +0000
824@@ -0,0 +1,30 @@
825+openerp.project.GraphKanban = function (instance)
826+{
827+ var _t = instance.web._t,
828+ _lt = instance.web._lt;
829+ instance.web_kanban.ProjectGraph = instance.web_kanban.AbstractField.extend({
830+ start: function() {
831+ var self = this;
832+ self.display_graph(self.field.raw_value);
833+ },
834+ display_graph : function(data) {
835+ var self = this;
836+ nv.addGraph(function () {
837+ self.$el.append('<svg>');
838+ var chart = nv.models.pieChart()
839+ .x(function(d) { return d.label; })
840+ .y(function(d) { return d.value; })
841+ .showLabels(false)
842+ .showLegend(false)
843+ .width(170)
844+ .height(170);
845+ self.svg = self.$el.find('svg')[0];
846+ d3.select(self.svg)
847+ .datum(data)
848+ .transition().duration(350)
849+ .call(chart);
850+ });
851+ },
852+ });
853+ instance.web_kanban.fields_registry.add("project_graph", "instance.web_kanban.ProjectGraph");
854+};
855\ No newline at end of file
856
857=== modified file 'project/views/project.xml'
858--- project/views/project.xml 2014-04-24 17:21:29 +0000
859+++ project/views/project.xml 2014-05-15 11:32:23 +0000
860@@ -7,6 +7,7 @@
861 <xpath expr="." position="inside">
862 <link rel="stylesheet" href="/project/static/src/css/project.css"/>
863 <script type="text/javascript" src="/project/static/src/js/project.js"></script>
864+ <script type="text/javascript" src="/project/static/src/js/project_graph.js"></script>
865 </xpath>
866 </template>
867 </data>
868
869=== modified file 'project_issue/project_issue.py'
870--- project_issue/project_issue.py 2014-05-08 15:25:36 +0000
871+++ project_issue/project_issue.py 2014-05-15 11:32:23 +0000
872@@ -19,8 +19,9 @@
873 #
874 ##############################################################################
875
876-from datetime import datetime
877-
878+from datetime import datetime, date
879+import calendar
880+from dateutil import relativedelta
881 from openerp import SUPERUSER_ID
882 from openerp import tools
883 from openerp.addons.crm import crm
884@@ -474,13 +475,45 @@
885 project_id: Issue.search_count(cr,uid, [('project_id', '=', project_id), ('stage_id.fold', '=', False)], context=context)
886 for project_id in ids
887 }
888+
889+ def _get_issue_data(self, cr, uid, ids, field_name, arg, context=None):
890+ """ Get task-related data for project kanban view
891+ monthly_open_issue: number of open task during the last months
892+ """
893+ Issue = self.pool.get('project.issue')
894+ res = dict.fromkeys(ids, False)
895+ month_begin = date.today().replace(day=1)
896+ date_begin = month_begin - relativedelta.relativedelta(months=self._period_number - 1)
897+ date_end = month_begin.replace(day=calendar.monthrange(month_begin.year, month_begin.month)[1])
898+ project_pre_domain = [('date_closed', '>=', date_begin.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)),
899+ ('date_closed', '<=', date_end.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
900+ ]
901+ for id in ids:
902+ res[id] = dict()
903+ project_domain = project_pre_domain + [('project_id', '=', id)]
904+ res[id] = self.__get_bar_values(cr, uid, Issue, project_domain, ['date_closed'], 'date_closed_count', 'date_closed', context=context)
905+ return res
906+
907+ def _get_issues_per_user(self, cr, uid, ids, field_name, arg, context=None):
908+ res = dict.fromkeys(ids, False)
909+ Issue = self.pool.get('project.issue')
910+ for project in self.browse(cr, uid, ids, context=context):
911+ data = []
912+ group_obj = Issue.read_group(cr, uid, [('project_id','=',project.id)], ['user_id'], 'user_id', context=context)
913+ for group in group_obj:
914+ data.append({'label' : group['user_id'] and group['user_id'][1] or 'Unassigned', 'value': group['user_id_count']})
915+ res[project.id] = data
916+ return res
917+
918 _columns = {
919 'project_escalation_id': fields.many2one('project.project', 'Project Escalation',
920 help='If any issue is escalated from the current Project, it will be listed under the project selected here.',
921 states={'close': [('readonly', True)], 'cancelled': [('readonly', True)]}),
922 'issue_count': fields.function(_issue_count, type='integer', string="Issues",),
923 'issue_ids': fields.one2many('project.issue', 'project_id',
924- domain=[('stage_id.fold', '=', False)])
925+ domain=[('stage_id.fold', '=', False)]),
926+ 'monthly_issue':fields.function(_get_issue_data,type='string',string="Monthly issue",readonly=True),
927+ 'issue_per_user':fields.function(_get_issues_per_user,type='string',string="Issue per User",readonly=True),
928 }
929
930 def _check_escalation(self, cr, uid, ids, context=None):
931@@ -548,6 +581,14 @@
932 self._check_create_write_values(cr, uid, vals, context=context)
933 return super(project_project, self).write(cr, uid, ids, vals, context=context)
934
935+ def setActive(self, cr, uid, ids, value=True, state=False, context=None):
936+ super(project_project, self).setActive(cr, uid, ids, value, state, context=context)
937+ issue_obj = self.pool['project.issue']
938+ issue_ids = issue_obj.search(cr, uid, [('project_id','in', ids),'|',('active','=',True),('active','=',False)], context=context)
939+ if issue_ids:
940+ issue_obj.write(cr, uid, issue_ids, {'active': value}, context=context)
941+ return True
942+
943 class res_partner(osv.osv):
944 def _issue_count(self, cr, uid, ids, field_name, arg, context=None):
945 Issue = self.pool['project.issue']
946
947=== modified file 'project_issue/project_issue_data.xml'
948--- project_issue/project_issue_data.xml 2014-05-08 15:25:36 +0000
949+++ project_issue/project_issue_data.xml 2014-05-15 11:32:23 +0000
950@@ -92,6 +92,30 @@
951 <field name="parent_id" eval="ref('mt_issue_stage')"/>
952 <field name="relation_field">project_id</field>
953 </record>
954-
955+
956+ <!--Onboarding data -->
957+ <record id="project.project_project_onboard" model="project.project">
958+ <field name="use_issues" eval="True"/>
959+ </record>
960+
961+ <record id="project_issue_onboard_cate_1" model="project.category">
962+ <field name="name">Little problem</field>
963+ </record>
964+
965+ <record id="project_issue_onboard_1" model="project.issue">
966+ <field name="date" eval="DateTime.today()"/>
967+ <field name="priority">0</field>
968+ <field name="user_id" ref="base.user_root"/>
969+ <field eval="1" name="active"/>
970+ <field name="project_id" ref="project.project_project_onboard"/>
971+ <field eval="15.0" name="duration"/>
972+ <field name="name">Manage issues</field>
973+ <field name="description">To efficiantly manage things like internal requests, software development bugs, customer complaints, project troubles you can do it same way as task drag and drop, follow, invite users, block issue and in the end set as done.</field>
974+ <field name="email_from">issue@openerp.com</field>
975+ <field name="stage_id" ref="project.project_tt_specification"/>
976+ <field name="categ_ids" eval="[(6, 0, [
977+ ref('project_issue_onboard_cate_1')])]"/>
978+ </record>
979+
980 </data>
981 </openerp>
982
983=== modified file 'project_issue/project_issue_view.xml'
984--- project_issue/project_issue_view.xml 2014-05-08 15:34:32 +0000
985+++ project_issue/project_issue_view.xml 2014-05-15 11:32:23 +0000
986@@ -263,6 +263,7 @@
987 <field name="context">{
988 'search_default_project_id': [active_id],
989 'default_project_id': active_id,
990+ 'active_test': False,
991 }
992 </field>
993 <field name="help" type="html">
994@@ -297,6 +298,9 @@
995 <xpath expr='//field[@name="use_tasks"]' position="attributes">
996 <attribute name="attrs">{'on_change': 'on_change_use_tasks_or_issues(use_tasks, use_issues)'}</attribute>
997 </xpath>
998+ <xpath expr='//div[@name="options_active"]' position="attributes">
999+ <attribute name="invisible">False</attribute>
1000+ </xpath>
1001 <field name="sequence" position="before">
1002 <field name="project_escalation_id"/>
1003 </field>
1004@@ -311,15 +315,29 @@
1005 <field name="use_tasks" position="after">
1006 <field name="use_issues"/>
1007 <field name="issue_ids" invisible="1"/>
1008+ <field name="issue_per_user"/>
1009 </field>
1010 <xpath expr="//div[contains(@class, 'oe_kanban_project_list')]" position="inside">
1011- <a t-if="record.use_issues.raw_value" style="margin-right: 10px"
1012- name="%(act_project_project_2_project_issue_all)d" type="action">
1013+ <a t-if="record.use_issues.raw_value and record.issue_ids.raw_value.length >= 1" class="col-md-4" name="%(act_project_project_2_project_issue_all)d" type="action">
1014 <t t-raw="record.issue_ids.raw_value.length"/>
1015 <span t-if="record.issue_ids.raw_value.length == 1">Issue</span>
1016 <span t-if="record.issue_ids.raw_value.length > 1">Issues</span>
1017+ <a class="col-md-2">
1018+ <field name="monthly_issue" widget="sparkline_bar"
1019+ options="{'height': '20px', 'barWidth': 4, 'barSpacing': 1, 'delayIn': '3000', 'tooltip_suffix': ' Issue'}">Closed Issue per Month</field>
1020+ </a>
1021 </a>
1022 </xpath>
1023+ <xpath expr="//div[contains(@class, 'oe_issue_graph')]" position="replace">
1024+ <div t-if="record.use_issues.raw_value and record.issue_ids.raw_value.length >= 1" class="row col-md-7">
1025+ <div class="oe_project_graph">
1026+ <field name="issue_per_user" widget="project_graph"/>
1027+ </div>
1028+ <div class="row text-center">
1029+ <strong><span>Issues Per User</span></strong>
1030+ </div>
1031+ </div>
1032+ </xpath>
1033 </field>
1034 </record>
1035
1036
1037=== modified file 'project_timesheet/project_timesheet_view.xml'
1038--- project_timesheet/project_timesheet_view.xml 2014-04-15 12:57:15 +0000
1039+++ project_timesheet/project_timesheet_view.xml 2014-05-15 11:32:23 +0000
1040@@ -13,8 +13,8 @@
1041 <field name="currency_id"/>
1042 <field name="partner_id"/>
1043 </field>
1044- <xpath expr="//div[contains(@class, 'oe_kanban_project_list')]" position="inside">
1045- <a t-if="record.use_timesheets.raw_value" style="margin-right: 10px"
1046+ <xpath expr="//div[@name='docs']" position="inside">
1047+ <a t-if="record.use_timesheets.raw_value and record.hours_quantity.raw_value > 0"
1048 name="open_timesheets" type="object"><field name="hours_quantity"/> Hours</a>
1049 </xpath>
1050 </field>
1051@@ -33,6 +33,9 @@
1052 <button class="oe_inline oe_stat_button" name="open_timesheets" type="object" attrs="{'invisible':[('use_timesheets','=', 0)]}"
1053 icon="fa-calendar" string="Timesheets"/>
1054 </xpath>
1055+ <xpath expr='//div[@name="options_active"]' position="attributes">
1056+ <attribute name="invisible">False</attribute>
1057+ </xpath>
1058 </field>
1059 </record>
1060

Subscribers

People subscribed via source and target branches

to all changes: