Merge lp:~savoirfairelinux-openerp/openerp-mgmtsystem/nc-chatter-v7 into lp:openerp-mgmtsystem

Status: Merged
Merged at revision: 80
Proposed branch: lp:~savoirfairelinux-openerp/openerp-mgmtsystem/nc-chatter-v7
Merge into: lp:openerp-mgmtsystem
Diff against target: 1245 lines (+389/-226)
21 files modified
mgmtsystem_action/__openerp__.py (+8/-9)
mgmtsystem_action/mgmtsystem_action.py (+27/-6)
mgmtsystem_action/mgmtsystem_action.xml (+55/-31)
mgmtsystem_audit/__init__.py (+3/-3)
mgmtsystem_audit/__openerp__.py (+10/-10)
mgmtsystem_audit/demo_audit.xml (+1/-0)
mgmtsystem_audit/mgmtsystem_audit.py (+34/-6)
mgmtsystem_audit/mgmtsystem_audit.xml (+108/-30)
mgmtsystem_audit/migrations/7.0.1.0/post-migration.py (+1/-0)
mgmtsystem_audit/report/__init__.py (+2/-2)
mgmtsystem_audit/report/audit_report.py (+3/-2)
mgmtsystem_audit/report/verification_list.py (+4/-11)
mgmtsystem_audit/wizard/__init__.py (+1/-3)
mgmtsystem_audit/wizard/copy_verification_lines.py (+12/-12)
mgmtsystem_nonconformity/__openerp__.py (+13/-14)
mgmtsystem_nonconformity/demo_nonconformity.xml (+1/-0)
mgmtsystem_nonconformity/mgmtsystem_nonconformity.py (+81/-49)
mgmtsystem_nonconformity/mgmtsystem_nonconformity.xml (+8/-28)
mgmtsystem_nonconformity/mgmtsystem_nonconformity_workflow.xml (+4/-4)
mgmtsystem_nonconformity/migrations/7.0.1.0/post-migration.py (+7/-6)
mgmtsystem_nonconformity_deptm/mgmtsystem_nonconformity.py (+6/-0)
To merge this branch: bzr merge lp:~savoirfairelinux-openerp/openerp-mgmtsystem/nc-chatter-v7
Reviewer Review Type Date Requested Status
Daniel Reis Approve
Maxime Chambreuil (http://www.savoirfairelinux.com) review, no test Approve
Review via email: mp+184352@code.launchpad.net

Description of the change

Added OpenChatter integration to Audits, Actions, NCs.
Removed old messaging system.
Added automatic follower subscriptions according to blueprint.
Added custom OpenChatter messages where needed, according to blueprint.
Added automatic emails.

Test follower subscriptions with multiple users (including responsible/owners who are not current user).
Test email messages, esp. links that are included.
Test email formats (HTML, plaintext).
Test state changes -> chatter posts.

Nothing was done to Procedures as per discussion with Max.

To post a comment you must log in.
51. By Sandy Carter (http://www.savoirfairelinux.com)

Added object's direct link to emails.

Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

Thanks Sandy. Please have the conflicts fixed to get this MP approved.

review: Needs Fixing
52. By Sandy Carter (http://www.savoirfairelinux.com)

Merge: lp:openerp-mgmtsystem

53. By Maxime Chambreuil (http://www.savoirfairelinux.com)

[FIX] PEP8 compliance in audit, action and nonconformity

54. By Maxime Chambreuil (http://www.savoirfairelinux.com)

[IMP] Bump versions

Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) :
review: Approve (lgtm, no test)
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

LGTM

review: Approve (review, no test)
Revision history for this message
Daniel Reis (dreis-pt) wrote :

Well done, great work there Sandy!

There some minor details I think could be improved:

* The text for the chatter notifications could be improved, to be similar to the text used in Project Issues. For example, instead notifications with of just "Analysis" or "Pending Approval", or even " has been opened.", we would have something like:
"""
Stage changed
    • Stage: New → Pending
"""
The "Analysis Approved" and "Action Plan Approved" look fine for me, and could be kept..

* I also suggest for the buttons to change to previous states to be in a different colour (I suggest blue):
  - At "Pending Approval" state, the "Send for Analysis" button
  - At the "In Progress" state, the "Send for Review".
You might have to create additions buttons for the same actions.

Thanks!

review: Needs Fixing
Revision history for this message
Daniel Reis (dreis-pt) wrote :

PS: at line 280, is there a reason to add inheritance on crm.claim to Audits? Shouldn't it inherit from mail.thread directly?

Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote :

Thank you for the feedback.

With mail.thread, without crm.claim:
"""
ValidateError

Error occurred while validating the field(s) arch: Invalid XML for View Architecture!
"""
"""
2013-09-09 14:10:48,496 4912 ERROR dev openerp.osv.orm: Can't find field 'user_id' in the following view parts composing the view of object model 'mgmtsystem.audit':
 * mgmtsystem.audit.form

Either you wrongly customized this view, or some modules bringing those views are not compatible with your current data model
"""
I added it to match actions.

Revision history for this message
Sandy Carter (http://www.savoirfairelinux.com) (sandy-carter) wrote :

> """
> Stage changed
> • Stage: New → Pending
> """

I'm pretty sure that:
"""
Stage: New → Settled
"""
is the default message for OpenChatter when states change (see Actions -> close)

55. By Sandy Carter (http://www.savoirfairelinux.com)

Improvement to NC chatter state change messages.

56. By Sandy Carter (http://www.savoirfairelinux.com)

Buttons that change state backwards (towards draft) are no longer highlighted.

Revision history for this message
Daniel Reis (dreis-pt) wrote :

The messages looks great now Sandy, thanks.

Note that there is still a problem on the message when going from Pending Approval to In Progress:
it displays a cut-out sentence: " has been opened.".
I did further checking on this, and the prefix is provided by case_get_note_msg_prefix() (see base_status/base_stage.py#166). It needs to be overridden to return "Nonconformity".

Regarding Audits and crm.claim, for some strange reason 'user_id' is not defined in mgmtsystem_audit.py!
You can solve this with:
 31 _inherit = ['mail.thread']
 33 _columns = {
 34 'user_id': fields.many2one('res.users', 'Audit Manager'),

review: Needs Fixing
57. By Sandy Carter (http://www.savoirfairelinux.com)

Make audit inherit mail.thread instead of crm.claim

58. By Sandy Carter (http://www.savoirfairelinux.com)

Prefix overwriten for Nonconformity

59. By Sandy Carter (http://www.savoirfairelinux.com)

Fix to integrity check error

Revision history for this message
Daniel Reis (dreis-pt) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'mgmtsystem_action/__openerp__.py'
2--- mgmtsystem_action/__openerp__.py 2013-08-26 03:22:45 +0000
3+++ mgmtsystem_action/__openerp__.py 2013-09-10 15:25:36 +0000
4@@ -19,12 +19,12 @@
5 #
6 ##############################################################################
7 {
8- "name" : "Management System - Action",
9- "version" : "1.1",
10- "author" : "Savoir-faire Linux",
11- "website" : "http://www.savoirfairelinux.com",
12- "license" : "AGPL-3",
13- "category" : "Management System",
14+ "name": "Management System - Action",
15+ "version": "1.2",
16+ "author": "Savoir-faire Linux",
17+ "website": "http://www.savoirfairelinux.com",
18+ "license": "AGPL-3",
19+ "category": "Management System",
20 "description": """\
21 This module enables you to manage the different actions of your management system:
22 * immediate actions
23@@ -41,8 +41,7 @@
24 'mgmtsystem_action.xml',
25 'board_mgmtsystem_action.xml',
26 ],
27- "demo" : ['demo_action.xml',],
28- "installable" : True,
29+ "demo": ['demo_action.xml'],
30+ "installable": True,
31 }
32 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
33-
34
35=== modified file 'mgmtsystem_action/mgmtsystem_action.py'
36--- mgmtsystem_action/mgmtsystem_action.py 2013-08-25 14:58:18 +0000
37+++ mgmtsystem_action/mgmtsystem_action.py 2013-09-10 15:25:36 +0000
38@@ -1,6 +1,6 @@
39 # -*- encoding: utf-8 -*-
40 ##############################################################################
41-#
42+#
43 # OpenERP, Open Source Management Solution
44 # Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
45 #
46@@ -15,13 +15,17 @@
47 # GNU Affero General Public License for more details.
48 #
49 # You should have received a copy of the GNU Affero General Public License
50-# along with this program. If not, see <http://www.gnu.org/licenses/>.
51+# along with this program. If not, see <http://www.gnu.org/licenses/>.
52 #
53 ##############################################################################
54
55+from tools.translate import _
56+from urllib import urlencode
57+from urlparse import urljoin
58 from openerp.osv import fields, orm
59 from crm import crm
60
61+
62 class mgmtsystem_action(orm.Model):
63 _name = "mgmtsystem.action"
64 _description = "Action"
65@@ -33,10 +37,6 @@
66 ('prevention', 'Preventive Action'),
67 ('improvement', 'Improvement Opportunity')],
68 'Response Type'),
69- 'message_ids': fields.one2many('mail.message',
70- 'res_id',
71- 'Messages',
72- domain=[('model','=',_name)]),
73 'system_id': fields.many2one('mgmtsystem.system', 'System'),
74 'company_id': fields.many2one('res.company', 'Company')
75 }
76@@ -52,4 +52,25 @@
77 }, context=context)
78 return super(mgmtsystem_action, self).create(cr, uid, vals, context=context)
79
80+ def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None):
81+ """Automatically add the responsible user to the follow list."""
82+ for o in self.browse(cr, uid, ids, context=context):
83+ self.message_subscribe_users(cr, uid, ids, user_ids=[o.user_id.id], subtype_ids=None, context=context)
84+ return super(mgmtsystem_action, self).message_auto_subscribe(cr, uid, ids, updated_fields, context=context)
85+
86+ def case_close(self, cr, uid, ids, context=None):
87+ """When Action is closed, post a message on the related NC's chatter"""
88+ for o in self.browse(cr, uid, ids, context=context):
89+ for nc in o.nonconformity_ids:
90+ nc.case_send_note(_('Action "%s" was closed.' % o.name))
91+ return super(mgmtsystem_action, self).case_close(cr, uid, ids, context=context)
92+
93+ def get_action_url(self, cr, uid, ids, context=None):
94+ assert len(ids) == 1
95+ action = self.browse(cr, uid, ids[0], context=context)
96+ base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context)
97+ query = {'db': cr.dbname}
98+ fragment = {'id': action.id, 'model': self._name}
99+ return urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment)))
100+
101 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
102
103=== modified file 'mgmtsystem_action/mgmtsystem_action.xml'
104--- mgmtsystem_action/mgmtsystem_action.xml 2013-08-25 15:20:05 +0000
105+++ mgmtsystem_action/mgmtsystem_action.xml 2013-09-10 15:25:36 +0000
106@@ -57,40 +57,27 @@
107 <button name="case_close" string="Close" states="draft,open" type="object" icon="gtk-jump-to"/>
108 <field name="state" widget="statusbar" statusbar_visible="draft,open,pending,done"/>
109 </header>
110- <group colspan="4" col="4">
111- <field name="name" colspan="4"/>
112- <field name="type_action" required="True"/>
113- <field name="reference"/>
114- <field name="user_id" string="Responsible" required="1"/>
115- <field name="date" string="Date"/>
116- <field name="date_deadline" string="Deadline"/>
117- <field name="system_id"/>
118- <field name="company_id" groups="base.group_multi_company"/>
119- </group>
120- <notebook colspan="4">
121+ <sheet string="Action">
122+ <group colspan="4" col="4">
123+ <field name="name" colspan="4"/>
124+ <field name="type_action" required="True"/>
125+ <field name="reference"/>
126+ <field name="user_id" string="Responsible" required="1"/>
127+ <field name="date" string="Date"/>
128+ <field name="date_deadline" string="Deadline"/>
129+ <field name="system_id"/>
130+ <field name="company_id" groups="base.group_multi_company"/>
131+ </group>
132+ <notebook colspan="4">
133 <page string="Description">
134 <field name="description" colspan="4" nolabel="1"/>
135 </page>
136- <page string="History">
137- <group colspan="4">
138- <field colspan="4" name="email_cc" string="Global CC" widget="char"/>
139- </group>
140- <field name="message_ids" colspan="4" nolabel="1" mode="tree" readonly="1">
141- <tree string="History">
142- <field name="subject" string="History Information"/>
143- <field name="email_from" invisible="1"/>
144- <button
145- string="Reply" attrs="{'invisible': [('email_from', '=', False)]}"
146- name="%(mail.action_email_compose_message_wizard)d"
147- context="{'mail.compose.message.mode':'reply', 'message_id':active_id}"
148- icon="terp-mail-replied" type="action" />
149- </tree>
150- </field>
151- <button string="Send New Email"
152- name="%(mail.action_email_compose_message_wizard)d"
153- icon="terp-mail-message-new" type="action"/>
154- </page>
155- </notebook>
156+ </notebook>
157+ </sheet>
158+ <div class="oe_chatter">
159+ <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
160+ <field name="message_ids" widget="mail_thread"/>
161+ </div>
162 </form>
163 </field>
164 </record>
165@@ -112,4 +99,41 @@
166 groups="mgmtsystem.group_mgmtsystem_manager,mgmtsystem.group_mgmtsystem_auditor,base.group_user"/>
167
168 </data>
169+
170+ <data noupdate="1">
171+ <!-- Email template for Action Reminders -->
172+ <record id="action_email_reminder_action" model="ir.actions.server">
173+ <field name="name">Reminder to Responsible</field>
174+ <field name="model_id" ref="model_mgmtsystem_action"/>
175+ <field name="condition">True</field>
176+ <field name="type">ir.actions.server</field>
177+ <field name="state">email</field>
178+ <field name="email">object.user_id.email</field>
179+ <field name="subject">Reminder on Action: "[[object.name]]"</field>
180+ <field name="message">
181+Hello,
182+
183+This is an automated message to remind you that the following action is due to be completed in 10 days ([[object.date_deadline]]):
184+
185+[[object.get_action_url()]]
186+
187+
188+Thank you and have a nice day.
189+--
190+OpenERP
191+ </field>
192+ </record>
193+
194+ <!-- Automated Action: Email reponsible user 10 days before deadline. -->
195+ <record id="rule_set_reminder_action" model="base.action.rule">
196+ <field name="name">Email Action Reminders 10 days before due date.</field>
197+ <field name="model_id" ref="model_mgmtsystem_action"/>
198+ <field name="trg_date_id" ref="field_mgmtsystem_action_date_deadline"/>
199+ <field name="trg_date_range">-10</field>
200+ <field name="trg_date_range_type">day</field>
201+ <field name="server_action_ids" eval="[(6, 0, [ref('action_email_reminder_action')])]"/>
202+ </record>
203+
204+ </data>
205+
206 </openerp>
207
208=== modified file 'mgmtsystem_audit/__init__.py'
209--- mgmtsystem_audit/__init__.py 2013-03-04 14:34:30 +0000
210+++ mgmtsystem_audit/__init__.py 2013-09-10 15:25:36 +0000
211@@ -1,5 +1,5 @@
212 # -*- encoding: utf-8 -*-
213-import mgmtsystem_audit
214-import report
215-import wizard
216+from . import mgmtsystem_audit
217+from . import report
218+from . import wizard
219 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
220
221=== modified file 'mgmtsystem_audit/__openerp__.py'
222--- mgmtsystem_audit/__openerp__.py 2013-08-26 03:22:45 +0000
223+++ mgmtsystem_audit/__openerp__.py 2013-09-10 15:25:36 +0000
224@@ -19,17 +19,17 @@
225 #
226 ##############################################################################
227 {
228- "name" : "Management System - Audit",
229- "version" : "1.1",
230- "author" : "Savoir-faire Linux",
231- "website" : "http://www.savoirfairelinux.com",
232- "license" : "AGPL-3",
233- "category" : "Management System",
234+ "name": "Management System - Audit",
235+ "version": "1.2",
236+ "author": "Savoir-faire Linux",
237+ "website": "http://www.savoirfairelinux.com",
238+ "license": "AGPL-3",
239+ "category": "Management System",
240 "description": """\
241 This module enables you to manage audits and verifications lists of your management system.
242 """,
243 "depends": ['mgmtsystem_nonconformity'],
244- "data" : [
245+ "data": [
246 'security/ir.model.access.csv',
247 'security/mgmtsystem_audit_security.xml',
248 'audit_sequence.xml',
249@@ -39,10 +39,10 @@
250 'board_mgmtsystem_audit.xml',
251 'wizard/copy_verification_lines.xml',
252 ],
253- "demo" : [
254+ "demo": [
255 'demo_audit.xml',
256 ],
257- "installable" : True,
258- "certificate" : ''
259+ "installable": True,
260+ "certificate": ''
261 }
262 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
263
264=== modified file 'mgmtsystem_audit/demo_audit.xml'
265--- mgmtsystem_audit/demo_audit.xml 2012-03-09 23:47:59 +0000
266+++ mgmtsystem_audit/demo_audit.xml 2013-09-10 15:25:36 +0000
267@@ -7,6 +7,7 @@
268 <field name="date">2010-12-03</field>
269 <field name="strong_points">* Good documentation</field>
270 <field name="to_improve_points">* Procedure respect</field>
271+ <field name="user_id" ref="base.user_demo"/>
272 <field name="auditor_user_ids" eval="[(6,0,[ref('base.user_demo')])]"/>
273 <field name="auditee_user_ids" eval="[(6,0,[ref('base.user_root')])]"/>
274 <field name="imp_opp_ids" eval="[(6,0,[ref('mgmtsystem_action.demo_improvement')])]"/>
275
276=== modified file 'mgmtsystem_audit/mgmtsystem_audit.py'
277--- mgmtsystem_audit/mgmtsystem_audit.py 2013-08-25 15:20:05 +0000
278+++ mgmtsystem_audit/mgmtsystem_audit.py 2013-09-10 15:25:36 +0000
279@@ -19,24 +19,29 @@
280 #
281 ##############################################################################
282
283+from tools.translate import _
284 from openerp.osv import fields, orm
285+from urllib import urlencode
286+from urlparse import urljoin
287
288
289 class mgmtsystem_audit(orm.Model):
290 _name = "mgmtsystem.audit"
291 _description = "Audit"
292+ _inherit = ['mail.thread']
293 _columns = {
294 'name': fields.char('Name', size=50),
295 'reference': fields.char('Reference', size=64, required=True, readonly=True),
296 'date': fields.datetime('Date'),
297- 'line_ids': fields.one2many('mgmtsystem.verification.line','audit_id','Verification List'),
298- 'auditor_user_ids': fields.many2many('res.users','mgmtsystem_auditor_user_rel','user_id','mgmtsystem_audit_id','Auditors'),
299- 'auditee_user_ids': fields.many2many('res.users','mgmtsystem_auditee_user_rel','user_id','mgmtsystem_audit_id','Auditees'),
300+ 'line_ids': fields.one2many('mgmtsystem.verification.line', 'audit_id', 'Verification List'),
301+ 'user_id': fields.many2one('res.users', 'Audit Manager'),
302+ 'auditor_user_ids': fields.many2many('res.users', 'mgmtsystem_auditor_user_rel', 'user_id', 'mgmtsystem_audit_id', 'Auditors'),
303+ 'auditee_user_ids': fields.many2many('res.users', 'mgmtsystem_auditee_user_rel', 'user_id', 'mgmtsystem_audit_id', 'Auditees'),
304 'strong_points': fields.text('Strong Points'),
305 'to_improve_points': fields.text('Points To Improve'),
306- 'imp_opp_ids': fields.many2many('mgmtsystem.action','mgmtsystem_audit_imp_opp_rel','mgmtsystem_action_id','mgmtsystem_audit_id','Improvement Opportunities'),
307+ 'imp_opp_ids': fields.many2many('mgmtsystem.action', 'mgmtsystem_audit_imp_opp_rel', 'mgmtsystem_action_id', 'mgmtsystem_audit_id', 'Improvement Opportunities'),
308 'nonconformity_ids': fields.many2many('mgmtsystem.nonconformity', string='Nonconformities'),
309- 'state': fields.selection([('open','Open'),('done','Closed')], 'State'),
310+ 'state': fields.selection([('open', 'Open'), ('done', 'Closed')], 'State'),
311 'system_id': fields.many2one('mgmtsystem.system', 'System'),
312 'company_id': fields.many2one('res.company', 'Company')
313 }
314@@ -54,14 +59,37 @@
315 return super(mgmtsystem_audit, self).create(cr, uid, vals, context)
316
317 def button_close(self, cr, uid, ids, context=None):
318+ """When Audit is closed, post a message to followers' chatter."""
319+ self.message_post(cr, uid, ids, _("Audit closed"), context=context)
320 return self.write(cr, uid, ids, {'state': 'done'})
321
322+ def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None):
323+ """Automatically add the Auditors, Auditees and Audit Manager to the follow list"""
324+ for o in self.browse(cr, uid, ids, context=context):
325+ user_ids = [o.user_id.id]
326+ user_ids += [a.id for a in o.auditor_user_ids]
327+ user_ids += [a.id for a in o.auditee_user_ids]
328+ self.message_subscribe_users(cr, uid, ids, user_ids=user_ids, subtype_ids=None, context=context)
329+ return super(mgmtsystem_audit, self).message_auto_subscribe(cr, uid, ids, updated_fields, context=context)
330+
331+ def get_audit_url(self, cr, uid, ids, context=None):
332+ """
333+ Return a short link to the audit form view
334+ eg. http://localhost:8069/?db=prod#id=1&model=mgmtsystem.audit
335+ """
336+ assert len(ids) == 1
337+ audit = self.browse(cr, uid, ids[0], context=context)
338+ base_url = self.pool.get('ir.config_parameter').get_param(cr, uid, 'web.base.url', default='http://localhost:8069', context=context)
339+ query = {'db': cr.dbname}
340+ fragment = {'id': audit.id, 'model': self._name}
341+ return urljoin(base_url, "?%s#%s" % (urlencode(query), urlencode(fragment)))
342+
343
344 class mgmtsystem_verification_line(orm.Model):
345 _name = "mgmtsystem.verification.line"
346 _description = "Verification Line"
347 _columns = {
348- 'name': fields.char('Question',size=300, required=True),
349+ 'name': fields.char('Question', size=300, required=True),
350 'audit_id': fields.many2one('mgmtsystem.audit', 'Audit', ondelete='cascade', select=True),
351 'procedure_id': fields.many2one('document.page', 'Procedure', ondelete='cascade', select=True),
352 'is_conformed': fields.boolean('Is conformed'),
353
354=== modified file 'mgmtsystem_audit/mgmtsystem_audit.xml'
355--- mgmtsystem_audit/mgmtsystem_audit.xml 2013-08-25 15:20:05 +0000
356+++ mgmtsystem_audit/mgmtsystem_audit.xml 2013-09-10 15:25:36 +0000
357@@ -112,36 +112,43 @@
358 <button name="button_close" string="Close" states="open" type="object" icon="gtk-jump-to"/>
359 <field name="state" widget="statusbar" select="1" readonly="1"/>
360 </header>
361- <group col="8" colspan="6">
362- <field name="name" attrs="{'readonly':[('state','=','done')]}"/>
363- <field name="reference"/>
364- <field name="date" attrs="{'readonly':[('state','=','done')]}"/>
365- <field name="system_id"/>
366- <field name="company_id" groups="base.group_multi_company"/>
367- </group>
368- <notebook colspan="4">
369- <page string="Auditors">
370- <field name="auditor_user_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
371- </page>
372- <page string="Auditees">
373- <field name="auditee_user_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
374- </page>
375- <page string="Verification List">
376- <field name="line_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
377- </page>
378- <page string="Strong Points">
379- <field name="strong_points" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
380- </page>
381- <page string="To Improve Points">
382- <field name="to_improve_points" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
383- </page>
384- <page string="Improvement Opportunities">
385- <field name="imp_opp_ids" domain="[('type_action','=','improvement')]" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
386- </page>
387- <page string="Nonconformities">
388- <field name="nonconformity_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
389- </page>
390- </notebook>
391+ <sheet string="Audit">
392+ <group col="4" colspan="2">
393+ <field name="name" attrs="{'readonly':[('state','=','done')]}"/>
394+ <field name="reference"/>
395+ <field name="date" attrs="{'readonly':[('state','=','done')]}"/>
396+ <field name="user_id" string="Audit Manager" required="1"/>
397+ <field name="company_id" groups="base.group_multi_company"/>
398+ <field name="system_id"/>
399+ </group>
400+ <notebook colspan="4">
401+ <page string="Auditors">
402+ <field name="auditor_user_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
403+ </page>
404+ <page string="Auditees">
405+ <field name="auditee_user_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
406+ </page>
407+ <page string="Verification List">
408+ <field name="line_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
409+ </page>
410+ <page string="Strong Points">
411+ <field name="strong_points" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
412+ </page>
413+ <page string="To Improve Points">
414+ <field name="to_improve_points" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
415+ </page>
416+ <page string="Improvement Opportunities">
417+ <field name="imp_opp_ids" domain="[('type_action','=','improvement')]" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
418+ </page>
419+ <page string="Nonconformities">
420+ <field name="nonconformity_ids" nolabel="1" attrs="{'readonly':[('state','=','done')]}"/>
421+ </page>
422+ </notebook>
423+ </sheet>
424+ <div class="oe_chatter">
425+ <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
426+ <field name="message_ids" widget="mail_thread"/>
427+ </div>
428 </form>
429 </field>
430 </record>
431@@ -193,4 +200,75 @@
432 </record>
433
434 </data>
435+
436+ <data noupdate="1">
437+ <!-- Email template for "Prepare to audit" message to all auditors. -->
438+ <record id="action_email_prepare_to_audit" model="ir.actions.server">
439+ <field name="name">Prepare to audit</field>
440+ <field name="model_id" ref="model_mgmtsystem_audit"/>
441+ <field name="condition">True</field>
442+ <field name="type">ir.actions.server</field>
443+ <field name="state">email</field>
444+ <field name="email">",".join(set([ i.email for i in object.auditor_user_ids ]))</field>
445+ <field name="subject">Prepare to Audit: "[[object.name]]"</field>
446+ <field name="message">
447+Hello,
448+
449+The audit "[[object.name]]" is scheduled in 2 weeks.
450+Please prepare the verification list:
451+
452+[[object.get_audit_url()]]
453+
454+
455+Thank you.
456+--
457+OpenERP
458+ </field>
459+ </record>
460+ <!-- Automated Action: Email all auditors 2 weeks before Audit. -->
461+ <record id="rule_set_prepare_to_audit" model="base.action.rule">
462+ <field name="name">Email all auditors 2 weeks before audit.</field>
463+ <field name="model_id" ref="model_mgmtsystem_audit"/>
464+ <field name="trg_date_id" ref="field_mgmtsystem_audit_date"/>
465+ <field name="trg_date_range">14</field>
466+ <field name="trg_date_range_type">day</field>
467+ <field name="server_action_ids" eval="[(6, 0, [ref('action_email_prepare_to_audit')])]"/>
468+ </record>
469+ </data>
470+
471+ <data noupdate="1">
472+ <!-- Email template for "Send verification list" message to all followers -->
473+ <record id="action_email_send_verification_list" model="ir.actions.server">
474+ <field name="name">Send Verification List</field>
475+ <field name="model_id" ref="model_mgmtsystem_audit"/>
476+ <field name="condition">True</field>
477+ <field name="type">ir.actions.server</field>
478+ <field name="state">email</field>
479+ <field name="email">",".join(set([i.email for i in object.auditor_user_ids] + [i.email for i in object.auditee_user_ids] + [object.user_id.email]))</field>
480+ <field name="subject">Send Verification List: "[[object.name]]"</field>
481+ <field name="message">
482+Hello,
483+
484+The audit "[[object.name]]" is scheduled in 1 week.
485+Please finish the verification list and send it to the auditees:
486+
487+[[object.get_audit_url()]]
488+
489+
490+Thank you.
491+--
492+OpenERP
493+ </field>
494+ </record>
495+ <!-- Automated Action: Email all followers 1 weeks before Audit. -->
496+ <record id="rule_set_send_verification_list" model="base.action.rule">
497+ <field name="name">Email all followers 1 week before audit.</field>
498+ <field name="model_id" ref="model_mgmtsystem_audit"/>
499+ <field name="trg_date_id" ref="field_mgmtsystem_audit_date"/>
500+ <field name="trg_date_range">7</field>
501+ <field name="trg_date_range_type">day</field>
502+ <field name="server_action_ids" eval="[(6, 0, [ref('action_email_send_verification_list')])]"/>
503+ </record>
504+ </data>
505+
506 </openerp>
507
508=== modified file 'mgmtsystem_audit/migrations/7.0.1.0/post-migration.py'
509--- mgmtsystem_audit/migrations/7.0.1.0/post-migration.py 2013-04-01 19:13:26 +0000
510+++ mgmtsystem_audit/migrations/7.0.1.0/post-migration.py 2013-09-10 15:25:36 +0000
511@@ -25,6 +25,7 @@
512
513 logger = logging.getLogger('upgrade')
514
515+
516 def migrate(cr, version):
517 logger.info("Migrating mgmtsystem_audit from version %s", version)
518
519
520=== modified file 'mgmtsystem_audit/report/__init__.py'
521--- mgmtsystem_audit/report/__init__.py 2012-12-17 17:18:12 +0000
522+++ mgmtsystem_audit/report/__init__.py 2013-09-10 15:25:36 +0000
523@@ -1,4 +1,4 @@
524 # -*- encoding: utf-8 -*-
525-import audit_report
526-import verification_list
527+from . import audit_report
528+from . import verification_list
529 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
530
531=== modified file 'mgmtsystem_audit/report/audit_report.py'
532--- mgmtsystem_audit/report/audit_report.py 2013-05-29 16:51:38 +0000
533+++ mgmtsystem_audit/report/audit_report.py 2013-09-10 15:25:36 +0000
534@@ -1,6 +1,6 @@
535 # -*- encoding: utf-8 -*-
536 ##############################################################################
537-#
538+#
539 # OpenERP, Open Source Management Solution
540 # Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
541 #
542@@ -15,13 +15,14 @@
543 # GNU Affero General Public License for more details.
544 #
545 # You should have received a copy of the GNU Affero General Public License
546-# along with this program. If not, see <http://www.gnu.org/licenses/>.
547+# along with this program. If not, see <http://www.gnu.org/licenses/>.
548 #
549 ##############################################################################
550
551 import time
552 from report import report_sxw
553
554+
555 class mgmtsystem_audit_report(report_sxw.rml_parse):
556 def __init__(self, cr, uid, name, context):
557 super(mgmtsystem_audit_report, self).__init__(cr, uid, name, context)
558
559=== modified file 'mgmtsystem_audit/report/verification_list.py'
560--- mgmtsystem_audit/report/verification_list.py 2013-05-29 16:51:38 +0000
561+++ mgmtsystem_audit/report/verification_list.py 2013-09-10 15:25:36 +0000
562@@ -1,6 +1,6 @@
563 # -*- encoding: utf-8 -*-
564 ##############################################################################
565-#
566+#
567 # OpenERP, Open Source Management Solution
568 # Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
569 #
570@@ -15,13 +15,14 @@
571 # GNU Affero General Public License for more details.
572 #
573 # You should have received a copy of the GNU Affero General Public License
574-# along with this program. If not, see <http://www.gnu.org/licenses/>.
575+# along with this program. If not, see <http://www.gnu.org/licenses/>.
576 #
577 ##############################################################################
578
579 import time
580 from report import report_sxw
581
582+
583 class mgmtsystem_audit_verification_list(report_sxw.rml_parse):
584 def __init__(self, cr, uid, name, context):
585 super(mgmtsystem_audit_verification_list, self).__init__(cr, uid, name, context)
586@@ -32,7 +33,6 @@
587 self.context = context
588
589 def get_lines_by_procedure(self, verification_lines):
590- v = {}
591 p = []
592 for l in verification_lines:
593 proc_nm = self.pool.get('document.page').read(self.cr, self.uid, l.procedure_id.id, ['name'])
594@@ -40,16 +40,13 @@
595 "procedure": proc_nm['name'],
596 "name": l.name,
597 "yes_no": "Yes / No"})
598-
599 p = sorted(p, key=lambda k: k["procedure"])
600-
601 proc_line = False
602 q = []
603 proc_name = ''
604 for i in range(len(p)):
605 if proc_name != p[i]['procedure']:
606 proc_line = True
607-
608 if proc_line:
609 q.append({"id": p[i]['id'],
610 "procedure": p[i]['procedure'],
611@@ -57,16 +54,12 @@
612 "yes_no": ""})
613 proc_line = False
614 proc_name = p[i]['procedure']
615-
616 q.append({"id": p[i]['id'],
617 "procedure": "",
618 "name": p[i]['name'],
619 "yes_no": "Yes / No"})
620-
621-
622-
623 return q
624-
625+
626 report_sxw.report_sxw(
627 'report.mgmtsystem.audit.verificationlist',
628 'mgmtsystem.audit',
629
630=== modified file 'mgmtsystem_audit/wizard/__init__.py'
631--- mgmtsystem_audit/wizard/__init__.py 2012-12-17 17:18:12 +0000
632+++ mgmtsystem_audit/wizard/__init__.py 2013-09-10 15:25:36 +0000
633@@ -1,5 +1,3 @@
634 # -*- encoding: utf-8 -*-
635-
636-import copy_verification_lines
637-
638+from . import copy_verification_lines
639 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
640
641=== modified file 'mgmtsystem_audit/wizard/copy_verification_lines.py'
642--- mgmtsystem_audit/wizard/copy_verification_lines.py 2012-12-17 17:18:12 +0000
643+++ mgmtsystem_audit/wizard/copy_verification_lines.py 2013-09-10 15:25:36 +0000
644@@ -1,6 +1,6 @@
645 # -*- encoding: utf-8 -*-
646 ##############################################################################
647-#
648+#
649 # OpenERP, Open Source Management Solution
650 # Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
651 #
652@@ -15,25 +15,25 @@
653 # GNU Affero General Public License for more details.
654 #
655 # You should have received a copy of the GNU Affero General Public License
656-# along with this program. If not, see <http://www.gnu.org/licenses/>.
657+# along with this program. If not, see <http://www.gnu.org/licenses/>.
658 #
659 ##############################################################################
660
661 from osv import fields, osv
662
663+
664 class copy_verification_lines(osv.osv_memory):
665 """
666 Copy Verification Lines
667 """
668 _name = "copy.verification.lines"
669 _description = "Copy Verification Lines"
670-
671 _columns = {
672- 'audit_src': fields.many2one('mgmtsystem.audit','Choose audit'),
673+ 'audit_src': fields.many2one('mgmtsystem.audit', 'Choose audit'),
674 }
675
676 def copy(self, cr, uid, ids, context=None):
677- # Code to copy verification lines from the chosen audit to the current one
678+ # Code to copy verification lines from the chosen audit to the current one
679 if context is None:
680 context = {}
681
682@@ -42,14 +42,14 @@
683 src_id = self.read(cr, uid, ids, [], context=context)[0]['audit_src'][0]
684
685 for line in audit_proxy.browse(cr, uid, src_id, context=context).line_ids:
686- verification_line_proxy.create(cr,uid, {
687- 'seq' : line.seq,
688- 'name' : line.name,
689- 'audit_id' : context['active_id'],
690- 'procedure_id' : line.procedure_id.id,
691- 'is_conformed' : False,
692+ verification_line_proxy.create(cr, uid, {
693+ 'seq': line.seq,
694+ 'name': line.name,
695+ 'audit_id': context['active_id'],
696+ 'procedure_id': line.procedure_id.id,
697+ 'is_conformed': False,
698 }, context=context)
699- return {'type':'ir.actions.act_window_close'}
700+ return {'type': 'ir.actions.act_window_close'}
701
702 copy_verification_lines()
703
704
705=== modified file 'mgmtsystem_nonconformity/__openerp__.py'
706--- mgmtsystem_nonconformity/__openerp__.py 2013-08-26 03:22:45 +0000
707+++ mgmtsystem_nonconformity/__openerp__.py 2013-09-10 15:25:36 +0000
708@@ -1,6 +1,6 @@
709 # -*- encoding: utf-8 -*-
710 ##############################################################################
711-#
712+#
713 # OpenERP, Open Source Management Solution
714 # Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
715 #
716@@ -19,23 +19,23 @@
717 #
718 ##############################################################################
719 {
720- "name" : "Management System - Nonconformity",
721- "version" : "1.1",
722- "author" : "Savoir-faire Linux",
723- "website" : "http://www.savoirfairelinux.com",
724- "license" : "AGPL-3",
725- "category" : "Management System",
726+ "name": "Management System - Nonconformity",
727+ "version": "1.2",
728+ "author": "Savoir-faire Linux",
729+ "website": "http://www.savoirfairelinux.com",
730+ "license": "AGPL-3",
731+ "category": "Management System",
732 "description": """\
733-This module enables you to manage the nonconformities of your management
734-system : quality (ISO9001), environment (ISO14001) or security (ISO27001).
735+This module enables you to manage the nonconformities of your management
736+system: quality (ISO9001), environment (ISO14001) or security (ISO27001).
737
738 WARNING: when upgrading from v0.1, data conversion is required, since there are subtancial changes to the data structure.
739 """,
740- "depends" : [
741+ "depends": [
742 'mgmtsystem_action',
743 'document_page_procedure',
744 ],
745- "data" : [
746+ "data": [
747 'security/ir.model.access.csv',
748 'security/mgmtsystem_nonconformity_security.xml',
749 'mgmtsystem_nonconformity.xml',
750@@ -44,10 +44,9 @@
751 'board_mgmtsystem_nonconformity.xml',
752 'mgmtsystem_nonconformity_data.xml',
753 ],
754- "demo" : [
755+ "demo": [
756 'demo_nonconformity.xml',
757 ],
758- "installable" : True,
759+ "installable": True,
760 }
761 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
762-
763
764=== modified file 'mgmtsystem_nonconformity/demo_nonconformity.xml'
765--- mgmtsystem_nonconformity/demo_nonconformity.xml 2012-10-30 20:43:51 +0000
766+++ mgmtsystem_nonconformity/demo_nonconformity.xml 2013-09-10 15:25:36 +0000
767@@ -18,6 +18,7 @@
768 <record id="demo_nonconformity" model="mgmtsystem.nonconformity">
769 <field name="partner_id" ref="base.res_partner_3"/>
770 <field name="date">2010-12-03</field>
771+ <field name="name">Demo Nonconformity</field>
772 <field name="responsible_user_id" ref="base.user_demo"/>
773 <field name="manager_user_id" ref="base.user_root"/>
774 <field name="author_user_id" ref="base.user_demo"/>
775
776=== modified file 'mgmtsystem_nonconformity/mgmtsystem_nonconformity.py'
777--- mgmtsystem_nonconformity/mgmtsystem_nonconformity.py 2013-09-05 20:36:23 +0000
778+++ mgmtsystem_nonconformity/mgmtsystem_nonconformity.py 2013-09-10 15:25:36 +0000
779@@ -1,6 +1,6 @@
780 # -*- encoding: utf-8 -*-
781 ##############################################################################
782-#
783+#
784 # OpenERP, Open Source Management Solution
785 # Copyright (C) 2010 Savoir-faire Linux (<http://www.savoirfairelinux.com>).
786 #
787@@ -15,29 +15,31 @@
788 # GNU Affero General Public License for more details.
789 #
790 # You should have received a copy of the GNU Affero General Public License
791-# along with this program. If not, see <http://www.gnu.org/licenses/>.
792+# along with this program. If not, see <http://www.gnu.org/licenses/>.
793 #
794 ##############################################################################
795
796 from tools.translate import _
797 import netsvc as netsvc
798 from openerp.osv import fields, orm
799+from openerp.addons.base_status.base_state import base_state
800
801 import time
802 from tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT
803 from tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
804
805+
806 class mgmtsystem_nonconformity_cause(orm.Model):
807 """
808 Cause of the nonconformity of the management system
809 """
810 _name = "mgmtsystem.nonconformity.cause"
811 _description = "Cause of the nonconformity of the management system"
812- _order = 'parent_id, sequence'
813+ _order = 'parent_id, sequence'
814
815 def name_get(self, cr, uid, ids, context=None):
816 ids = ids or []
817- reads = self.read(cr, uid, ids, ['name','parent_id'], context=context)
818+ reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context)
819 res = []
820 for record in reads:
821 name = record['name']
822@@ -45,7 +47,7 @@
823 name = record['parent_id'][1]+' / '+name
824 res.append((record['id'], name))
825 return res
826-
827+
828 def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
829 res = self.name_get(cr, uid, ids, context=context)
830 return dict(res)
831@@ -73,11 +75,11 @@
832 """
833 _name = "mgmtsystem.nonconformity.origin"
834 _description = "Origin of nonconformity of the management system"
835- _order = 'parent_id, sequence'
836+ _order = 'parent_id, sequence'
837
838 def name_get(self, cr, uid, ids, context=None):
839 ids = ids or []
840- reads = self.read(cr, uid, ids, ['name','parent_id'], context=context)
841+ reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context)
842 res = []
843 for record in reads:
844 name = record['name']
845@@ -85,7 +87,7 @@
846 name = record['parent_id'][1]+' / '+name
847 res.append((record['id'], name))
848 return res
849-
850+
851 def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
852 res = self.name_get(cr, uid, ids, context=context)
853 return dict(res)
854@@ -127,16 +129,17 @@
855 ('done', _('Closed')),
856 ('cancel', _('Cancelled')),
857 ]
858-_STATES_DICT = dict(_STATES)
859-
860-class mgmtsystem_nonconformity(orm.Model):
861+_STATES_DICT = dict(_STATES)
862+
863+
864+class mgmtsystem_nonconformity(base_state, orm.Model):
865 """
866- Management System - Nonconformity
867+ Management System - Nonconformity
868 """
869 _name = "mgmtsystem.nonconformity"
870 _description = "Nonconformity of the management system"
871 _rec_name = "description"
872- _inherit = ['mail.thread']
873+ _inherit = ['crm.claim']
874 _order = "date desc"
875
876 def _state_name(self, cr, uid, ids, name, args, context=None):
877@@ -152,35 +155,31 @@
878 'date': fields.date('Date', required=True),
879 'partner_id': fields.many2one('res.partner', 'Partner', required=True),
880 'reference': fields.char('Related to', size=50),
881- 'responsible_user_id': fields.many2one('res.users','Responsible', required=True),
882- 'manager_user_id': fields.many2one('res.users','Manager', required=True),
883- 'author_user_id': fields.many2one('res.users','Filled in by', required=True),
884- 'origin_ids': fields.many2many('mgmtsystem.nonconformity.origin','mgmtsystem_nonconformity_origin_rel', 'nonconformity_id', 'origin_id', 'Origin', required=True),
885- 'procedure_ids': fields.many2many('document.page','mgmtsystem_nonconformity_procedure_rel', 'nonconformity_id', 'procedure_id', 'Procedure'),
886+ 'responsible_user_id': fields.many2one('res.users', 'Responsible', required=True),
887+ 'manager_user_id': fields.many2one('res.users', 'Manager', required=True),
888+ 'author_user_id': fields.many2one('res.users', 'Filled in by', required=True),
889+ 'origin_ids': fields.many2many('mgmtsystem.nonconformity.origin', 'mgmtsystem_nonconformity_origin_rel', 'nonconformity_id', 'origin_id', 'Origin', required=True),
890+ 'procedure_ids': fields.many2many('document.page', 'mgmtsystem_nonconformity_procedure_rel', 'nonconformity_id', 'procedure_id', 'Procedure'),
891 'description': fields.text('Description', required=True),
892 'state': fields.selection(_STATES, 'State', readonly=True),
893 'state_name': fields.function(_state_name, string='State Description', type='char', size=40),
894 'system_id': fields.many2one('mgmtsystem.system', 'System'),
895- 'message_ids': fields.one2many('mail.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
896 #2. Root Cause Analysis
897- 'cause_ids': fields.many2many('mgmtsystem.nonconformity.cause','mgmtsystem_nonconformity_cause_rel', 'nonconformity_id', 'cause_id', 'Cause'),
898+ 'cause_ids': fields.many2many('mgmtsystem.nonconformity.cause', 'mgmtsystem_nonconformity_cause_rel', 'nonconformity_id', 'cause_id', 'Cause'),
899 'severity_id': fields.many2one('mgmtsystem.nonconformity.severity', 'Severity'),
900 'analysis': fields.text('Analysis'),
901- 'immediate_action_id': fields.many2one('mgmtsystem.action', 'Immediate action',
902- domain="[('nonconformity_id','=',id)]"),
903+ 'immediate_action_id': fields.many2one('mgmtsystem.action', 'Immediate action', domain="[('nonconformity_id','=',id)]"),
904 'analysis_date': fields.datetime('Analysis Date', readonly=True),
905- 'analysis_user_id': fields.many2one('res.users','Analysis by', readonly=True),
906+ 'analysis_user_id': fields.many2one('res.users', 'Analysis by', readonly=True),
907 #3. Action Plan
908 'action_ids': fields.many2many('mgmtsystem.action', 'mgmtsystem_nonconformity_action_rel', 'nonconformity_id', 'action_id', 'Actions'),
909 'actions_date': fields.datetime('Action Plan Date', readonly=True),
910- 'actions_user_id': fields.many2one('res.users','Action Plan by', readonly=True),
911- 'action_comments': fields.text('Action Plan Comments',
912- help="Comments on the action plan."),
913+ 'actions_user_id': fields.many2one('res.users', 'Action Plan by', readonly=True),
914+ 'action_comments': fields.text('Action Plan Comments', help="Comments on the action plan."),
915 #4. Effectiveness Evaluation
916 'evaluation_date': fields.datetime('Evaluation Date', readonly=True),
917- 'evaluation_user_id': fields.many2one('res.users','Evaluation by', readonly=True),
918- 'evaluation_comments': fields.text('Evaluation Comments',
919- help="Conclusions from the last effectiveness evaluation."),
920+ 'evaluation_user_id': fields.many2one('res.users', 'Evaluation by', readonly=True),
921+ 'evaluation_comments': fields.text('Evaluation Comments', help="Conclusions from the last effectiveness evaluation."),
922 # Multi-company
923 'company_id': fields.many2one('res.company', 'Company'),
924 }
925@@ -199,10 +198,36 @@
926 })
927 return super(mgmtsystem_nonconformity, self).create(cr, uid, vals, context)
928
929+ def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None):
930+ """Add the reponsible, manager and OpenChatter follow list."""
931+ o = self.browse(cr, uid, ids, context=context)[0]
932+ user_ids = [o.responsible_user_id.id, o.manager_user_id.id, o.author_user_id.id]
933+ self.message_subscribe_users(cr, uid, ids, user_ids=user_ids, subtype_ids=None, context=context)
934+ return super(mgmtsystem_nonconformity, self).message_auto_subscribe(cr, uid, ids, updated_fields=updated_fields, context=context)
935+
936+ def case_send_note(self, cr, uid, ids, text, data=None, context=None):
937+ for id in ids:
938+ pre = self.case_get_note_msg_prefix(cr, uid, id, context=context)
939+ msg = '%s <b>%s</b>' % (pre, text)
940+ if data:
941+ o = self.browse(cr, uid, ids, context=context)[0]
942+ post = _('\n<br />\n<ul><li> <b>Stage:</b> %s \xe2\x86\x92 %s</li></ul>') % (o.state, data['state'])
943+ msg += post
944+ self.message_post(cr, uid, [id], body=msg, context=context)
945+ return True
946+
947+ def case_get_note_msg_prefix(self, cr, uid, id, context=None):
948+ return _('Nonconformity')
949+
950+
951 def wkf_analysis(self, cr, uid, ids, context=None):
952 """Change state from draft to analysis"""
953- self.message_post(cr, uid, self.browse(cr, uid, ids), _('Analysis'))
954- return self.write(cr, uid, ids, {'state': 'analysis', 'analysis_date': None, 'analysis_user_id': None}, context=context)
955+ data = {
956+ 'state': 'analysis',
957+ 'analysis_date': None,
958+ 'analysis_user_id': None}
959+ self.case_send_note(cr, uid, ids, _('Analysis'), data=data, context=context)
960+ return self.write(cr, uid, ids, data, context=context)
961
962 def action_sign_analysis(self, cr, uid, ids, context=None):
963 """Sign-off the analysis"""
964@@ -213,18 +238,24 @@
965 raise orm.except_orm(_('Error !'), _('Analysis is already approved.'))
966 if not o.analysis:
967 raise orm.except_orm(_('Error !'), _('Please provide an analysis before approving.'))
968- vals = {'analysis_date': time.strftime(DATETIME_FORMAT), 'analysis_user_id': uid }
969+ vals = {'analysis_date': time.strftime(DATETIME_FORMAT), 'analysis_user_id': uid}
970 self.write(cr, uid, ids, vals, context=context)
971- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Analysis Approved'))
972+ note = _('Analysis Approved')
973+ self.case_send_note(cr, uid, ids, note, context=context)
974 return True
975
976 def wkf_review(self, cr, uid, ids, context=None):
977 """Change state from analysis to pending approval"""
978 o = self.browse(cr, uid, ids, context=context)[0]
979 if not o.analysis_date:
980- raise orm.except_orm(_('Error !'), _('Analysis must be performed before submiting to approval.'))
981- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Pending Approval'))
982- return self.write(cr, uid, ids, {'state': 'pending', 'actions_date': None, 'actions_user_id': None}, context=context)
983+ err = _('Analysis must be performed before submiting to approval.')
984+ raise orm.except_orm(_('Error !'), err)
985+ vals = {
986+ 'state': 'pending',
987+ 'actions_date': None,
988+ 'actions_user_id': None}
989+ self.case_send_note(cr, uid, ids, _('Pending Approval'), data=vals, context=context)
990+ return self.write(cr, uid, ids, vals, context=context)
991
992 def action_sign_actions(self, cr, uid, ids, context=None):
993 """Sign-off the action plan"""
994@@ -235,9 +266,10 @@
995 raise orm.except_orm(_('Error !'), _('Action plan is already approved.'))
996 if not self.browse(cr, uid, ids, context=context)[0].analysis_date:
997 raise orm.except_orm(_('Error !'), _('Analysis approved before the review confirmation.'))
998- vals = {'actions_date': time.strftime(DATETIME_FORMAT), 'actions_user_id': uid }
999+ vals = {'actions_date': time.strftime(DATETIME_FORMAT), 'actions_user_id': uid}
1000 self.write(cr, uid, ids, vals, context=context)
1001- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Action Plan Approved'))
1002+ note = _('Action Plan Approved')
1003+ self.case_send_note(cr, uid, ids, note, context=context)
1004 return True
1005
1006 def wkf_open(self, cr, uid, ids, context=None):
1007@@ -245,7 +277,7 @@
1008 o = self.browse(cr, uid, ids, context=context)[0]
1009 if not o.actions_date:
1010 raise orm.except_orm(_('Error !'), _('Action plan must be approved before opening.'))
1011- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('In Progress'))
1012+ self.case_open_send_note(cr, uid, ids, context=context)
1013 #Open related Actions
1014 if o.immediate_action_id and o.immediate_action_id.state == 'draft':
1015 o.immediate_action_id.case_open()
1016@@ -259,14 +291,15 @@
1017 o = self.browse(cr, uid, ids, context=context)[0]
1018 if o.state != 'open':
1019 raise orm.except_orm(_('Error !'), _('This action can only be done in the In Progress state.'))
1020- vals = {'evaluation_date': time.strftime(DATETIME_FORMAT), 'evaluation_user_id': uid }
1021+ vals = {'evaluation_date': time.strftime(DATETIME_FORMAT), 'evaluation_user_id': uid}
1022 self.write(cr, uid, ids, vals, context=context)
1023- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Effectiveness Evaluation Approved'))
1024+ note = _('Effectiveness Evaluation Approved')
1025+ self.case_send_note(cr, uid, ids, note, context=context)
1026 return True
1027
1028 def wkf_cancel(self, cr, uid, ids, context=None):
1029 """Change state to cancel"""
1030- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Cancel'))
1031+ self.case_cancel_send_note(cr, uid, ids, context=context)
1032 return self.write(cr, uid, ids, {'state': 'cancel'}, context=context)
1033
1034 def wkf_close(self, cr, uid, ids, context=None):
1035@@ -279,21 +312,21 @@
1036 raise orm.except_orm(_('Error !'), _('Not all actions have been closed.'))
1037 if not o.evaluation_date:
1038 raise orm.except_orm(_('Error !'), _('Effectiveness evaluation must be performed before closing.'))
1039- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Close'))
1040+ self.case_close_send_note(cr, uid, ids, context=context)
1041 return self.write(cr, uid, ids, {'state': 'done'}, context=context)
1042
1043 def case_reset(self, cr, uid, ids, context=None, *args):
1044 """Reset to Draft and restart the workflows"""
1045 wf_service = netsvc.LocalService("workflow")
1046 for id in ids:
1047- res = wf_service.trg_create(uid, self._name, id, cr)
1048- self.message_post(cr, uid, self.browse(cr, uid, ids, context=context), _('Draft'))
1049+ wf_service.trg_create(uid, self._name, id, cr)
1050+ self.case_reset_send_note(cr, uid, ids, context=context)
1051 vals = {
1052 'state': 'draft',
1053- 'analysis_date': None, 'analysis_user_id': None,
1054+ 'analysis_date': None, 'analysis_user_id': None,
1055 'actions_date': None, 'actions_user_id': None,
1056 'evaluation_date': None, 'evaluation_user_id': None,
1057- }
1058+ }
1059 return self.write(cr, uid, ids, vals, context=context)
1060
1061
1062@@ -301,8 +334,7 @@
1063 _inherit = "mgmtsystem.action"
1064 _columns = {
1065 'nonconformity_immediate_id': fields.one2many('mgmtsystem.nonconformity', 'immediate_action_id', readonly=True),
1066- 'nonconformity_ids': fields.many2many(
1067- 'mgmtsystem.nonconformity', 'mgmtsystem_nonconformity_action_rel', 'action_id', 'nonconformity_id', 'Nonconformities', readonly=True),
1068+ 'nonconformity_ids': fields.many2many('mgmtsystem.nonconformity', 'mgmtsystem_nonconformity_action_rel', 'action_id', 'nonconformity_id', 'Nonconformities', readonly=True),
1069 }
1070
1071 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1072
1073=== modified file 'mgmtsystem_nonconformity/mgmtsystem_nonconformity.xml'
1074--- mgmtsystem_nonconformity/mgmtsystem_nonconformity.xml 2013-08-25 15:20:05 +0000
1075+++ mgmtsystem_nonconformity/mgmtsystem_nonconformity.xml 2013-09-10 15:25:36 +0000
1076@@ -72,8 +72,10 @@
1077 <form string="Non-Conformity" version="7.0">
1078 <header>
1079 <button name="button_cancel" string="Cancel" states="draft,analysis,pending,open"/>
1080- <button name="button_analysis" string="Send for Analysis" states="draft,pending" class="oe_highlight"/>
1081- <button name="button_review" string="Send for Review" states="analysis,open" class="oe_highlight"/>
1082+ <button name="button_analysis_n" string="Send for Analysis" states="draft" class="oe_highlight"/>
1083+ <button name="button_analysis_p" string="Send for Analysis" states="pending"/>
1084+ <button name="button_review_n" string="Send for Review" states="analysis" class="oe_highlight"/>
1085+ <button name="button_review_p" string="Send for Review" states="open"/>
1086 <button name="button_open" string="Start/Open" states="pending" class="oe_highlight"/>
1087 <button name="button_close" string="Close" class="oe_highlight"
1088 states="open" groups="mgmtsystem.group_mgmtsystem_manager,mgmtsystem.group_mgmtsystem_auditor"/>
1089@@ -97,9 +99,9 @@
1090 <field name="company_id" group="base.group_multi_company"/>
1091 </group>
1092 </group>
1093-
1094+
1095 <notebook>
1096-
1097+
1098 <page string="Description">
1099 <field name="description" placeholder="Add a description ..." attrs="{'readonly':[('state','not in',['draft','analysis'])]}"/>
1100 </page>
1101@@ -157,36 +159,14 @@
1102 </group>
1103 </group>
1104 </page>
1105-
1106- <!-- Communication History -->
1107- <!-- TODO: REMOVE and migrate to Chatter -->
1108- <page string="Communication &amp; History">
1109- <field name="message_ids" colspan="4" nolabel="1" mode="tree" readonly="1">
1110- <tree string="History">
1111- <field name="subject" string="History Information"/>
1112- <field name="email_from" invisible="1"/>
1113- <button
1114- string="Reply" attrs="{'invisible': [('email_from', '=', False)]}"
1115- name="%(mail.action_email_compose_message_wizard)d"
1116- context="{'mail.compose.message.mode':'reply', 'message_id':active_id}"
1117- icon="terp-mail-replied" type="action" />
1118- </tree>
1119- </field>
1120- <separator colspan="4"/>
1121- <button string="Send New Email"
1122- name="%(mail.action_email_compose_message_wizard)d"
1123- icon="terp-mail-message-new" type="action"/>
1124- </page>
1125
1126 </notebook>
1127 </sheet>
1128
1129- <!-- TODO: migrate to Chatter
1130 <div class="oe_chatter">
1131 <field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
1132 <field name="message_ids" widget="mail_thread"/>
1133 </div>
1134- -->
1135
1136 </form>
1137 </field>
1138@@ -267,7 +247,7 @@
1139 groups="mgmtsystem.group_mgmtsystem_manager"/>
1140
1141 <!-- Cause -->
1142-
1143+
1144 <record id="view_mgmtsystem_nonconformity_cause_form" model="ir.ui.view">
1145 <field name="name">mgmtsystem.nonconformity.cause.form</field>
1146 <field name="type">form</field>
1147@@ -323,7 +303,7 @@
1148 parent="menu_mgmtsystem_configuration_nonconformities"
1149 sequence="30"
1150 groups="mgmtsystem.group_mgmtsystem_manager"/>
1151-
1152+
1153 <!-- Severity -->
1154 <record id="view_mgmtsystem_nonconformity_severity_form" model="ir.ui.view">
1155 <field name="name">mgmtsystem.nonconformity.severity.form</field>
1156
1157=== modified file 'mgmtsystem_nonconformity/mgmtsystem_nonconformity_workflow.xml'
1158--- mgmtsystem_nonconformity/mgmtsystem_nonconformity_workflow.xml 2012-10-25 13:38:14 +0000
1159+++ mgmtsystem_nonconformity/mgmtsystem_nonconformity_workflow.xml 2013-09-10 15:25:36 +0000
1160@@ -69,14 +69,14 @@
1161 <record model="workflow.transition" id="mgmtsystem_nonconformity_draft_analysis">
1162 <field name="act_from" ref="mgmtsystem_nonconformity_draft"/>
1163 <field name="act_to" ref="mgmtsystem_nonconformity_analysis"/>
1164- <field name="signal">button_analysis</field>
1165+ <field name="signal">button_analysis_n</field>
1166 <field name="condition">True</field>
1167 </record>
1168
1169 <record model="workflow.transition" id="mgmtsystem_nonconformity_analysis_pending">
1170 <field name="act_from" ref="mgmtsystem_nonconformity_analysis"/>
1171 <field name="act_to" ref="mgmtsystem_nonconformity_pending"/>
1172- <field name="signal">button_review</field>
1173+ <field name="signal">button_review_n</field>
1174 <field name="condition">True</field>
1175 </record>
1176
1177@@ -90,14 +90,14 @@
1178 <record model="workflow.transition" id="mgmtsystem_nonconformity_open_pending">
1179 <field name="act_from" ref="mgmtsystem_nonconformity_open"/>
1180 <field name="act_to" ref="mgmtsystem_nonconformity_pending"/>
1181- <field name="signal">button_review</field>
1182+ <field name="signal">button_review_p</field>
1183 <field name="condition">True</field>
1184 </record>
1185
1186 <record model="workflow.transition" id="mgmtsystem_nonconformity_pending_analysis">
1187 <field name="act_from" ref="mgmtsystem_nonconformity_pending"/>
1188 <field name="act_to" ref="mgmtsystem_nonconformity_analysis"/>
1189- <field name="signal">button_analysis</field>
1190+ <field name="signal">button_analysis_p</field>
1191 <field name="condition">True</field>
1192 </record>
1193
1194
1195=== modified file 'mgmtsystem_nonconformity/migrations/7.0.1.0/post-migration.py'
1196--- mgmtsystem_nonconformity/migrations/7.0.1.0/post-migration.py 2013-04-01 19:13:26 +0000
1197+++ mgmtsystem_nonconformity/migrations/7.0.1.0/post-migration.py 2013-09-10 15:25:36 +0000
1198@@ -25,6 +25,7 @@
1199
1200 logger = logging.getLogger('upgrade')
1201
1202+
1203 def migrate(cr, version):
1204 logger.info("Migrating mgmtsystem_nonconformity from version %s", version)
1205 cr.execute("select count(*) from mgmtsystem_nonconformity_action_rel")
1206@@ -33,17 +34,17 @@
1207 logger.info("Moving nonconformity/action relations to mgmtsystem_nonconformity_action_rel")
1208 for action_field in ('preventive_action_id', 'immediate_action_id', 'corrective_action_id'):
1209 cr.execute("insert into mgmtsystem_nonconformity_action_rel"
1210- "(nonconformity_id, action_id) "
1211- "(SELECT id, %s FROM "
1212- " mgmtsystem_nonconformity "
1213- "WHERE %s IS NOT NULL )" % (action_field, action_field))
1214+ "(nonconformity_id, action_id) "
1215+ "(SELECT id, %s FROM "
1216+ " mgmtsystem_nonconformity "
1217+ "WHERE %s IS NOT NULL )" % (action_field, action_field))
1218 else:
1219 logger.warning("Attempt to migrate nonconformity action IDs failed: migration was already done.")
1220
1221 logger.info("Concatening action comments into evaluation_comments")
1222 cr.execute("update mgmtsystem_nonconformity set evaluation_comments = "
1223- "effectiveness_preventive || ' ' || effectiveness_immediate || ' ' || effectiveness_corrective "
1224- "where evaluation_comments is null")
1225+ "effectiveness_preventive || ' ' || effectiveness_immediate || ' ' || effectiveness_corrective "
1226+ "where evaluation_comments is null")
1227
1228 logger.info("Updating state flags")
1229 cr.execute("update mgmtsystem_nonconformity set state = 'open' where state = 'o'")
1230
1231=== modified file 'mgmtsystem_nonconformity_deptm/mgmtsystem_nonconformity.py'
1232--- mgmtsystem_nonconformity_deptm/mgmtsystem_nonconformity.py 2013-04-12 15:10:42 +0000
1233+++ mgmtsystem_nonconformity_deptm/mgmtsystem_nonconformity.py 2013-09-10 15:25:36 +0000
1234@@ -37,5 +37,11 @@
1235 result['superior_user_id'] = deptm.parent_id.manager_id.user_id.id
1236 return {'value': result}
1237
1238+ def message_auto_subscribe(self, cr, uid, ids, updated_fields, context=None):
1239+ """Add the Top Manager to OpenChatter follow list."""
1240+ o = self.browse(cr, uid, ids, context=context)[0]
1241+ user_ids = [o.superior_user_id.id]
1242+ self.message_subscribe_users(cr, uid, ids, user_ids=user_ids, subtype_ids=None, context=context)
1243+ return super(mgmtsystem_nonconformity, self).message_auto_subscribe(cr, uid, ids, updated_fields=updated_fields, context=context)
1244
1245 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: