Merge lp:~openerp-dev/openobject-addons/trunk-project-onboarding into lp:openobject-addons
- trunk-project-onboarding
- Merge into trunk
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+218955@code.launchpad.net |
Commit message
Description of the change
[TO UPDATE]
- 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
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','<>',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' |
808 | Binary 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' |
810 | Binary 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 |