Merge lp:~openerp-dev/openobject-addons/saas-4-gamification-fixes-mat into lp:~openerp/openobject-addons/saas-4
- saas-4-gamification-fixes-mat
- Merge into saas-4
Proposed by
Martin Trigaux (OpenERP)
Status: | Merged |
---|---|
Merged at revision: | 9362 |
Proposed branch: | lp:~openerp-dev/openobject-addons/saas-4-gamification-fixes-mat |
Merge into: | lp:~openerp/openobject-addons/saas-4 |
Diff against target: |
360 lines (+98/-79) 9 files modified
gamification/data/goal_base.xml (+2/-2) gamification/models/challenge.py (+89/-70) gamification/models/res_users.py (+0/-1) gamification/views/challenge.xml (+1/-0) gamification_sale_crm/sale_crm_goals.xml (+2/-2) website_forum/data/badges_answer.xml (+1/-1) website_forum/data/badges_moderation.xml (+1/-1) website_forum/data/badges_participation.xml (+1/-1) website_forum/data/badges_question.xml (+1/-1) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-addons/saas-4-gamification-fixes-mat |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
OpenERP Core Team | Pending | ||
Review via email: mp+216452@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'gamification/data/goal_base.xml' |
2 | --- gamification/data/goal_base.xml 2014-04-16 15:10:26 +0000 |
3 | +++ gamification/data/goal_base.xml 2014-04-22 07:53:23 +0000 |
4 | @@ -164,7 +164,7 @@ |
5 | <field name="period">once</field> |
6 | <field name="visibility_mode">personal</field> |
7 | <field name="report_message_frequency">never</field> |
8 | - <field name="user_domain">[('groups_id', 'in', ref('base.group_user'))]</field> |
9 | + <field name="user_domain" eval="[('groups_id', '=', ref('base.group_user'))]" /> |
10 | <field name="state">inprogress</field> |
11 | <field name="category">other</field> |
12 | </record> |
13 | @@ -174,7 +174,7 @@ |
14 | <field name="period">once</field> |
15 | <field name="visibility_mode">personal</field> |
16 | <field name="report_message_frequency">never</field> |
17 | - <field name="user_domain">[('groups_id', 'in', ref('base.user_root'))]</field> |
18 | + <field name="user_domain" eval="[('groups_id', '=', ref('base.group_erp_manager'))]" /> |
19 | <field name="state">inprogress</field> |
20 | <field name="category">other</field> |
21 | </record> |
22 | |
23 | === modified file 'gamification/models/challenge.py' |
24 | --- gamification/models/challenge.py 2014-04-18 09:05:20 +0000 |
25 | +++ gamification/models/challenge.py 2014-04-22 07:53:23 +0000 |
26 | @@ -21,14 +21,13 @@ |
27 | |
28 | from openerp import SUPERUSER_ID |
29 | from openerp.osv import fields, osv |
30 | -from openerp.tools import DEFAULT_SERVER_DATE_FORMAT as DF |
31 | +from openerp.tools import ustr, DEFAULT_SERVER_DATE_FORMAT as DF |
32 | from openerp.tools.safe_eval import safe_eval as eval |
33 | from openerp.tools.translate import _ |
34 | |
35 | from datetime import date, datetime, timedelta |
36 | import calendar |
37 | import logging |
38 | -import functools |
39 | _logger = logging.getLogger(__name__) |
40 | |
41 | # display top 3 in ranking, could be db variable |
42 | @@ -117,12 +116,6 @@ |
43 | except ValueError: |
44 | return False |
45 | |
46 | - def _get_challenger_users(self, cr, uid, domain, context=None): |
47 | - ref = functools.partial(self.pool['ir.model.data'].xmlid_to_res_id, cr, uid) |
48 | - user_domain = eval(domain, {'ref': ref}) |
49 | - return self.pool['res.users'].search(cr, uid, user_domain, context=context) |
50 | - |
51 | - |
52 | _order = 'end_date, start_date, name, id' |
53 | _columns = { |
54 | 'name': fields.char('Challenge Name', required=True, translate=True), |
55 | @@ -218,7 +211,6 @@ |
56 | def create(self, cr, uid, vals, context=None): |
57 | """Overwrite the create method to add the user of groups""" |
58 | |
59 | - # add users when change the group auto-subscription |
60 | if vals.get('user_domain'): |
61 | user_ids = self._get_challenger_users(cr, uid, vals.get('user_domain'), context=context) |
62 | |
63 | @@ -240,14 +232,18 @@ |
64 | if isinstance(ids, (int,long)): |
65 | ids = [ids] |
66 | |
67 | + if vals.get('user_domain'): |
68 | + user_ids = self._get_challenger_users(cr, uid, vals.get('user_domain'), context=context) |
69 | + |
70 | + if not vals.get('user_ids'): |
71 | + vals['user_ids'] = [] |
72 | + vals['user_ids'] += [(4, user_id) for user_id in user_ids] |
73 | + |
74 | + write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context) |
75 | + |
76 | if vals.get('state') == 'inprogress': |
77 | - for challenge in self.browse(cr, uid, ids, context=context): |
78 | - user_ids = self._get_challenger_users(cr, uid, challenge.user_domain, context=context) |
79 | - write_op = [(4, user_id) for user_id in user_ids] |
80 | - self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context) |
81 | - self.message_subscribe_users(cr, uid, [challenge.id], user_ids, context=context) |
82 | - |
83 | - self.generate_goals_from_challenge(cr, uid, ids, context=context) |
84 | + self._recompute_challenge_users(cr, uid, ids, context=context) |
85 | + self._generate_goals_from_challenge(cr, uid, ids, context=context) |
86 | |
87 | elif vals.get('state') == 'done': |
88 | self.check_challenge_reward(cr, uid, ids, force=True, context=context) |
89 | @@ -256,9 +252,6 @@ |
90 | # resetting progress |
91 | if self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', 'in', ids), ('state', '=', 'inprogress')], context=context): |
92 | raise osv.except_osv("Error", "You can not reset a challenge with unfinished goals.") |
93 | - |
94 | - write_res = super(gamification_challenge, self).write(cr, uid, ids, vals, context=context) |
95 | - |
96 | |
97 | return write_res |
98 | |
99 | @@ -314,18 +307,10 @@ |
100 | # update every running goal already generated linked to selected challenges |
101 | goal_obj.update(cr, uid, goal_ids, context=context) |
102 | |
103 | + self._recompute_challenge_users(cr, uid, ids, context=context) |
104 | + self._generate_goals_from_challenge(cr, uid, ids, context=context) |
105 | + |
106 | for challenge in self.browse(cr, uid, ids, context=context): |
107 | - # in case of new users matching the domain |
108 | - old_user_ids = [user.id for user in challenge.user_ids] |
109 | - new_user_ids = self._get_challenger_users(cr, uid, challenge.user_domain, context=context) |
110 | - to_remove_ids = list(set(old_user_ids) - set(new_user_ids)) |
111 | - to_add_ids = list(set(new_user_ids) - set(old_user_ids)) |
112 | - |
113 | - write_op = [(3, user_id) for user_id in to_remove_ids] |
114 | - write_op += [(4, user_id) for user_id in to_add_ids] |
115 | - self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context) |
116 | - |
117 | - self.generate_goals_from_challenge(cr, uid, [challenge.id], context=context) |
118 | |
119 | # goals closed but still opened at the last report date |
120 | closed_goals_to_report = goal_obj.search(cr, uid, [ |
121 | @@ -345,11 +330,36 @@ |
122 | return True |
123 | |
124 | def quick_update(self, cr, uid, challenge_id, context=None): |
125 | - """Update all the goals of a challenge, no generation of new goals""" |
126 | + """Update all the goals of a specific challenge, no generation of new goals""" |
127 | goal_ids = self.pool.get('gamification.goal').search(cr, uid, [('challenge_id', '=', challenge_id)], context=context) |
128 | self.pool.get('gamification.goal').update(cr, uid, goal_ids, context=context) |
129 | return True |
130 | |
131 | + def _get_challenger_users(self, cr, uid, domain, context=None): |
132 | + user_domain = eval(ustr(domain)) |
133 | + return self.pool['res.users'].search(cr, uid, user_domain, context=context) |
134 | + |
135 | + def _recompute_challenge_users(self, cr, uid, challenge_ids, context=None): |
136 | + """Recompute the domain to add new users and remove the one no longer matching the domain""" |
137 | + for challenge in self.browse(cr, uid, challenge_ids, context=context): |
138 | + if challenge.user_domain: |
139 | + |
140 | + old_user_ids = [user.id for user in challenge.user_ids] |
141 | + new_user_ids = self._get_challenger_users(cr, uid, challenge.user_domain, context=context) |
142 | + to_remove_ids = list(set(old_user_ids) - set(new_user_ids)) |
143 | + to_add_ids = list(set(new_user_ids) - set(old_user_ids)) |
144 | + |
145 | + write_op = [(3, user_id) for user_id in to_remove_ids] |
146 | + write_op += [(4, user_id) for user_id in to_add_ids] |
147 | + self.write(cr, uid, [challenge.id], {'user_ids': write_op}, context=context) |
148 | + |
149 | + if to_remove_ids: |
150 | + self.message_unsubscribe_users(cr, uid, [challenge.id], to_remove_ids, context=None) |
151 | + if to_add_ids: |
152 | + self.message_subscribe_users(cr, uid, [challenge.id], new_user_ids, context=context) |
153 | + |
154 | + return True |
155 | + |
156 | |
157 | def action_check(self, cr, uid, ids, context=None): |
158 | """Check a challenge |
159 | @@ -370,6 +380,10 @@ |
160 | ##### Automatic actions ##### |
161 | |
162 | def generate_goals_from_challenge(self, cr, uid, ids, context=None): |
163 | + _logger.warning("Deprecated, use private method _generate_goals_from_challenge(...) instead.") |
164 | + return self._generate_goals_from_challenge(cr, uid, ids, context=context) |
165 | + |
166 | + def _generate_goals_from_challenge(self, cr, uid, ids, context=None): |
167 | """Generate the goals for each line and user. |
168 | |
169 | If goals already exist for this line and user, the line is skipped. This |
170 | @@ -388,44 +402,49 @@ |
171 | end_date = challenge.end_date |
172 | |
173 | for line in challenge.line_ids: |
174 | - # FIXME: allow to restrict to a subset of users |
175 | - for user in challenge.user_ids: |
176 | - |
177 | - domain = [('line_id', '=', line.id), ('user_id', '=', user.id)] |
178 | - if start_date: |
179 | - domain.append(('start_date', '=', start_date)) |
180 | - |
181 | - # goal already existing for this line ? |
182 | - if len(goal_obj.search(cr, uid, domain, context=context)) > 0: |
183 | - |
184 | - # resume canceled goals |
185 | - domain.append(('state', '=', 'canceled')) |
186 | - canceled_goal_ids = goal_obj.search(cr, uid, domain, context=context) |
187 | - if canceled_goal_ids: |
188 | - goal_obj.write(cr, uid, canceled_goal_ids, {'state': 'inprogress'}, context=context) |
189 | - to_update.extend(canceled_goal_ids) |
190 | - |
191 | - # skip to next user |
192 | - continue |
193 | - |
194 | - values = { |
195 | - 'definition_id': line.definition_id.id, |
196 | - 'line_id': line.id, |
197 | - 'user_id': user.id, |
198 | - 'target_goal': line.target_goal, |
199 | - 'state': 'inprogress', |
200 | - } |
201 | - |
202 | - if start_date: |
203 | - values['start_date'] = start_date |
204 | - if end_date: |
205 | - values['end_date'] = end_date |
206 | - |
207 | - if challenge.remind_update_delay: |
208 | - values['remind_update_delay'] = challenge.remind_update_delay |
209 | - |
210 | - new_goal_id = goal_obj.create(cr, uid, values, context=context) |
211 | - to_update.append(new_goal_id) |
212 | + |
213 | + # there is potentially a lot of users |
214 | + # detect the ones with no goal linked to this line |
215 | + date_clause = "" |
216 | + query_params = [line.id] |
217 | + if start_date: |
218 | + date_clause += "AND g.start_date = %s" |
219 | + query_params.append(start_date) |
220 | + if end_date: |
221 | + date_clause += "AND g.end_date = %s" |
222 | + query_params.append(end_date) |
223 | + |
224 | + query = """SELECT u.id AS user_id |
225 | + FROM res_users u |
226 | + LEFT JOIN gamification_goal g |
227 | + ON (u.id = g.user_id) |
228 | + WHERE line_id = %s |
229 | + {date_clause} |
230 | + """.format(date_clause=date_clause) |
231 | + |
232 | + cr.execute(query, query_params) |
233 | + user_with_goal_ids = cr.dictfetchall() |
234 | + user_without_goal_ids = list(set([user.id for user in challenge.user_ids]) - set([user['user_id'] for user in user_with_goal_ids])) |
235 | + |
236 | + values = { |
237 | + 'definition_id': line.definition_id.id, |
238 | + 'line_id': line.id, |
239 | + 'target_goal': line.target_goal, |
240 | + 'state': 'inprogress', |
241 | + } |
242 | + |
243 | + if start_date: |
244 | + values['start_date'] = start_date |
245 | + if end_date: |
246 | + values['end_date'] = end_date |
247 | + |
248 | + if challenge.remind_update_delay: |
249 | + values['remind_update_delay'] = challenge.remind_update_delay |
250 | + |
251 | + for user_id in user_without_goal_ids: |
252 | + values.update({'user_id': user_id}) |
253 | + goal_id = goal_obj.create(cr, uid, values, context=context) |
254 | + to_update.append(goal_id) |
255 | |
256 | goal_obj.update(cr, uid, to_update, context=context) |
257 | |
258 | @@ -638,7 +657,7 @@ |
259 | message = "%s has joined the challenge" % user.name |
260 | self.message_post(cr, SUPERUSER_ID, challenge_ids, body=message, context=context) |
261 | self.write(cr, SUPERUSER_ID, challenge_ids, {'invited_user_ids': [(3, user_id)], 'user_ids': [(4, user_id)]}, context=context) |
262 | - return self.generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context) |
263 | + return self._generate_goals_from_challenge(cr, SUPERUSER_ID, challenge_ids, context=context) |
264 | |
265 | # TODO in trunk, remove unused parameter user_id |
266 | def discard_challenge(self, cr, uid, challenge_ids, context=None, user_id=None): |
267 | |
268 | === modified file 'gamification/models/res_users.py' |
269 | --- gamification/models/res_users.py 2014-04-16 15:10:26 +0000 |
270 | +++ gamification/models/res_users.py 2014-04-22 07:53:23 +0000 |
271 | @@ -19,7 +19,6 @@ |
272 | # |
273 | ############################################################################## |
274 | |
275 | -from openerp import SUPERUSER_ID |
276 | from openerp.osv import osv |
277 | from challenge import MAX_VISIBILITY_RANKING |
278 | |
279 | |
280 | === modified file 'gamification/views/challenge.xml' |
281 | --- gamification/views/challenge.xml 2014-04-16 15:22:08 +0000 |
282 | +++ gamification/views/challenge.xml 2014-04-22 07:53:23 +0000 |
283 | @@ -48,6 +48,7 @@ |
284 | <label for="user_domain" class="oe_edit_only" string="Assign Challenge To"/> |
285 | <div> |
286 | <field name="user_domain" widget="char_domain" options="{'model': 'res.users'}" /> |
287 | + <field name="user_ids" groups="base.group_no_one" widget="many2many_tags" /> |
288 | </div> |
289 | </div> |
290 | |
291 | |
292 | === modified file 'gamification_sale_crm/sale_crm_goals.xml' |
293 | --- gamification_sale_crm/sale_crm_goals.xml 2014-04-16 15:34:28 +0000 |
294 | +++ gamification_sale_crm/sale_crm_goals.xml 2014-04-22 07:53:23 +0000 |
295 | @@ -130,7 +130,7 @@ |
296 | <field name="name">Monthly Sales Targets</field> |
297 | <field name="period">monthly</field> |
298 | <field name="visibility_mode">ranking</field> |
299 | - <field name="user_domain">[('groups_id', 'in', ref('base.group_sale_salesman'))]</field> |
300 | + <field name="user_domain" eval="[('groups_id', 'in', ref('base.group_sale_salesman'))]" /> |
301 | <field name="report_message_frequency">weekly</field> |
302 | </record> |
303 | |
304 | @@ -138,7 +138,7 @@ |
305 | <field name="name">Lead Acquisition</field> |
306 | <field name="period">monthly</field> |
307 | <field name="visibility_mode">ranking</field> |
308 | - <field name="user_domain">[('groups_id', 'in', ref('base.group_sale_salesman'))]</field> |
309 | + <field name="user_domain" eval="[('groups_id', 'in', ref('base.group_sale_salesman'))]" />" |
310 | <field name="report_message_frequency">weekly</field> |
311 | </record> |
312 | |
313 | |
314 | === modified file 'website_forum/data/badges_answer.xml' |
315 | --- website_forum/data/badges_answer.xml 2014-04-16 15:10:26 +0000 |
316 | +++ website_forum/data/badges_answer.xml 2014-04-22 07:53:23 +0000 |
317 | @@ -1,6 +1,6 @@ |
318 | <?xml version="1.0" encoding="utf-8"?> |
319 | <openerp> |
320 | - <data> |
321 | + <data noupdate="1"> |
322 | |
323 | <!-- QUALITY (VOTES) --> |
324 | <!-- Teacher: at least 3 upvotes --> |
325 | |
326 | === modified file 'website_forum/data/badges_moderation.xml' |
327 | --- website_forum/data/badges_moderation.xml 2014-04-16 15:14:10 +0000 |
328 | +++ website_forum/data/badges_moderation.xml 2014-04-22 07:53:23 +0000 |
329 | @@ -1,6 +1,6 @@ |
330 | <?xml version="1.0" encoding="utf-8"?> |
331 | <openerp> |
332 | - <data> |
333 | + <data noupdate="1"> |
334 | |
335 | <!-- Cleanup: answer or question edition --> |
336 | <!-- Not rollback feature in forum --> |
337 | |
338 | === modified file 'website_forum/data/badges_participation.xml' |
339 | --- website_forum/data/badges_participation.xml 2014-04-16 15:22:08 +0000 |
340 | +++ website_forum/data/badges_participation.xml 2014-04-22 07:53:23 +0000 |
341 | @@ -1,6 +1,6 @@ |
342 | <?xml version="1.0" encoding="utf-8"?> |
343 | <openerp> |
344 | - <data> |
345 | + <data noupdate="1"> |
346 | |
347 | <!-- Biography: complet your profile --> |
348 | <record id="badge_p_1" model="gamification.badge"> |
349 | |
350 | === modified file 'website_forum/data/badges_question.xml' |
351 | --- website_forum/data/badges_question.xml 2014-04-16 15:14:10 +0000 |
352 | +++ website_forum/data/badges_question.xml 2014-04-22 07:53:23 +0000 |
353 | @@ -1,6 +1,6 @@ |
354 | <!-- <?xml version="1.0" encoding="utf-8"?> --> |
355 | <openerp> |
356 | - <data> |
357 | + <data noupdate="1"> |
358 | |
359 | <!-- POPULARITY (VIEWS) --> |
360 | <!-- Popular: 150 views --> |