Merge lp:~openerp-dev/openobject-addons/trunk-kanban-column-avo into lp:openobject-addons
- trunk-kanban-column-avo
- Merge into trunk
Status: | Needs review |
---|---|
Proposed branch: | lp:~openerp-dev/openobject-addons/trunk-kanban-column-avo |
Merge into: | lp:openobject-addons |
Diff against target: |
1150 lines (+663/-82) 20 files modified
crm/__init__.py (+1/-1) crm/crm.py (+65/-3) crm/crm_lead.py (+0/-2) crm/tests/__init__.py (+24/-0) crm/tests/test_crm_stages_case.py (+70/-0) hr_recruitment/__init__.py (+1/-1) hr_recruitment/hr_recruitment.py (+106/-41) hr_recruitment/hr_recruitment_data.xml (+6/-0) hr_recruitment/hr_recruitment_demo.xml (+6/-1) hr_recruitment/hr_recruitment_menu.xml (+28/-0) hr_recruitment/hr_recruitment_view.xml (+11/-26) hr_recruitment/tests/__init__.py (+24/-0) hr_recruitment/tests/test_hr_recruitment_stage.py (+71/-0) project/project.py (+61/-3) project/tests/__init__.py (+2/-1) project/tests/project_stage_management.py (+74/-0) project_issue/__init__.py (+1/-1) project_issue/project_issue.py (+10/-2) project_issue/tests/__init__.py (+28/-0) project_issue/tests/project_stage_management.py (+74/-0) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-addons/trunk-kanban-column-avo |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+214028@code.launchpad.net |
Commit message
Description of the change
Hello,
done the changes specified in pad. https:/
Thanks.
avo
- 9259. By Amit Vora(OpenERP)
-
[IMP] override copy method display stages in perticular parent
- 9260. By Amit Vora(OpenERP)
-
[MRG] merge with main branch
- 9261. By Amit Vora(OpenERP)
-
[IMP] resolve conflict
- 9262. By Amit Vora(OpenERP)
-
[MRG] merge with main branch
Unmerged revisions
- 9262. By Amit Vora(OpenERP)
-
[MRG] merge with main branch
- 9261. By Amit Vora(OpenERP)
-
[IMP] resolve conflict
- 9260. By Amit Vora(OpenERP)
-
[MRG] merge with main branch
- 9259. By Amit Vora(OpenERP)
-
[IMP] override copy method display stages in perticular parent
- 9258. By Amit Vora(OpenERP)
-
[IMP] add test cases for crm,hr_
recruitment, project - 9257. By Amit Vora(OpenERP)
-
[IMP] improve code add condition in mail_message
- 9256. By Amit Vora(OpenERP)
-
[IMP] assign value to variable
- 9255. By Amit Vora(OpenERP)
-
[IMP] in crm,project module give default value case_default and in hr_recruitment module add job_ids many2many field,Add Configuration menu of Recruitment: Stages, Degrees, Source of Applications,add new boolean field to indicate default stage on create new recruitment,update demo data of hr job with link of stages
- 9254. By Amit Vora(OpenERP)
-
[MERGE] merge with main branch
- 9253. By Amit Vora(OpenERP)
-
[MRG] merge with lp:~openerp-dev/openobject-addons/trunk-kanban-column-hr-avo
Preview Diff
1 | === modified file 'crm/__init__.py' |
2 | --- crm/__init__.py 2014-05-12 11:41:49 +0000 |
3 | +++ crm/__init__.py 2014-05-20 06:41:52 +0000 |
4 | @@ -30,6 +30,6 @@ |
5 | import res_partner |
6 | import res_config |
7 | import base_partner_merge |
8 | - |
9 | +import tests |
10 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
11 | |
12 | |
13 | === modified file 'crm/crm.py' |
14 | --- crm/crm.py 2014-05-14 15:21:54 +0000 |
15 | +++ crm/crm.py 2014-05-20 06:41:52 +0000 |
16 | @@ -77,16 +77,78 @@ |
17 | string='Type', size=16, required=True, |
18 | help="This field is used to distinguish stages related to Leads from stages related to Opportunities, or to specify stages available for both types."), |
19 | } |
20 | - |
21 | + def _get_default_section_ids(self, cr, uid, context=None): |
22 | + """ Gives default section by checking if present in the context """ |
23 | + section_id = self.pool.get('crm.lead')._resolve_section_id_from_context(cr, uid, context=context) or False |
24 | + return section_id and [section_id] or None |
25 | + |
26 | _defaults = { |
27 | 'sequence': 1, |
28 | 'probability': 0.0, |
29 | 'on_change': True, |
30 | 'fold': False, |
31 | 'type': 'both', |
32 | - 'case_default': True, |
33 | + 'section_ids': _get_default_section_ids, |
34 | + 'case_default': lambda self, cr, uid, ctx={}: ctx.get('default_section_id', False) == False, |
35 | } |
36 | - |
37 | + |
38 | + _sql_constraints = [('stage_name_uniq', 'unique(name)', 'Name should be unique.')] |
39 | + |
40 | + def copy(self, cr, uid, id, default=None, context=None): |
41 | + if context is None: |
42 | + context = {} |
43 | + if default is None: |
44 | + default = {} |
45 | + default['section_ids'] = [] |
46 | + section = self.browse(cr, uid, id, context=context) |
47 | + if not default.get('name', False): |
48 | + default.update(name=_("%s (copy)") % (section.name)) |
49 | + return super(crm_case_stage, self).copy(cr, uid, id, default, context) |
50 | + |
51 | + def create(self, cr, uid, vals, context=None): |
52 | + if context is None: context = {} |
53 | + section_id = context.get('default_section_id') |
54 | + type_id = False |
55 | + if section_id: |
56 | + #check already exist or not |
57 | + type_ids = self.search(cr, uid, [('name', '=', vals.get('name'))], context=context, limit=1) |
58 | + if type_ids and len(type_ids): |
59 | + type_id = type_ids[0] |
60 | + if not type_id: |
61 | + type_id = super(crm_case_stage, self).create(cr, uid, vals, context=context) |
62 | + return type_id |
63 | + |
64 | + def write(self, cr, uid, ids, vals, context=None): |
65 | + if context is None:context = {} |
66 | + section_id = context.get('default_section_id') |
67 | + section_obj = self.pool.get('crm.case.section') |
68 | + if section_id: |
69 | + context.update({'section_id': section_id}) |
70 | + if vals.get('name', False): |
71 | + for stage in self.browse(cr, uid, ids, context=context): |
72 | + new_stage_id = self.copy(cr, uid, stage.id, default=vals, context=context) |
73 | + section_obj.write(cr, uid, [section_id], {'stage_ids': [(3, stage.id),(4, new_stage_id),]}, context=context) |
74 | + self._update_leads(cr, uid, section_id, stage.id, new_stage_id, context=context) |
75 | + return True |
76 | + return super(crm_case_stage, self).write(cr, uid, ids, vals, context=context) |
77 | + |
78 | + def unlink(self, cr, uid, ids, context=None): |
79 | + if context is None: context = {} |
80 | + section_id = context.get('default_section_id') |
81 | + section_obj = self.pool.get('crm.case.section') |
82 | + if not section_id: |
83 | + return super(crm_case_stage, self).unlink(cr, uid, ids, context=context) |
84 | + |
85 | + for stage in self.browse(cr, uid, ids, context=context): |
86 | + section_obj.write(cr, uid, section_id, {'stage_ids': [(3, stage.id)]}, context=context) |
87 | + self._update_leads(cr, uid, section_id, stage.id, False, context=context) |
88 | + return True |
89 | + |
90 | + def _update_leads(self, cr, uid, section_id, old_stage_id, new_stage_id, context=None): |
91 | + if context is None: context = {} |
92 | + crm_lead_obj = self.pool.get('crm.lead') |
93 | + lead_ids = crm_lead_obj.search(cr, uid, [('stage_id', '=', old_stage_id),('section_id', '=', section_id)], context=context) |
94 | + return crm_lead_obj.write(cr, uid, lead_ids, {'stage_id': new_stage_id} , context=context) |
95 | |
96 | class crm_case_categ(osv.osv): |
97 | """ Category of Case """ |
98 | |
99 | === modified file 'crm/crm_lead.py' |
100 | --- crm/crm_lead.py 2014-05-12 11:41:49 +0000 |
101 | +++ crm/crm_lead.py 2014-05-20 06:41:52 +0000 |
102 | @@ -139,8 +139,6 @@ |
103 | if section_id: |
104 | search_domain += ['|', ('section_ids', '=', section_id)] |
105 | search_domain += [('id', 'in', ids)] |
106 | - else: |
107 | - search_domain += ['|', ('id', 'in', ids), ('case_default', '=', True)] |
108 | # retrieve type from the context (if set: choose 'type' or 'both') |
109 | type = self._resolve_type_from_context(cr, uid, context=context) |
110 | if type: |
111 | |
112 | === added directory 'crm/tests' |
113 | === added file 'crm/tests/__init__.py' |
114 | --- crm/tests/__init__.py 1970-01-01 00:00:00 +0000 |
115 | +++ crm/tests/__init__.py 2014-05-20 06:41:52 +0000 |
116 | @@ -0,0 +1,24 @@ |
117 | +# -*- coding: utf-8 -*- |
118 | +############################################################################## |
119 | +# |
120 | +# OpenERP, Open Source Business Applications |
121 | +# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com> |
122 | +# |
123 | +# This program is free software: you can redistribute it and/or modify |
124 | +# it under the terms of the GNU Affero General Public License as |
125 | +# published by the Free Software Foundation, either version 3 of the |
126 | +# License, or (at your option) any later version. |
127 | +# |
128 | +# This program is distributed in the hope that it will be useful, |
129 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
130 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
131 | +# GNU Affero General Public License for more details. |
132 | +# |
133 | +# You should have received a copy of the GNU Affero General Public License |
134 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
135 | +# |
136 | +############################################################################## |
137 | +from . import test_crm_stages_case |
138 | +checks = [ |
139 | + test_crm_stages_case, |
140 | + ] |
141 | \ No newline at end of file |
142 | |
143 | === added file 'crm/tests/test_crm_stages_case.py' |
144 | --- crm/tests/test_crm_stages_case.py 1970-01-01 00:00:00 +0000 |
145 | +++ crm/tests/test_crm_stages_case.py 2014-05-20 06:41:52 +0000 |
146 | @@ -0,0 +1,70 @@ |
147 | +# -*- coding: utf-8 -*- |
148 | +############################################################################## |
149 | +# |
150 | +# OpenERP, Open Source Business Applications |
151 | +# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com> |
152 | +# |
153 | +# This program is free software: you can redistribute it and/or modify |
154 | +# it under the terms of the GNU Affero General Public License as |
155 | +# published by the Free Software Foundation, either version 3 of the |
156 | +# License, or (at your option) any later version. |
157 | +# |
158 | +# This program is distributed in the hope that it will be useful, |
159 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
160 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
161 | +# GNU Affero General Public License for more details. |
162 | +# |
163 | +# You should have received a copy of the GNU Affero General Public License |
164 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
165 | +# |
166 | +############################################################################## |
167 | +from openerp.osv.orm import except_orm |
168 | +from openerp.tests import common |
169 | + |
170 | + |
171 | +class TestCrmStagesCase(common.TransactionCase): |
172 | + def setUp(self): |
173 | + super(TestCrmStagesCase, self).setUp() |
174 | + |
175 | + def test_00_stage_management(self): |
176 | + cr, uid = self.cr, self.uid |
177 | + crm_stage_stage = self.registry('crm.case.stage') |
178 | + crm_case_section = self.registry('crm.case.section') |
179 | + crm_lead = self.registry('crm.lead'); |
180 | + crm_case_section_id = crm_case_section.create(cr, uid, {'name':'test_section'},context={}) |
181 | + context = {'default_section_id': crm_case_section_id} |
182 | + |
183 | + ''' For create when default_section_id pass in context |
184 | + If same name is present than returns its id otherwise create new. |
185 | + and link with given section. |
186 | + ''' |
187 | + stage_type_id = crm_stage_stage.create(cr, uid, {'name':'First'}, {}) |
188 | + self.assertEqual(stage_type_id, crm_stage_stage.create(cr, uid, {'name':'First'}, context=context)) |
189 | + |
190 | + ''' For edit when default_section_id pass in context |
191 | + If same name is present than returns its id otherwise create new. |
192 | + and link with given section and remove old link with section and crm_lead. |
193 | + ''' |
194 | + crm_case_section.write(cr, uid, [crm_case_section_id], {'stage_ids': [(4, stage_type_id),]}, context=context) |
195 | + lead_id = crm_lead.create(cr, uid, {'name':'Test1', 'stage_id': stage_type_id, 'section_id': crm_case_section_id}) |
196 | + |
197 | + crm_stage_stage.write(cr, uid, [stage_type_id],{'name':'Second'}, context=context) |
198 | + |
199 | + stage_m2m_newlist = crm_case_section.browse(cr, uid, crm_case_section_id, context=context).stage_ids |
200 | + check_crm_lead_stage_id = crm_lead.browse(cr, uid, lead_id, context).stage_id.id |
201 | + crm_case_section_id_new = crm_stage_stage.search(cr, uid, [('name','=', 'Second')], context=context) |
202 | + |
203 | + self.assertIn(crm_case_section_id_new[0], [x.id for x in stage_m2m_newlist]) |
204 | + self.assertEqual(check_crm_lead_stage_id, crm_case_section_id_new[0]) |
205 | + |
206 | + ''' For unlink when default_section_id pass in context |
207 | + It will unlink relation, not delete. |
208 | + ''' |
209 | + stage_m2m_oldlist = crm_case_section.browse(cr, uid, crm_case_section_id, context=context).stage_ids |
210 | + crm_stage_stage.unlink(cr, uid, crm_case_section_id_new, context=context) |
211 | + stage_m2m_newlist = crm_case_section.browse(cr, uid, crm_case_section_id, context=context).stage_ids |
212 | + |
213 | + self.assertEqual(len(stage_m2m_oldlist) -1, len(stage_m2m_newlist)) |
214 | + |
215 | + unlink_id = crm_stage_stage.search(cr, uid, [('name','=', 'Second')], context=context) |
216 | + self.assertEqual(unlink_id, crm_case_section_id_new) |
217 | \ No newline at end of file |
218 | |
219 | === modified file 'hr_recruitment/__init__.py' |
220 | --- hr_recruitment/__init__.py 2012-04-02 05:44:18 +0000 |
221 | +++ hr_recruitment/__init__.py 2014-05-20 06:41:52 +0000 |
222 | @@ -23,5 +23,5 @@ |
223 | import report |
224 | import wizard |
225 | import res_config |
226 | - |
227 | +import tests |
228 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
229 | |
230 | === modified file 'hr_recruitment/hr_recruitment.py' |
231 | --- hr_recruitment/hr_recruitment.py 2014-05-08 12:35:29 +0000 |
232 | +++ hr_recruitment/hr_recruitment.py 2014-05-20 06:41:52 +0000 |
233 | @@ -45,20 +45,88 @@ |
234 | _name = "hr.recruitment.stage" |
235 | _description = "Stage of Recruitment" |
236 | _order = 'sequence' |
237 | + |
238 | _columns = { |
239 | 'name': fields.char('Name', size=64, required=True, translate=True), |
240 | 'sequence': fields.integer('Sequence', help="Gives the sequence order when displaying a list of stages."), |
241 | - 'department_id':fields.many2one('hr.department', 'Specific to a Department', help="Stages of the recruitment process may be different per department. If this stage is common to all departments, keep this field empty."), |
242 | + 'job_ids': fields.many2many('hr.job', 'job_stage_rel', 'stage_id','job_id', 'Stages'), |
243 | 'requirements': fields.text('Requirements'), |
244 | + 'case_default': fields.boolean('Default for New Job'), |
245 | 'template_id': fields.many2one('email.template', 'Use template', help="If set, a message is posted on the applicant using the template when the applicant is set to the stage."), |
246 | 'fold': fields.boolean('Folded in Kanban View', |
247 | help='This stage is folded in the kanban view when' |
248 | 'there are no records in that stage to display.'), |
249 | } |
250 | + def _get_default_job_ids(self, cr, uid, context=None): |
251 | + """ Gives default jon_id by checking if present in the context """ |
252 | + job_id = self.pool.get('hr.applicant')._resolve_job_id_from_context(cr, uid, context=context) or False |
253 | + return job_id and [job_id] or None |
254 | + |
255 | _defaults = { |
256 | 'sequence': 1, |
257 | + 'job_ids': _get_default_job_ids, |
258 | + 'case_default': lambda self, cr, uid, ctx={}: ctx.get('default_job_id', False) == False, |
259 | } |
260 | - |
261 | + |
262 | + _sql_constraints = [('stage_name_uniq', 'unique(name)', 'Name should be unique.')] |
263 | + |
264 | + def copy(self, cr, uid, id, default=None, context=None): |
265 | + if context is None: |
266 | + context = {} |
267 | + if default is None: |
268 | + default = {} |
269 | + default['job_ids'] = [] |
270 | + job = self.browse(cr, uid, id, context=context) |
271 | + if not default.get('name', False): |
272 | + default.update(name=_("%s (copy)") % (job.name)) |
273 | + return super(hr_recruitment_stage, self).copy(cr, uid, id, default, context) |
274 | + |
275 | + def create(self, cr, uid, vals, context=None): |
276 | + if context is None: context = {} |
277 | + job_id = context.get('default_job_id') |
278 | + type_id = False |
279 | + if job_id: |
280 | + #check already exist or not |
281 | + context.update({'job_id': job_id}) |
282 | + type_ids = self.search(cr, uid, [('name', '=', vals.get('name'))], context=context, limit=1) |
283 | + if type_ids and len(type_ids): |
284 | + type_id = type_ids[0] |
285 | + if not type_id: |
286 | + type_id = super(hr_recruitment_stage, self).create(cr, uid, vals, context=context) |
287 | + return type_id |
288 | + |
289 | + def write(self, cr, uid, ids, vals, context=None): |
290 | + if context is None: context = {} |
291 | + job_id = context.get('default_job_id') |
292 | + job_obj = self.pool.get('hr.job') |
293 | + if job_id: |
294 | + context.update({'job_id': job_id}) |
295 | + if vals.get('name', False): |
296 | + for stage in self.browse(cr, uid, ids, context=context): |
297 | + new_stage_id = self.copy(cr, uid, stage.id, default=vals, context=context) |
298 | + job_obj.write(cr, uid, [job_id], {'stage_ids': [(3, stage.id),(4, new_stage_id),]}, context=context) |
299 | + self._update_application(cr, uid, job_id, stage.id, new_stage_id, context=context) |
300 | + return True |
301 | + return super(hr_recruitment_stage, self).write(cr, uid, ids, vals, context=context) |
302 | + |
303 | + def unlink(self, cr, uid, ids, context=None): |
304 | + if context is None: context = {} |
305 | + job_id = context.get('default_job_id') |
306 | + job_obj = self.pool.get('hr.job') |
307 | + if not job_id: |
308 | + return super(hr_recruitment_stage, self).unlink(cr, uid, ids, context=context) |
309 | + |
310 | + for stage in self.browse(cr, uid, ids, context=context): |
311 | + job_obj.write(cr, uid, job_id, {'stage_ids': [(3, stage.id)]}, context=context) |
312 | + self._update_application(cr, uid, job_id, stage.id, False, context=context) |
313 | + return True |
314 | + |
315 | + def _update_application(self, cr, uid, job_id, old_stage_id, new_stage_id, context=None): |
316 | + if context is None: context = {} |
317 | + hr_applicant_obj = self.pool.get('hr.applicant') |
318 | + applicant_ids = hr_applicant_obj.search(cr, uid, [('stage_id', '=', old_stage_id),('job_id', '=', job_id)], context=context) |
319 | + return hr_applicant_obj.write(cr, uid, applicant_ids, {'stage_id': new_stage_id} , context=context) |
320 | + |
321 | class hr_recruitment_degree(osv.osv): |
322 | """ Degree of HR Recruitment """ |
323 | _name = "hr.recruitment.degree" |
324 | @@ -89,29 +157,27 @@ |
325 | } |
326 | _mail_mass_mailing = _('Applicants') |
327 | |
328 | - def _get_default_department_id(self, cr, uid, context=None): |
329 | + def _get_default_job_id(self, cr, uid, context=None): |
330 | """ Gives default department by checking if present in the context """ |
331 | - return (self._resolve_department_id_from_context(cr, uid, context=context) or False) |
332 | + return (self._resolve_job_id_from_context(cr, uid, context=context) or False) |
333 | |
334 | def _get_default_stage_id(self, cr, uid, context=None): |
335 | """ Gives default stage_id """ |
336 | - department_id = self._get_default_department_id(cr, uid, context=context) |
337 | - return self.stage_find(cr, uid, [], department_id, [('fold', '=', False)], context=context) |
338 | - |
339 | - def _resolve_department_id_from_context(self, cr, uid, context=None): |
340 | - """ Returns ID of department based on the value of 'default_department_id' |
341 | - context key, or None if it cannot be resolved to a single |
342 | - department. |
343 | + job_id = self._get_default_job_id(cr, uid, context=context) |
344 | + return self.stage_find(cr, uid, [], job_id, [('sequence', '=', '1')], context=context) |
345 | + def _resolve_job_id_from_context(self, cr, uid, context=None): |
346 | + """ Returns ID of job based on the value of 'default_job_id' |
347 | + context key, or None if it cannot be resolved to a single |
348 | """ |
349 | if context is None: |
350 | context = {} |
351 | - if type(context.get('default_department_id')) in (int, long): |
352 | - return context.get('default_department_id') |
353 | - if isinstance(context.get('default_department_id'), basestring): |
354 | - department_name = context['default_department_id'] |
355 | - department_ids = self.pool.get('hr.department').name_search(cr, uid, name=department_name, context=context) |
356 | - if len(department_ids) == 1: |
357 | - return int(department_ids[0][0]) |
358 | + if type(context.get('default_job_id')) in (int, long): |
359 | + return context.get('default_job_id') |
360 | + if isinstance(context.get('default_job_id'), basestring): |
361 | + job_name = context['default_job_id'] |
362 | + job_ids = self.pool.get('hr.job').name_search(cr, uid, name=job_name, context=context) |
363 | + if len(job_ids) == 1: |
364 | + return int(job_ids[0][0]) |
365 | return None |
366 | |
367 | def _read_group_stage_ids(self, cr, uid, ids, domain, read_group_order=None, access_rights_uid=None, context=None): |
368 | @@ -123,23 +189,19 @@ |
369 | order = "%s desc" % order |
370 | # retrieve section_id from the context and write the domain |
371 | # - ('id', 'in', 'ids'): add columns that should be present |
372 | - # - OR ('department_id', '=', False), ('fold', '=', False): add default columns that are not folded |
373 | - # - OR ('department_id', 'in', department_id), ('fold', '=', False) if department_id: add department columns that are not folded |
374 | - department_id = self._resolve_department_id_from_context(cr, uid, context=context) |
375 | + # - OR ('job_id', '=', False), ('fold', '=', False): add default columns that are not folded |
376 | + # - OR ('job_id', 'in', job_id), ('fold', '=', False) if job_id: add department columns that are not folded |
377 | + job_id = self._resolve_job_id_from_context(cr, uid, context=context) |
378 | search_domain = [] |
379 | - if department_id: |
380 | - search_domain += ['|', ('department_id', '=', department_id)] |
381 | - search_domain += ['|', ('id', 'in', ids), ('department_id', '=', False)] |
382 | + if job_id: |
383 | + search_domain += [('job_ids', '=', job_id)] |
384 | stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context) |
385 | - result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) |
386 | - # restore order of the search |
387 | - result.sort(lambda x,y: cmp(stage_ids.index(x[0]), stage_ids.index(y[0]))) |
388 | - |
389 | fold = {} |
390 | for stage in stage_obj.browse(cr, access_rights_uid, stage_ids, context=context): |
391 | fold[stage.id] = stage.fold or False |
392 | + result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) |
393 | return result, fold |
394 | - |
395 | + |
396 | def _compute_day(self, cr, uid, ids, fields, args, context=None): |
397 | """ |
398 | @param cr: the current row, from the database cursor, |
399 | @@ -188,8 +250,7 @@ |
400 | 'partner_id': fields.many2one('res.partner', 'Contact'), |
401 | 'create_date': fields.datetime('Creation Date', readonly=True, select=True), |
402 | 'write_date': fields.datetime('Update Date', readonly=True), |
403 | - 'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage', track_visibility='onchange', |
404 | - domain="['|', ('department_id', '=', department_id), ('department_id', '=', False)]"), |
405 | + 'stage_id': fields.many2one ('hr.recruitment.stage', 'Stage', track_visibility='onchange',domain="[('job_ids', '=', job_id)]"), |
406 | 'last_stage_id': fields.many2one('hr.recruitment.stage', 'Last Stage', |
407 | help='Stage of the applicant before being in the current stage. Used for lost cases analysis.'), |
408 | 'categ_ids': fields.many2many('hr.applicant_category', string='Tags'), |
409 | @@ -230,7 +291,7 @@ |
410 | 'active': lambda *a: 1, |
411 | 'user_id': lambda s, cr, uid, c: uid, |
412 | 'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c), |
413 | - 'department_id': lambda s, cr, uid, c: s._get_default_department_id(cr, uid, c), |
414 | + 'job_id': lambda s, cr, uid, c: s._get_default_job_id(cr, uid, c), |
415 | 'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'hr.applicant', context=c), |
416 | 'color': 0, |
417 | 'date_last_stage_update': fields.datetime.now, |
418 | @@ -242,6 +303,7 @@ |
419 | |
420 | def onchange_job(self, cr, uid, ids, job_id=False, context=None): |
421 | department_id = False |
422 | + user_id = False |
423 | if job_id: |
424 | job_record = self.pool.get('hr.job').browse(cr, uid, job_id, context=context) |
425 | department_id = job_record and job_record.department_id and job_record.department_id.id or False |
426 | @@ -273,18 +335,16 @@ |
427 | if isinstance(cases, (int, long)): |
428 | cases = self.browse(cr, uid, cases, context=context) |
429 | # collect all section_ids |
430 | - department_ids = [] |
431 | + job_ids = [] |
432 | if section_id: |
433 | - department_ids.append(section_id) |
434 | + job_ids.append(section_id) |
435 | for case in cases: |
436 | - if case.department_id: |
437 | - department_ids.append(case.department_id.id) |
438 | - # OR all section_ids and OR with case_default |
439 | + if case.job_id: |
440 | + job_ids.append(case.job_id.id)# OR all section_ids and OR with case_default |
441 | search_domain = [] |
442 | - if department_ids: |
443 | - search_domain += ['|', ('department_id', 'in', department_ids)] |
444 | - search_domain.append(('department_id', '=', False)) |
445 | # AND with the domain in parameter |
446 | + if job_ids: |
447 | + search_domain += [('job_ids', 'in', job_ids)] |
448 | search_domain += list(domain) |
449 | # perform search, return the first found |
450 | stage_ids = self.pool.get('hr.recruitment.stage').search(cr, uid, search_domain, order=order, context=context) |
451 | @@ -424,7 +484,7 @@ |
452 | subtype="hr_recruitment.mt_job_applicant_new", context=context) |
453 | |
454 | # post processing: if stage changed, post a message in the chatter |
455 | - if vals.get('stage_id'): |
456 | + if vals.get('stage_id') and ids: |
457 | stage = self.pool['hr.recruitment.stage'].browse(cr, uid, vals['stage_id'], context=context) |
458 | if stage.template_id: |
459 | # TDENOTE: probably factorize me in a message_post_with_template generic method FIXME |
460 | @@ -528,6 +588,7 @@ |
461 | 'alias_id': fields.many2one('mail.alias', 'Alias', ondelete="restrict", required=True, |
462 | help="Email alias for this job position. New emails will automatically " |
463 | "create new applicants for this job position."), |
464 | + 'stage_ids':fields.many2many('hr.recruitment.stage', 'job_stage_rel','job_id', 'stage_id', 'Stages'), |
465 | 'address_id': fields.many2one('res.partner', 'Job Location', help="Address where employees are working"), |
466 | 'application_ids': fields.one2many('hr.applicant', 'job_id', 'Applications'), |
467 | 'application_count': fields.function(_count_all, type='integer', string='Applications', multi=True), |
468 | @@ -538,11 +599,15 @@ |
469 | 'color': fields.integer('Color Index'), |
470 | } |
471 | |
472 | + def _get_stage_common(self, cr, uid, context): |
473 | + return self.pool.get('hr.recruitment.stage').search(cr, uid, [('case_default','=',1)], context=context) |
474 | + |
475 | def _address_get(self, cr, uid, context=None): |
476 | user = self.pool.get('res.users').browse(cr, uid, uid, context=context) |
477 | return user.company_id.partner_id.id |
478 | |
479 | _defaults = { |
480 | + 'stage_ids': _get_stage_common, |
481 | 'address_id': _address_get |
482 | } |
483 | |
484 | |
485 | === modified file 'hr_recruitment/hr_recruitment_data.xml' |
486 | --- hr_recruitment/hr_recruitment_data.xml 2014-02-12 09:56:06 +0000 |
487 | +++ hr_recruitment/hr_recruitment_data.xml 2014-05-20 06:41:52 +0000 |
488 | @@ -92,30 +92,36 @@ |
489 | <record model="hr.recruitment.stage" id="stage_job1"> |
490 | <field name="name">Initial Qualification</field> |
491 | <field name="sequence">1</field> |
492 | + <field name="case_default" eval="True"/> |
493 | </record> |
494 | <record model="hr.recruitment.stage" id="stage_job2"> |
495 | <field name="name">First Interview</field> |
496 | <field name="template_id" ref="applicant_interest"/> |
497 | <field name="sequence">2</field> |
498 | + <field name="case_default" eval="True"/> |
499 | </record> |
500 | <record model="hr.recruitment.stage" id="stage_job3"> |
501 | <field name="name">Second Interview</field> |
502 | <field name="sequence">3</field> |
503 | + <field name="case_default" eval="True"/> |
504 | </record> |
505 | <record model="hr.recruitment.stage" id="stage_job4"> |
506 | <field name="name">Contract Proposed</field> |
507 | <field name="sequence">4</field> |
508 | + <field name="case_default" eval="True"/> |
509 | </record> |
510 | <record model="hr.recruitment.stage" id="stage_job5"> |
511 | <field name="name">Contract Signed</field> |
512 | <field name="sequence">5</field> |
513 | <field name="fold" eval="True"/> |
514 | + <field name="case_default" eval="True"/> |
515 | </record> |
516 | <record model="hr.recruitment.stage" id="stage_job6"> |
517 | <field name="name">Refused</field> |
518 | <field name="sequence">6</field> |
519 | <field name="template_id" ref="applicant_refuse"/> |
520 | <field name="fold" eval="True"/> |
521 | + <field name="case_default" eval="True"/> |
522 | </record> |
523 | |
524 | <record id="mail_alias_jobs" model="mail.alias"> |
525 | |
526 | === modified file 'hr_recruitment/hr_recruitment_demo.xml' |
527 | --- hr_recruitment/hr_recruitment_demo.xml 2014-04-15 09:30:47 +0000 |
528 | +++ hr_recruitment/hr_recruitment_demo.xml 2014-05-20 06:41:52 +0000 |
529 | @@ -126,12 +126,15 @@ |
530 | <record id="hr.job_developer" model="hr.job"> |
531 | <field name="state">recruit</field> |
532 | <field name="no_of_recruitment">4</field> |
533 | + <field name= "stage_ids" eval="[(4, stage_job1),(4, stage_job2),(4, stage_job3),(4, stage_job4),(4, stage_job5),(4, stage_job6)]" /> |
534 | <field name="survey_id" ref="recruitment_form"/> |
535 | </record> |
536 | <record id="hr.job_ceo" model="hr.job"> |
537 | + <field name= "stage_ids" eval="[(4, stage_job3),(4, stage_job4),(4, stage_job5),(4, stage_job6)]" /> |
538 | <field name="survey_id" ref="recruitment_form"/> |
539 | </record> |
540 | <record id="hr.job_cto" model="hr.job"> |
541 | + <field name= "stage_ids" eval="[(4, stage_job1),(4, stage_job4),(4, stage_job5),(4, stage_job6)]" /> |
542 | <field name="survey_id" ref="recruitment_form"/> |
543 | </record> |
544 | <record id="hr.job_consultant" model="hr.job"> |
545 | @@ -142,19 +145,21 @@ |
546 | <record id="hr.job_hrm" model="hr.job"> |
547 | <field name="no_of_recruitment">1</field> |
548 | <field name="state">recruit</field> |
549 | + <field name= "stage_ids" eval="[(4, stage_job1),(4, stage_job2),(4, stage_job3),(4, stage_job4)]" /> |
550 | <field name="survey_id" ref="recruitment_form"/> |
551 | </record> |
552 | <record id="hr.job_marketing" model="hr.job"> |
553 | <field name="state">recruit</field> |
554 | <field name="no_of_recruitment">3</field> |
555 | + <field name= "stage_ids" eval="[(4, stage_job1),(4, stage_job2),(4, stage_job3),(4, stage_job4)]" /> |
556 | <field name="survey_id" ref="recruitment_form"/> |
557 | </record> |
558 | <record id="hr.job_trainee" model="hr.job"> |
559 | <field name="state">recruit</field> |
560 | <field name="no_of_recruitment">6</field> |
561 | + <field name= "stage_ids" eval="[(4, stage_job1),(4, stage_job2),(4, stage_job3),(4, stage_job4)]" /> |
562 | <field name="survey_id" ref="recruitment_form"/> |
563 | </record> |
564 | - --> |
565 | <record id="message_application_demo" model="mail.message"> |
566 | <field name="model">hr.applicant</field> |
567 | <field name="res_id" ref="hr_case_advertisement"/> |
568 | |
569 | === modified file 'hr_recruitment/hr_recruitment_menu.xml' |
570 | --- hr_recruitment/hr_recruitment_menu.xml 2014-02-11 11:41:21 +0000 |
571 | +++ hr_recruitment/hr_recruitment_menu.xml 2014-05-20 06:41:52 +0000 |
572 | @@ -61,5 +61,33 @@ |
573 | name="Applications" |
574 | parent="base.menu_crm_case_job_req_main" |
575 | id="menu_crm_case_categ0_act_job" action="crm_case_categ0_act_job" sequence="2"/> |
576 | + |
577 | + <menuitem parent="hr.menu_hr_configuration" id="hr.menu_hr_job" action="hr.action_hr_job" sequence="2"/> |
578 | + |
579 | + <menuitem name="Recruitment" |
580 | + id="menu_hr_recruitment_recruitment" |
581 | + parent="hr.menu_hr_configuration" |
582 | + sequence="40"/> |
583 | + |
584 | + <menuitem |
585 | + id="menu_hr_recruitment_stage" |
586 | + name="Stages" |
587 | + parent="menu_hr_recruitment_recruitment" |
588 | + action="hr_recruitment_stage_act" |
589 | + sequence="1" groups="base.group_no_one"/> |
590 | + <menuitem |
591 | + id="menu_hr_recruitment_degree" |
592 | + name="Degrees" |
593 | + parent="menu_hr_recruitment_recruitment" |
594 | + action="hr_recruitment_degree_action" |
595 | + sequence="5" groups="base.group_no_one"/> |
596 | + |
597 | + <menuitem |
598 | + id="menu_hr_recruitment_source" |
599 | + parent="menu_hr_recruitment_recruitment" |
600 | + action="hr_recruitment_source_action" |
601 | + groups="base.group_no_one" |
602 | + sequence="10"/> |
603 | + |
604 | </data> |
605 | </openerp> |
606 | |
607 | === modified file 'hr_recruitment/hr_recruitment_view.xml' |
608 | --- hr_recruitment/hr_recruitment_view.xml 2014-05-08 15:25:36 +0000 |
609 | +++ hr_recruitment/hr_recruitment_view.xml 2014-05-20 06:41:52 +0000 |
610 | @@ -370,6 +370,10 @@ |
611 | </div> |
612 | </div> |
613 | </xpath> |
614 | + <xpath expr="//field[@name='requirements']" position="after"> |
615 | + <separator string="Recruitment Stages" /> |
616 | + <field name="stage_ids" nolabel="1"/> |
617 | + </xpath> |
618 | <xpath expr="//field[@name='department_id']" position="after"> |
619 | <field name="user_id" class="oe_inline"/> |
620 | </xpath> |
621 | @@ -518,7 +522,6 @@ |
622 | <tree string="Stages"> |
623 | <field name="sequence" invisible="1"/> |
624 | <field name="name"/> |
625 | - <field name="department_id"/> |
626 | <field name="fold"/> |
627 | </tree> |
628 | </field> |
629 | @@ -534,17 +537,18 @@ |
630 | <group string="Stage Definition"> |
631 | <group> |
632 | <field name="name"/> |
633 | - <field name="department_id"/> |
634 | - </group> |
635 | - <group> |
636 | <field name="sequence"/> |
637 | + <field name="template_id" domain= "[('model_id.model', '=', 'hr.applicant')]"/> |
638 | + </group> |
639 | + <group> |
640 | <field name="fold"/> |
641 | - <field name="template_id" domain= "[('model_id.model', '=', 'hr.applicant')]"/> |
642 | + <field name="case_default"/> |
643 | </group> |
644 | </group> |
645 | <separator string="Requirements"/> |
646 | <field name="requirements"/> |
647 | </sheet> |
648 | + <field name="job_ids" invisible="1"/> |
649 | </form> |
650 | </field> |
651 | </record> |
652 | @@ -565,13 +569,6 @@ |
653 | </field> |
654 | </record> |
655 | |
656 | - <menuitem |
657 | - id="menu_hr_recruitment_stage" |
658 | - name="Stages" |
659 | - parent="menu_hr_recruitment_recruitment" |
660 | - action="hr_recruitment_stage_act" |
661 | - sequence="1" groups="base.group_no_one"/> |
662 | - |
663 | <!-- Degree Tree View --> |
664 | <record model="ir.ui.view" id="hr_recruitment_degree_tree"> |
665 | <field name="name">hr.recruitment.degree.tree</field> |
666 | @@ -608,13 +605,6 @@ |
667 | <field name="view_id" ref="hr_recruitment_degree_tree"/> |
668 | </record> |
669 | |
670 | - <menuitem |
671 | - id="menu_hr_recruitment_degree" |
672 | - name="Degrees" |
673 | - parent="menu_hr_recruitment_recruitment" |
674 | - action="hr_recruitment_degree_action" |
675 | - sequence="5" groups="base.group_no_one"/> |
676 | - |
677 | <!-- Source Tree View --> |
678 | <record model="ir.ui.view" id="hr_recruitment_source_tree"> |
679 | <field name="name">hr.recruitment.source.tree</field> |
680 | @@ -625,6 +615,7 @@ |
681 | </tree> |
682 | </field> |
683 | </record> |
684 | + |
685 | <record model="ir.ui.view" id="hr_recruitment_source_form"> |
686 | <field name="name">hr.recruitment.source.form</field> |
687 | <field name="model">hr.recruitment.source</field> |
688 | @@ -638,18 +629,12 @@ |
689 | </form> |
690 | </field> |
691 | </record> |
692 | + |
693 | <record id="hr_recruitment_source_action" model="ir.actions.act_window"> |
694 | <field name="name">Sources of Applicants</field> |
695 | <field name="res_model">hr.recruitment.source</field> |
696 | <field name="view_type">form</field> |
697 | </record> |
698 | |
699 | - <menuitem |
700 | - id="menu_hr_recruitment_source" |
701 | - parent="menu_hr_recruitment_recruitment" |
702 | - action="hr_recruitment_source_action" |
703 | - groups="base.group_no_one" |
704 | - sequence="10"/> |
705 | - |
706 | </data> |
707 | </openerp> |
708 | |
709 | === added directory 'hr_recruitment/tests' |
710 | === added file 'hr_recruitment/tests/__init__.py' |
711 | --- hr_recruitment/tests/__init__.py 1970-01-01 00:00:00 +0000 |
712 | +++ hr_recruitment/tests/__init__.py 2014-05-20 06:41:52 +0000 |
713 | @@ -0,0 +1,24 @@ |
714 | +# -*- coding: utf-8 -*- |
715 | +############################################################################## |
716 | +# |
717 | +# OpenERP, Open Source Business Applications |
718 | +# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com> |
719 | +# |
720 | +# This program is free software: you can redistribute it and/or modify |
721 | +# it under the terms of the GNU Affero General Public License as |
722 | +# published by the Free Software Foundation, either version 3 of the |
723 | +# License, or (at your option) any later version. |
724 | +# |
725 | +# This program is distributed in the hope that it will be useful, |
726 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
727 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
728 | +# GNU Affero General Public License for more details. |
729 | +# |
730 | +# You should have received a copy of the GNU Affero General Public License |
731 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
732 | +# |
733 | +############################################################################## |
734 | +from . import test_hr_recruitment_stage |
735 | +checks = [ |
736 | + test_hr_recruitment_stage, |
737 | + ] |
738 | \ No newline at end of file |
739 | |
740 | === added file 'hr_recruitment/tests/test_hr_recruitment_stage.py' |
741 | --- hr_recruitment/tests/test_hr_recruitment_stage.py 1970-01-01 00:00:00 +0000 |
742 | +++ hr_recruitment/tests/test_hr_recruitment_stage.py 2014-05-20 06:41:52 +0000 |
743 | @@ -0,0 +1,71 @@ |
744 | +# -*- coding: utf-8 -*- |
745 | +############################################################################## |
746 | +# |
747 | +# OpenERP, Open Source Business Applications |
748 | +# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com> |
749 | +# |
750 | +# This program is free software: you can redistribute it and/or modify |
751 | +# it under the terms of the GNU Affero General Public License as |
752 | +# published by the Free Software Foundation, either version 3 of the |
753 | +# License, or (at your option) any later version. |
754 | +# |
755 | +# This program is distributed in the hope that it will be useful, |
756 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
757 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
758 | +# GNU Affero General Public License for more details. |
759 | +# |
760 | +# You should have received a copy of the GNU Affero General Public License |
761 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
762 | +# |
763 | +############################################################################## |
764 | +from openerp.osv.orm import except_orm |
765 | +from openerp.tests import common |
766 | + |
767 | + |
768 | +class TestHrRecruitmentStage(common.TransactionCase): |
769 | + def setUp(self): |
770 | + super(TestHrRecruitmentStage, self).setUp() |
771 | + |
772 | + def test_00_stage_management(self): |
773 | + cr, uid = self.cr, self.uid |
774 | + hr_job = self.registry('hr.job') |
775 | + hr_recruitment_stage= self.registry('hr.recruitment.stage') |
776 | + hr_applicant = self.registry('hr.applicant'); |
777 | + hr_job_id = hr_job.create(cr, uid, {'name':'test_section'},context={}) |
778 | + context = {'default_job_id': hr_job_id} |
779 | + |
780 | + ''' For create when default_job_id pass in context |
781 | + If same name is present than returns its id otherwise create new. |
782 | + and link with given job. |
783 | + ''' |
784 | + |
785 | + check_len_id = hr_recruitment_stage.create(cr, uid, {'name':'First'},{}) |
786 | + self.assertEqual(check_len_id, hr_recruitment_stage.create(cr, uid, {'name':'First'}, context=context)) |
787 | + |
788 | + ''' For edit when default_job_id pass in context |
789 | + If same name is present than returns its id otherwise create new. |
790 | + and link with given job and remove old link with job and project_task. |
791 | + ''' |
792 | + hr_job.write(cr, uid, [hr_job_id], {'stage_ids': [(4, check_len_id),]}, context=context) |
793 | + hr_recruitment_id = hr_applicant.create(cr, uid, {'name':'Test1', 'stage_id': check_len_id, 'job_id':hr_job_id}) |
794 | + |
795 | + hr_recruitment_stage.write(cr, uid, [check_len_id],{'name':'Second'}, context=context) |
796 | + |
797 | + stage_m2m_newlist = hr_job.browse(cr, uid, hr_job_id, context=context).stage_ids |
798 | + check_hr_recruitment_stage_id = hr_applicant.browse(cr, uid, hr_recruitment_id, context).stage_id.id |
799 | + hr_recruitment_stage_id_new = hr_recruitment_stage.search(cr, uid, [('name','=', 'Second')], context=context) |
800 | + |
801 | + self.assertIn(hr_recruitment_stage_id_new[0], [x.id for x in stage_m2m_newlist]) |
802 | + self.assertEqual(check_hr_recruitment_stage_id, hr_recruitment_stage_id_new[0]) |
803 | + |
804 | + ''' For unlink when default_job_id pass in context |
805 | + It will unlink relation, not delete. |
806 | + ''' |
807 | + stage_m2m_oldlist = hr_job.browse(cr, uid, hr_job_id, context=context).stage_ids |
808 | + hr_recruitment_stage.unlink(cr, uid, hr_recruitment_stage_id_new, context=context) |
809 | + stage_m2m_newlist = hr_job.browse(cr, uid, hr_job_id, context=context).stage_ids |
810 | + |
811 | + self.assertEqual(len(stage_m2m_oldlist) -1, len(stage_m2m_newlist)) |
812 | + unlink_id = hr_recruitment_stage.search(cr, uid, [('name','=', 'Second')], context=context) |
813 | + self.assertEqual(unlink_id, hr_recruitment_stage_id_new) |
814 | + |
815 | |
816 | === modified file 'project/project.py' |
817 | --- project/project.py 2014-05-13 11:18:37 +0000 |
818 | +++ project/project.py 2014-05-20 06:41:52 +0000 |
819 | @@ -55,9 +55,68 @@ |
820 | _defaults = { |
821 | 'sequence': 1, |
822 | 'project_ids': _get_default_project_ids, |
823 | + 'case_default': lambda self, cr, uid, ctx={}: ctx.get('default_project_id', False) == False, |
824 | } |
825 | _order = 'sequence' |
826 | - |
827 | + |
828 | + _sql_constraints = [('stage_name_uniq', 'unique(name)', 'Name should be unique.')] |
829 | + |
830 | + def copy(self, cr, uid, id, default=None, context=None): |
831 | + if context is None: |
832 | + context = {} |
833 | + if default is None: |
834 | + default = {} |
835 | + default['project_ids'] = [] |
836 | + proj = self.browse(cr, uid, id, context=context) |
837 | + if not default.get('name', False): |
838 | + default.update(name=_("%s (copy)") % (proj.name)) |
839 | + return super(project_task_type, self).copy(cr, uid, id, default, context) |
840 | + |
841 | + def create(self, cr, uid, vals, context=None): |
842 | + if context is None: context = {} |
843 | + project_id = context.get('default_project_id') |
844 | + type_id = False |
845 | + if project_id: |
846 | + #check already exist or not |
847 | + context.update({'project_id': project_id}) |
848 | + type_ids = self.search(cr, uid, [('name','=', vals.get('name'))], context=context, limit=1) |
849 | + if type_ids and len(type_ids): |
850 | + type_id = type_ids[0] |
851 | + if not type_id: |
852 | + type_id = super(project_task_type, self).create(cr, uid, vals, context=context) |
853 | + return type_id |
854 | + |
855 | + def write(self, cr, uid, ids, vals, context=None): |
856 | + if context is None: context = {} |
857 | + project_id = context.get('default_project_id') |
858 | + project_obj = self.pool.get('project.project') |
859 | + if project_id: |
860 | + context.update({'project_id': project_id}) |
861 | + if vals.get('name', False): |
862 | + for stage in self.browse(cr, uid, ids, context=context): |
863 | + new_stage_id = self.copy(cr, uid, stage.id, default=vals, context=context) |
864 | + project_obj.write(cr, uid, [project_id], {'type_ids': [(3, stage.id),(4, new_stage_id),]}, context=context) |
865 | + self._update_tasks(cr, uid, project_id, stage.id, new_stage_id, context=context) |
866 | + return True |
867 | + return super(project_task_type, self).write(cr, uid, ids, vals, context=context) |
868 | + |
869 | + def unlink(self, cr, uid, ids, context=None): |
870 | + if context is None: context = {} |
871 | + project_id = context.get('default_project_id') |
872 | + project_obj = self.pool.get('project.project') |
873 | + if not project_id: |
874 | + return super(project_task_type, self).unlink(cr, uid, ids, context=context) |
875 | + |
876 | + for stage in self.browse(cr, uid, ids, context=context): |
877 | + project_obj.write(cr, uid, project_id, {'type_ids': [(3, stage.id)]}, context=context) |
878 | + self._update_tasks(cr, uid, project_id, stage.id, False, context=context) |
879 | + return True |
880 | + |
881 | + def _update_tasks(self, cr, uid, project_id, old_stage_id, new_stage_id, context=None): |
882 | + if context is None: context = {} |
883 | + task_obj = self.pool.get('project.task') |
884 | + task_ids = task_obj.search(cr, uid, [('stage_id', '=', old_stage_id),('project_id', '=', project_id)], context=context) |
885 | + return task_obj.write(cr, uid, task_ids, {'stage_id': new_stage_id} , context=context) |
886 | |
887 | class project(osv.osv): |
888 | _name = "project.project" |
889 | @@ -611,8 +670,7 @@ |
890 | search_domain = [] |
891 | project_id = self._resolve_project_id_from_context(cr, uid, context=context) |
892 | if project_id: |
893 | - search_domain += ['|', ('project_ids', '=', project_id)] |
894 | - search_domain += [('id', 'in', ids)] |
895 | + search_domain += [('project_ids', '=', project_id)] |
896 | stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context) |
897 | result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) |
898 | # restore order of the search |
899 | |
900 | === modified file 'project/tests/__init__.py' |
901 | --- project/tests/__init__.py 2013-07-10 10:15:08 +0000 |
902 | +++ project/tests/__init__.py 2014-05-20 06:41:52 +0000 |
903 | @@ -19,10 +19,11 @@ |
904 | # |
905 | ############################################################################## |
906 | |
907 | -from . import test_project_flow |
908 | +from . import test_project_flow,project_stage_management |
909 | |
910 | checks = [ |
911 | test_project_flow, |
912 | + project_stage_management, |
913 | ] |
914 | |
915 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
916 | |
917 | === added file 'project/tests/project_stage_management.py' |
918 | --- project/tests/project_stage_management.py 1970-01-01 00:00:00 +0000 |
919 | +++ project/tests/project_stage_management.py 2014-05-20 06:41:52 +0000 |
920 | @@ -0,0 +1,74 @@ |
921 | +# -*- coding: utf-8 -*- |
922 | +############################################################################## |
923 | +# |
924 | +# OpenERP, Open Source Business Applications |
925 | +# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com> |
926 | +# |
927 | +# This program is free software: you can redistribute it and/or modify |
928 | +# it under the terms of the GNU Affero General Public License as |
929 | +# published by the Free Software Foundation, either version 3 of the |
930 | +# License, or (at your option) any later version. |
931 | +# |
932 | +# This program is distributed in the hope that it will be useful, |
933 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
934 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
935 | +# GNU Affero General Public License for more details. |
936 | +# |
937 | +# You should have received a copy of the GNU Affero General Public License |
938 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
939 | +# |
940 | +############################################################################## |
941 | +from openerp.osv.orm import except_orm |
942 | +from openerp.tests import common |
943 | + |
944 | + |
945 | +class TestCrmStagesCase(common.TransactionCase): |
946 | + def setUp(self): |
947 | + super(TestCrmStagesCase, self).setUp() |
948 | + |
949 | + def test_00_stage_management(self): |
950 | + |
951 | + cr, uid = self.cr, self.uid |
952 | + project_project = self.registry('project.project') |
953 | + project_task_type= self.registry('project.task.type') |
954 | + project_task = self.registry('project.task'); |
955 | + project_project_id = project_project.create(cr, uid, {'name':'Project1'},context={}) |
956 | + context = {'default_project_id': project_project_id} |
957 | + |
958 | + ''' For create when default_project_id pass in context |
959 | + If same name is present than returns its id otherwise create new. |
960 | + and link with given project |
961 | + ''' |
962 | + |
963 | + task_type_id = project_task_type.create(cr, uid, {'name':'First'}, {}) |
964 | + self.assertEqual(task_type_id, project_task_type.create(cr, uid, {'name':'First'}, context=context)) |
965 | + |
966 | + ''' For edit when default_project_id pass in context |
967 | + If same name is present than returns its id otherwise create new. |
968 | + and link with given project and remove old link with project and project_task. |
969 | + ''' |
970 | + project_project.write(cr, uid, [project_project_id], {'type_ids': [(4, task_type_id),]}, context=context) |
971 | + task_id = project_task.create(cr, uid, {'name':'Test1', 'stage_id': task_type_id, 'project_id':project_project_id}) |
972 | + context.update({'stage_model':'project.task'}) |
973 | + |
974 | + project_task_type.write(cr, uid, [task_type_id],{'name':'Second'}, context=context) |
975 | + |
976 | + stage_m2m_newlist = project_project.browse(cr, uid, project_project_id, context=context).type_ids |
977 | + check_project_task_stage_id = project_task.browse(cr, uid, task_id, context).stage_id.id |
978 | + task_type_id_new = project_task_type.search(cr, uid, [('name','=', 'Second')], context=context) |
979 | + |
980 | + self.assertIn(task_type_id_new[0], [x.id for x in stage_m2m_newlist]) |
981 | + self.assertEqual(check_project_task_stage_id, task_type_id_new[0]) |
982 | + |
983 | + ''' For unlink when default_project_id pass in context |
984 | + It will unlink relation, not delete. |
985 | + ''' |
986 | + stage_m2m_oldlist = project_project.browse(cr, uid, project_project_id, context=context).type_ids |
987 | + project_task_type.unlink(cr, uid, task_type_id_new, context=context) |
988 | + stage_m2m_newlist = project_project.browse(cr, uid, project_project_id, context=context).type_ids |
989 | + |
990 | + self.assertEqual(len(stage_m2m_oldlist) -1, len(stage_m2m_newlist)) |
991 | + |
992 | + unlink_id = project_task_type.search(cr, uid, [('name','=', 'Second')], context=context) |
993 | + self.assertEqual(unlink_id, task_type_id_new) |
994 | + |
995 | \ No newline at end of file |
996 | |
997 | === modified file 'project_issue/__init__.py' |
998 | --- project_issue/__init__.py 2012-03-15 06:19:19 +0000 |
999 | +++ project_issue/__init__.py 2014-05-20 06:41:52 +0000 |
1000 | @@ -23,5 +23,5 @@ |
1001 | import project_issue |
1002 | import report |
1003 | import res_config |
1004 | - |
1005 | +import tests |
1006 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1007 | |
1008 | === modified file 'project_issue/project_issue.py' |
1009 | --- project_issue/project_issue.py 2014-05-08 15:25:36 +0000 |
1010 | +++ project_issue/project_issue.py 2014-05-20 06:41:52 +0000 |
1011 | @@ -108,8 +108,7 @@ |
1012 | search_domain = [] |
1013 | project_id = self._resolve_project_id_from_context(cr, uid, context=context) |
1014 | if project_id: |
1015 | - search_domain += ['|', ('project_ids', '=', project_id)] |
1016 | - search_domain += [('id', 'in', ids)] |
1017 | + search_domain += [('project_ids', '=', project_id)] |
1018 | # perform search |
1019 | stage_ids = stage_obj._search(cr, uid, search_domain, order=order, access_rights_uid=access_rights_uid, context=context) |
1020 | result = stage_obj.name_get(cr, access_rights_uid, stage_ids, context=context) |
1021 | @@ -547,6 +546,15 @@ |
1022 | def write(self, cr, uid, ids, vals, context=None): |
1023 | self._check_create_write_values(cr, uid, vals, context=context) |
1024 | return super(project_project, self).write(cr, uid, ids, vals, context=context) |
1025 | + |
1026 | +class project_task_type(osv.Model): |
1027 | + _inherit = "project.task.type" |
1028 | + |
1029 | + def _update_tasks(self, cr, uid, project_id, old_stage_id, new_stage_id, context=None): |
1030 | + super(project_task_type, self)._update_tasks(cr, uid, project_id, old_stage_id, new_stage_id, context=context) |
1031 | + issue_obj = self.pool.get('project.issue') |
1032 | + issue_ids = issue_obj.search(cr, uid, [('stage_id', '=', old_stage_id),('project_id', '=', project_id)], context=context) |
1033 | + return issue_obj.write(cr, uid, issue_ids, {'stage_id': new_stage_id} , context=context) |
1034 | |
1035 | class res_partner(osv.osv): |
1036 | def _issue_count(self, cr, uid, ids, field_name, arg, context=None): |
1037 | |
1038 | === added directory 'project_issue/tests' |
1039 | === added file 'project_issue/tests/__init__.py' |
1040 | --- project_issue/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1041 | +++ project_issue/tests/__init__.py 2014-05-20 06:41:52 +0000 |
1042 | @@ -0,0 +1,28 @@ |
1043 | +# -*- coding: utf-8 -*- |
1044 | +############################################################################## |
1045 | +# |
1046 | +# OpenERP, Open Source Business Applications |
1047 | +# Copyright (c) 2013-TODAY OpenERP S.A. <http://www.openerp.com> |
1048 | +# |
1049 | +# This program is free software: you can redistribute it and/or modify |
1050 | +# it under the terms of the GNU Affero General Public License as |
1051 | +# published by the Free Software Foundation, either version 3 of the |
1052 | +# License, or (at your option) any later version. |
1053 | +# |
1054 | +# This program is distributed in the hope that it will be useful, |
1055 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1056 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1057 | +# GNU Affero General Public License for more details. |
1058 | +# |
1059 | +# You should have received a copy of the GNU Affero General Public License |
1060 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1061 | +# |
1062 | +############################################################################## |
1063 | + |
1064 | +from . import project_stage_management |
1065 | + |
1066 | +checks = [ |
1067 | + project_stage_management, |
1068 | +] |
1069 | + |
1070 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1071 | |
1072 | === added file 'project_issue/tests/project_stage_management.py' |
1073 | --- project_issue/tests/project_stage_management.py 1970-01-01 00:00:00 +0000 |
1074 | +++ project_issue/tests/project_stage_management.py 2014-05-20 06:41:52 +0000 |
1075 | @@ -0,0 +1,74 @@ |
1076 | +# -*- coding: utf-8 -*- |
1077 | +############################################################################## |
1078 | +# |
1079 | +# OpenERP, Open Source Business Applications |
1080 | +# Copyright (c) 2012-TODAY OpenERP S.A. <http://openerp.com> |
1081 | +# |
1082 | +# This program is free software: you can redistribute it and/or modify |
1083 | +# it under the terms of the GNU Affero General Public License as |
1084 | +# published by the Free Software Foundation, either version 3 of the |
1085 | +# License, or (at your option) any later version. |
1086 | +# |
1087 | +# This program is distributed in the hope that it will be useful, |
1088 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1089 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1090 | +# GNU Affero General Public License for more details. |
1091 | +# |
1092 | +# You should have received a copy of the GNU Affero General Public License |
1093 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1094 | +# |
1095 | +############################################################################## |
1096 | +from openerp.osv.orm import except_orm |
1097 | +from openerp.tests import common |
1098 | + |
1099 | + |
1100 | +class TestCrmStagesCase(common.TransactionCase): |
1101 | + def setUp(self): |
1102 | + super(TestCrmStagesCase, self).setUp() |
1103 | + |
1104 | + def test_00_stage_management(self): |
1105 | + |
1106 | + cr, uid = self.cr, self.uid |
1107 | + project_project = self.registry('project.project') |
1108 | + project_task_type= self.registry('project.task.type') |
1109 | + project_issue = self.registry('project.issue'); |
1110 | + project_project_id = project_project.create(cr, uid, {'name':'Project1'},context={}) |
1111 | + context = {'default_project_id': project_project_id} |
1112 | + |
1113 | + ''' For create when default_project_id pass in context |
1114 | + If same name is present than returns its id otherwise create new. |
1115 | + and link with given project |
1116 | + ''' |
1117 | + |
1118 | + task_type_id = project_task_type.create(cr, uid, {'name':'First'}, {}) |
1119 | + self.assertEqual(task_type_id, project_task_type.create(cr, uid, {'name':'First'}, context=context)) |
1120 | + |
1121 | + ''' For edit when default_project_id pass in context |
1122 | + If same name is present than returns its id otherwise create new. |
1123 | + and link with given project and remove old link with project and project_task. |
1124 | + ''' |
1125 | + project_project.write(cr, uid, [project_project_id], {'type_ids': [(4, task_type_id),]}, context=context) |
1126 | + issue_id = project_issue.create(cr, uid, {'name':'Test1', 'stage_id': task_type_id, 'project_id':project_project_id}) |
1127 | + context.update({'stage_model':'project.issue'}) |
1128 | + |
1129 | + project_task_type.write(cr, uid, [task_type_id],{'name':'Second'}, context=context) |
1130 | + |
1131 | + stage_m2m_newlist = project_project.browse(cr, uid, project_project_id, context=context).type_ids |
1132 | + check_project_task_stage_id = project_issue.browse(cr, uid, issue_id, context).stage_id.id |
1133 | + task_type_id_new = project_task_type.search(cr, uid, [('name','=', 'Second')], context=context) |
1134 | + |
1135 | + self.assertIn(task_type_id_new[0], [x.id for x in stage_m2m_newlist]) |
1136 | + self.assertEqual(check_project_task_stage_id, task_type_id_new[0]) |
1137 | + |
1138 | + ''' For unlink when default_project_id pass in context |
1139 | + It will unlink relation, not delete. |
1140 | + ''' |
1141 | + stage_m2m_oldlist = project_project.browse(cr, uid, project_project_id, context=context).type_ids |
1142 | + project_task_type.unlink(cr, uid, task_type_id_new, context=context) |
1143 | + stage_m2m_newlist = project_project.browse(cr, uid, project_project_id, context=context).type_ids |
1144 | + |
1145 | + self.assertEqual(len(stage_m2m_oldlist) -1, len(stage_m2m_newlist)) |
1146 | + |
1147 | + unlink_id = project_task_type.search(cr, uid, [('name','=', 'Second')], context=context) |
1148 | + self.assertEqual(unlink_id, task_type_id_new) |
1149 | + |
1150 | \ No newline at end of file |