Merge lp:~openerp-dev/openobject-addons/trunk-common-action-controller-jas into lp:openobject-addons

Proposed by ajay javiya (OpenERP)
Status: Work in progress
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-common-action-controller-jas
Merge into: lp:openobject-addons
Diff against target: 443 lines (+224/-4)
13 files modified
account/account_invoice.py (+15/-0)
analytic/analytic.py (+21/-0)
crm/crm_lead.py (+18/-0)
event/event.py (+14/-0)
fleet/fleet.py (+15/-0)
fleet/fleet_view.xml (+4/-0)
hr_holidays/hr_holidays.py (+14/-0)
hr_recruitment/hr_recruitment.py (+24/-0)
mail/controllers/main.py (+15/-0)
mail/mail_thread.py (+50/-4)
mail/views/mail_actions_button.html (+6/-0)
project/project.py (+10/-0)
project_issue/project_issue.py (+18/-0)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-common-action-controller-jas
Reviewer Review Type Date Requested Status
OpenERP Core Team Pending
Review via email: mp+219454@code.launchpad.net
To post a comment you must log in.
9452. By Jamin Shah(OpenERP)

[IMP]: Optimization

9453. By Jamin Shah(OpenERP)

[IMP]: change in _mail_action condition and optimization

9454. By Jamin Shah(OpenERP)

[IMP]: add action_xml_id in _mail_object

9455. By Jamin Shah(OpenERP)

[MERGE]: with Trunk

9456. By Jamin Shah(OpenERP)

[IMP]: changes in write() for sending template

9457. By Jamin Shah(OpenERP)

[IMP]: add _mail_actions in hr_applicant and safe coding in mail write method for calling message_post

9458. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9459. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9460. By Jamin Shah(OpenERP)

[MERGE]: with trunk

9461. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9462. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

Unmerged revisions

9462. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9461. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9460. By Jamin Shah(OpenERP)

[MERGE]: with trunk

9459. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9458. By Jamin Shah(OpenERP)

[IMP]: Code Optimization

9457. By Jamin Shah(OpenERP)

[IMP]: add _mail_actions in hr_applicant and safe coding in mail write method for calling message_post

9456. By Jamin Shah(OpenERP)

[IMP]: changes in write() for sending template

9455. By Jamin Shah(OpenERP)

[MERGE]: with Trunk

9454. By Jamin Shah(OpenERP)

[IMP]: add action_xml_id in _mail_object

9453. By Jamin Shah(OpenERP)

