[MERGE]upstream
[odoo/odoo.git] / addons / base_status / base_state.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-today OpenERP SA (<http://www.openerp.com>)
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from openerp.osv import fields, osv
23 from openerp.tools.translate import _
24
25 class base_state(object):
26     """ Base utility mixin class for objects willing to manage their state.
27         Object subclassing this class should define the following colums:
28         - ``date_open`` (datetime field)
29         - ``date_closed`` (datetime field)
30         - ``user_id`` (many2one to res.users)
31         - ``partner_id`` (many2one to res.partner)
32         - ``email_from`` (char field)
33         - ``state`` (selection field)
34     """
35
36     def _get_default_partner(self, cr, uid, context=None):
37         """ Gives id of partner for current user
38             :param context: if portal not in context returns False
39         """
40         if context is None:
41             context = {}
42         if not context or not context.get('portal'):
43             return False
44         user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
45         if hasattr(user, 'partner_address_id') and user.partner_address_id:
46             return user.partner_address_id
47         return user.company_id.partner_id.id
48
49     def _get_default_email(self, cr, uid, context=None):
50         """ Gives default email address for current user
51             :param context: if portal not in context returns False
52         """
53         if context is None:
54             context = {}
55         if not context or not context.get('portal'):
56             return False
57         user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
58         return user.email
59
60     def _get_default_user(self, cr, uid, context=None):
61         """ Gives current user id
62             :param context: if portal not in context returns False
63         """
64         if context is None:
65             context = {}
66         if not context or not context.get('portal'):
67             return False
68         return uid
69
70     def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
71         """ This function returns value of partner email based on Partner Address
72             :param add: Id of Partner's address
73             :param email: Partner's email ID
74         """
75         data = {'value': {'email_from': False, 'phone':False}}
76         if add:
77             address = self.pool.get('res.partner').browse(cr, uid, add)
78             data['value'] = {'email_from': address and address.email or False ,
79                              'phone':  address and address.phone or False}
80         if 'phone' not in self._columns:
81             del data['value']['phone']
82         return data
83
84     def onchange_partner_id(self, cr, uid, ids, part, email=False):
85         """ This function returns value of partner address based on partner
86             :param part: Partner's id
87             :param email: Partner's email ID
88         """
89         data={}
90         if  part:
91             addr = self.pool.get('res.partner').address_get(cr, uid, [part], ['contact'])
92             data.update(self.onchange_partner_address_id(cr, uid, ids, addr['contact'])['value'])
93         return {'value': data}
94
95     def case_escalate(self, cr, uid, ids, context=None):
96         """ Escalates case to parent level """
97         cases = self.browse(cr, uid, ids, context=context)
98         cases[0].state # fill browse record cache, for _action having old and new values
99         data = {'active': True}
100         for case in cases:
101             parent_id = case.section_id.parent_id
102             if parent_id:
103                 data['section_id'] = parent_id.id
104                 if parent_id.change_responsible and parent_id.user_id:
105                     data['user_id'] = parent_id.user_id.id
106             else:
107                 raise osv.except_osv(_('Error!'), _('You can not escalate, you are already at the top level regarding your sales-team category.'))
108             self.write(cr, uid, [case.id], data, context=context)
109             case.case_escalate_send_note(parent_id, context=context)
110         return True
111
112     def case_open(self, cr, uid, ids, context=None):
113         """ Opens case """
114         cases = self.browse(cr, uid, ids, context=context)
115         for case in cases:
116             values = {'active': True}
117             if case.state == 'draft':
118                 values['date_open'] = fields.datetime.now()
119             if not case.user_id:
120                 values['user_id'] = uid
121             self.case_set(cr, uid, [case.id], 'open', values, context=context)
122         return True
123
124     def case_close(self, cr, uid, ids, context=None):
125         """ Closes case """
126         return self.case_set(cr, uid, ids, 'done', {'date_closed': fields.datetime.now()}, context=context)
127
128     def case_cancel(self, cr, uid, ids, context=None):
129         """ Cancels case """
130         return self.case_set(cr, uid, ids, 'cancel', {'active': True}, context=context)
131
132     def case_pending(self, cr, uid, ids, context=None):
133         """ Sets case as pending """
134         return self.case_set(cr, uid, ids, 'pending', {'active': True}, context=context)
135
136     def case_reset(self, cr, uid, ids, context=None):
137         """ Resets case as draft """
138         return self.case_set(cr, uid, ids, 'draft', {'active': True}, context=context)
139
140     def case_set(self, cr, uid, ids, state_name, update_values=None, context=None):
141         """ Generic method for setting case. This methods wraps the update
142             of the record, as well as call to _action and browse_record
143             case setting to fill the cache.
144
145             :params: state_name: the new value of the state, such as
146                      'draft' or 'close'.
147             :params: update_values: values that will be added with the state
148                      update when writing values to the record.
149         """
150         cases = self.browse(cr, uid, ids, context=context)
151         cases[0].state # fill browse record cache, for _action having old and new values
152         if update_values is None:
153             update_values = {}
154         update_values['state'] = state_name
155         return self.write(cr, uid, ids, update_values, context=context)
156     
157     # ******************************
158     # Notifications
159     # ******************************
160     
161     def case_get_note_msg_prefix(self, cr, uid, id, context=None):
162         return ''
163
164     def case_open_send_note(self, cr, uid, ids, context=None):
165         for id in ids:
166             msg = _('%s has been <b>opened</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
167             self.message_post(cr, uid, [id], body=msg, context=context)
168         return True
169
170     def case_escalate_send_note(self, cr, uid, ids, new_section=None, context=None):
171         for id in ids:
172             if new_section:
173                 msg = '%s has been <b>escalated</b> to <b>%s</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context), new_section.name)
174             else:
175                 msg = '%s has been <b>escalated</b>.' % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
176             self.message_post(cr, uid, [id], body=msg, context=context)
177         return True
178
179     def case_close_send_note(self, cr, uid, ids, context=None):
180         for id in ids:
181             msg = _('%s has been <b>closed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
182             self.message_post(cr, uid, [id], body=msg, context=context)
183         return True
184
185     def case_cancel_send_note(self, cr, uid, ids, context=None):
186         for id in ids:
187             msg = _('%s has been <b>canceled</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
188             self.message_post(cr, uid, [id], body=msg, context=context)
189         return True
190
191     def case_pending_send_note(self, cr, uid, ids, context=None):
192         for id in ids:
193             msg = _('%s is now <b>pending</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
194             self.message_post(cr, uid, [id], body=msg, context=context)
195         return True
196
197     def case_reset_send_note(self, cr, uid, ids, context=None):
198         for id in ids:
199             msg = _('%s has been <b>renewed</b>.') % (self.case_get_note_msg_prefix(cr, uid, id, context=context))
200             self.message_post(cr, uid, [id], body=msg, context=context)
201         return True