[IMP]: change in _mail_action condition and optimization

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account/account_invoice.py'
2--- account/account_invoice.py 2014-05-07 17:01:12 +0000
3+++ account/account_invoice.py 2014-05-20 08:59:26 +0000
4@@ -225,6 +225,21 @@
5 'account.mt_invoice_validated': lambda self, cr, uid, obj, ctx=None: obj.state == 'open' and obj.type in ('out_invoice', 'out_refund'),
6 },
7 }
8+ _mail_actions = [{
9+ 'name': 'invoice_validate',
10+ 'type': 'object',
11+ 'string': 'Validate',
12+ 'condition': lambda self, obj, context=None: obj.state == 'draft',
13+ 'button_type': 'success'
14+ },
15+ {
16+ 'name': 'action_cancel',
17+ 'type': 'object',
18+ 'string': 'Cancel',
19+ 'condition': lambda self, obj, context=None: obj.state == 'draft',
20+ 'button_type': 'warning'
21+ }]
22+
23 _columns = {
24 'name': fields.char('Reference/Description', size=64, select=True, readonly=True, states={'draft':[('readonly',False)]}),
25 'origin': fields.char('Source Document', size=64, help="Reference of the document that produced this invoice.", readonly=True, states={'draft':[('readonly',False)]}),
26
27=== modified file 'analytic/analytic.py'
28--- analytic/analytic.py 2014-04-01 12:36:57 +0000
29+++ analytic/analytic.py 2014-05-20 08:59:26 +0000
30@@ -38,6 +38,27 @@
31 'analytic.mt_account_opened': lambda self, cr, uid, obj, ctx=None: obj.state == 'open',
32 },
33 }
34+ _mail_actions = [{
35+ 'name': 'set_pending',
36+ 'type': 'object',
37+ 'string': 'Renew',
38+ 'condition': lambda self, obj, context=None: obj.state == 'open',
39+ 'button_type': 'success'
40+ },
41+ {
42+ 'name': 'set_close',
43+ 'type': 'object',
44+ 'string': 'Close',
45+ 'condition': lambda self, obj, context=None: obj.state == 'open' or obj.state == 'pending',
46+ 'button_type': 'warning'
47+ },
48+ {
49+ 'name': 'set_cancel',
50+ 'type': 'object',
51+ 'string': 'Cancel',
52+ 'condition': lambda self, obj, context=None: obj.state == 'open' or obj.state == 'pending',
53+ 'button_type': 'warning'
54+ }]
55
56 def _compute_level_tree(self, cr, uid, ids, child_ids, res, field_names, context=None):
57 currency_obj = self.pool.get('res.currency')
58
59=== modified file 'crm/crm_lead.py'
60--- crm/crm_lead.py 2014-05-12 11:41:49 +0000
61+++ crm/crm_lead.py 2014-05-20 08:59:26 +0000
62@@ -79,6 +79,21 @@
63 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.fold and obj.stage_id.sequence > 1,
64 },
65 }
66+ _mail_actions = [{
67+ 'name': 'set_user',
68+ 'type': 'object',
69+ 'string': 'I will manage it',
70+ 'condition': lambda self, obj, context=None: not obj.user_id,
71+ 'button_type': 'success'
72+ },
73+ {
74+ 'type': 'action',
75+ 'string': 'Not interested',
76+ 'condition': lambda self, obj, context=None: not obj.user_id,
77+ 'button_type': 'warning',
78+ 'action_xml_id': 'crm_case_category_act_oppor11',
79+ 'module': 'crm'
80+ }]
81 _mail_mass_mailing = _('Leads / Opportunities')
82
83 def get_empty_list_help(self, cr, uid, help, context=None):
84@@ -317,6 +332,9 @@
85 ('check_probability', 'check(probability >= 0 and probability <= 100)', 'The probability of closing the deal should be between 0% and 100%!')
86 ]
87
88+ def set_user(self, cr, uid, ids, context=None):
89+ self.pool['crm.lead'].write(cr, uid, ids, {'user_id':uid})
90+
91 def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
92 if not stage_id:
93 return {'value': {}}
94
95=== modified file 'event/event.py'
96--- event/event.py 2014-05-12 07:23:31 +0000
97+++ event/event.py 2014-05-20 08:59:26 +0000
98@@ -327,6 +327,20 @@
99 }
100 _order = 'name, create_date desc'
101
102+ _mail_actions = [{
103+ 'name': 'registration_open',
104+ 'type': 'object',
105+ 'string': 'Confirm',
106+ 'condition': lambda self, obj, context=None: obj.state == 'draft',
107+ 'button_type': 'success'
108+ },
109+ {
110+ 'name': 'button_reg_cancel',
111+ 'type': 'object',
112+ 'string': 'Cancel',
113+ 'condition': lambda self, obj, context=None: obj.state == 'draft' or obj.state == 'open',
114+ 'button_type': 'warning'
115+ }]
116
117 def _check_seats_limit(self, cr, uid, ids, context=None):
118 for registration in self.browse(cr, uid, ids, context=context):
119
120=== modified file 'fleet/fleet.py'
121--- fleet/fleet.py 2014-05-07 07:56:45 +0000
122+++ fleet/fleet.py 2014-05-20 08:59:26 +0000
123@@ -792,10 +792,25 @@
124 res[contract.id] = totalsum
125 return res
126
127+ _inherit = ['mail.thread']
128 _inherits = {'fleet.vehicle.cost': 'cost_id'}
129 _name = 'fleet.vehicle.log.contract'
130 _description = 'Contract information on a vehicle'
131 _order='state desc,expiration_date'
132+ _mail_actions = [{
133+ 'name': 'act_renew_contract',
134+ 'type': 'object',
135+ 'string': 'Renew',
136+ 'condition': lambda self, obj, context=None: obj.state == 'open' or obj.state == 'closed',
137+ 'button_type': 'success'
138+ },
139+ {
140+ 'name': 'contract_close',
141+ 'type': 'object',
142+ 'string': 'Terminate',
143+ 'condition': lambda self, obj, context=None: obj.state == 'open',
144+ 'button_type': 'warning'
145+ }]
146 _columns = {
147 'name': fields.function(_vehicle_contract_name_get_fnc, type="text", string='Name', store=True),
148 'start_date': fields.date('Contract Start Date', help='Date when the coverage of the contract begins'),
149
150=== modified file 'fleet/fleet_view.xml'
151--- fleet/fleet_view.xml 2014-03-28 13:30:51 +0000
152+++ fleet/fleet_view.xml 2014-05-20 08:59:26 +0000
153@@ -502,6 +502,10 @@
154 <field name="notes" nolabel="1" placeholder="Write here all other information relative to this contract" />
155 </group>
156 </sheet>
157+ <div class="oe_chatter">
158+ <field name="message_follower_ids" widget="mail_followers"/>
159+ <field name="message_ids" widget="mail_thread"/>
160+ </div>
161 </form>
162 </field>
163 </record>
164
165=== modified file 'hr_holidays/hr_holidays.py'
166--- hr_holidays/hr_holidays.py 2014-05-07 08:35:56 +0000
167+++ hr_holidays/hr_holidays.py 2014-05-20 08:59:26 +0000
168@@ -111,6 +111,20 @@
169 'hr_holidays.mt_holidays_confirmed': lambda self, cr, uid, obj, ctx=None: obj.state == 'confirm',
170 },
171 }
172+ _mail_actions = [{
173+ 'name': 'holidays_validate',
174+ 'type': 'object',
175+ 'string': 'Approve',
176+ 'condition': lambda self, obj, context=None: obj.state == 'confirm',
177+ 'button_type': 'success'
178+ },
179+ {
180+ 'name': 'holidays_refuse',
181+ 'type': 'object',
182+ 'string': 'Refuse',
183+ 'condition': lambda self, obj, context=None: obj.state == 'confirm' or obj.state == 'validate',
184+ 'button_type': 'warning'
185+ }]
186
187 def _employee_get(self, cr, uid, context=None):
188 emp_id = context.get('default_employee_id', False)
189
190=== modified file 'hr_recruitment/hr_recruitment.py'
191--- hr_recruitment/hr_recruitment.py 2014-05-08 12:35:29 +0000
192+++ hr_recruitment/hr_recruitment.py 2014-05-20 08:59:26 +0000
193@@ -87,6 +87,20 @@
194 'hr_recruitment.mt_applicant_stage_changed': lambda self, cr, uid, obj, ctx=None: obj.stage_id and obj.stage_id.sequence > 1,
195 },
196 }
197+ _mail_actions = [{
198+ 'name': 'applicant_first_interview',
199+ 'type': 'object',
200+ 'string': 'Approve',
201+ 'condition': lambda self, obj, context=None: obj.stage_id.name == 'Initial Qualification',
202+ 'button_type': 'success'
203+ },
204+ {
205+ 'name': 'applicant_refused',
206+ 'type': 'object',
207+ 'string': 'Refuse',
208+ 'condition': lambda self, obj, context=None: obj.stage_id.name == 'Initial Qualification',
209+ 'button_type': 'warning'
210+ }]
211 _mail_mass_mailing = _('Applicants')
212
213 def _get_default_department_id(self, cr, uid, context=None):
214@@ -240,6 +254,16 @@
215 'stage_id': _read_group_stage_ids
216 }
217
218+ def applicant_first_interview(self, cr, uid, ids, context=None):
219+ stage_id = self.pool['hr.recruitment.stage'].search(cr, uid, [('name','=','First Interview')], context=context)
220+ if stage_id:
221+ self.pool['hr.applicant'].write(cr, uid, ids, {'stage_id':stage_id[0]}, context=context)
222+
223+ def applicant_refused(self, cr, uid, ids, context=None):
224+ stage_id = self.pool['hr.recruitment.stage'].search(cr, uid, [('name','=','Refused')], context=context)
225+ if stage_id:
226+ self.pool['hr.applicant'].write(cr, uid, ids, {'stage_id':stage_id[0]}, context=context)
227+
228 def onchange_job(self, cr, uid, ids, job_id=False, context=None):
229 department_id = False
230 if job_id:
231
232=== modified file 'mail/controllers/main.py'
233--- mail/controllers/main.py 2014-04-30 11:00:48 +0000
234+++ mail/controllers/main.py 2014-05-20 08:59:26 +0000
235@@ -1,5 +1,6 @@
236 import base64
237 import psycopg2
238+import werkzeug
239
240 import openerp
241 from openerp import SUPERUSER_ID
242@@ -42,3 +43,17 @@
243 except psycopg2.Error:
244 pass
245 return True
246+
247+ @http.route('/mail_action/<model>/<int:id>', type='http', auth='user')
248+ def mail_action(self, model, id, action_name=None, action_type=None, action_id=None):
249+ if not request.session.uid:
250+ return login_redirect()
251+ redirect_url = "/web?db=%s#id=%s&model=%s" %(request.db, id, model)
252+ object_pool = request.registry.get(model)
253+ if action_type in ['workflow','object']:
254+ action = getattr(object_pool,action_name)
255+ action(request.cr, request.uid, [id], context=request.context)
256+ redirect_url += "&view_type=form"
257+ if action_type == 'action':
258+ redirect_url += "&action=%s" % action_id
259+ return werkzeug.utils.redirect(redirect_url)
260
261=== modified file 'mail/mail_thread.py'
262--- mail/mail_thread.py 2014-05-12 10:04:00 +0000
263+++ mail/mail_thread.py 2014-05-20 08:59:26 +0000
264@@ -24,6 +24,8 @@
265 import datetime
266 import dateutil
267 import email
268+import jinja2
269+import sys
270 try:
271 import simplejson as json
272 except ImportError:
273@@ -46,6 +48,14 @@
274
275 _logger = logging.getLogger(__name__)
276
277+if hasattr(sys, 'frozen'):
278+ # When running on compiled windows binary, we don't have access to package loader.
279+ path = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', 'views'))
280+ loader = jinja2.FileSystemLoader(path)
281+else:
282+ loader = jinja2.PackageLoader('openerp.addons.mail', "views")
283+
284+env = jinja2.Environment(loader=loader, autoescape=True)
285
286 def decode_header(message, header, separator=' '):
287 return separator.join(map(decode, filter(None, message.get_all(header, []))))
288@@ -96,6 +106,14 @@
289 # :param obj: is a browse_record
290 # :param function lambda: returns whether the tracking should record using this subtype
291 _track = {}
292+ _default_mail_actions = [{
293+ 'name': 'message_unsubscribe_users',
294+ 'type': 'object',
295+ 'string': 'Mute',
296+ 'condition': lambda self, obj, context=None: True,
297+ 'button_type': 'info'
298+ }]
299+ _mail_actions = []
300
301 # Mass mailing feature
302 _mail_mass_mailing = False
303@@ -346,6 +364,23 @@
304 res['arch'] = etree.tostring(doc)
305 return res
306
307+ def _prepare_body_mail_action(self, cr, uid, obj, context=None):
308+ mail_actions = []
309+ data_pool = self.pool['ir.model.data']
310+ for mail_action in self._mail_actions + self._default_mail_actions:
311+ condition_fn = mail_action['condition']
312+ if mail_action.get('action_xml_id'):
313+ dummy, act_id = data_pool.get_object_reference(cr, uid, mail_action['module'], mail_action['action_xml_id'])
314+ mail_action['xml_id'] = act_id
315+ if condition_fn(self, obj, context=context):
316+ mail_actions.append(mail_action)
317+ mail_actions_body = env.get_template("mail_actions_button.html").render({
318+ 'mail_actions': mail_actions,
319+ 'model': self._name,
320+ 'res_id': obj.id
321+ })
322+ return mail_actions_body
323+
324 #------------------------------------------------------
325 # CRUD overrides for automatic subscription and logging
326 #------------------------------------------------------
327@@ -358,7 +393,6 @@
328 """
329 if context is None:
330 context = {}
331-
332 if context.get('tracking_disable'):
333 return super(mail_thread, self).create(
334 cr, uid, values, context=context)
335@@ -370,11 +404,17 @@
336 message_follower_ids.append([4, pid])
337 values['message_follower_ids'] = message_follower_ids
338 thread_id = super(mail_thread, self).create(cr, uid, values, context=context)
339-
340+ message_body = ''
341+ mail_actions_body = ''
342+ if thread_id:
343+ obj = self.browse(cr, uid, thread_id, context=context)
344+ mail_actions_body = self._prepare_body_mail_action(cr, uid, obj)
345 # automatic logging unless asked not to (mainly for various testing purpose)
346 if not context.get('mail_create_nolog'):
347- self.message_post(cr, uid, thread_id, body=_('%s created') % (self._description), context=context)
348-
349+ message_body +=_('%s created %s') % (self._description, mail_actions_body)
350+ else:
351+ message_body += mail_actions_body
352+ self.message_post(cr, uid, thread_id, body=message_body, context=context)
353 # auto_subscribe: take values and defaults into account
354 create_values = dict(values)
355 for key, val in context.iteritems():
356@@ -415,6 +455,12 @@
357 initial_values = dict((record.id, dict((key, getattr(record, key)) for key in tracked_fields))
358 for record in records)
359
360+ if ids:
361+ obj = self.browse(cr, uid, ids[0], context=context)
362+ mail_actions_body = self._prepare_body_mail_action(cr, uid, obj)
363+ message_body = mail_actions_body
364+ self.message_post(cr, uid, ids[0], body=message_body, context=context)
365+
366 # Perform write, update followers
367 result = super(mail_thread, self).write(cr, uid, ids, values, context=context)
368 self.message_auto_subscribe(cr, uid, ids, values.keys(), context=context, values=values)
369
370=== added file 'mail/views/mail_actions_button.html'
371--- mail/views/mail_actions_button.html 1970-01-01 00:00:00 +0000
372+++ mail/views/mail_actions_button.html 2014-05-20 08:59:26 +0000
373@@ -0,0 +1,6 @@
374+<div name="mail_actions_group">
375+ {% set button_style = {'info': 'background: gray', 'warning': 'background: red', 'success': 'background:green'} %}
376+ {% for button in mail_actions %}
377+ <a class="btn btn-default" name="mail_action" style="color:BLACK;{{ button_style[button.button_type] }}" href="/mail_action/{{ model }}/{{ res_id }}?action_name={{ button.name }}&action_type={{ button.type }}&action_id={{ button.xml_id }}"> {{ button.string }} </a>
378+ {% endfor %}
379+</div>
380
381=== modified file 'project/project.py'
382--- project/project.py 2014-05-13 11:18:37 +0000
383+++ project/project.py 2014-05-20 08:59:26 +0000
384@@ -568,6 +568,13 @@
385 'project.mt_task_ready': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'done',
386 },
387 }
388+ _mail_actions = [{
389+ 'name': 'set_user',
390+ 'type': 'object',
391+ 'string': 'I will do it',
392+ 'condition': lambda self, obj, context=None: not obj.user_id,
393+ 'button_type': 'success'
394+ }]
395
396 def _get_default_partner(self, cr, uid, context=None):
397 project_id = self._get_default_project_id(cr, uid, context)
398@@ -666,6 +673,9 @@
399 res[task.id]['progress'] = 100.0
400 return res
401
402+ def set_user(self, cr, uid, ids, context=None):
403+ self.pool['project.task'].write(cr, uid, ids, {'user_id':uid})
404+
405 def onchange_remaining(self, cr, uid, ids, remaining=0.0, planned=0.0):
406 if remaining and not planned:
407 return {'value': {'planned_hours': remaining}}
408
409=== modified file 'project_issue/project_issue.py'
410--- project_issue/project_issue.py 2014-05-08 15:25:36 +0000
411+++ project_issue/project_issue.py 2014-05-20 08:59:26 +0000
412@@ -60,6 +60,21 @@
413 'project_issue.mt_issue_ready': lambda self, cr, uid, obj, ctx=None: obj.kanban_state == 'done',
414 },
415 }
416+ _mail_actions = [{
417+ 'name': 'set_user',
418+ 'type': 'object',
419+ 'string': 'I will do it',
420+ 'condition': lambda self, obj, context=None: not obj.user_id,
421+ 'button_type': 'success'
422+ },
423+ {
424+ 'type': 'action',
425+ 'string': 'Not interested',
426+ 'condition': lambda self, obj, context=None: not obj.user_id,
427+ 'button_type': 'warning',
428+ 'action_xml_id': 'action_view_issues',
429+ 'module': 'project_issue'
430+ }]
431
432 def _get_default_partner(self, cr, uid, context=None):
433 project_id = self._get_default_project_id(cr, uid, context)
434@@ -306,6 +321,9 @@
435 'stage_id': _read_group_stage_ids
436 }
437
438+ def set_user(self, cr, uid, ids, context=None):
439+ self.pool['project.issue'].write(cr, uid, ids, {'user_id':uid})
440+
441 def copy(self, cr, uid, id, default=None, context=None):
442 issue = self.read(cr, uid, id, ['name'], context=context)
443 if not default:

Subscribers

People subscribed via source and target branches

to all changes: