[MERGE] forward port of branch saas-4 up to f68c835
[odoo/odoo.git] / addons / crm_claim / crm_claim.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 import openerp
23 from openerp.addons.crm import crm
24 from openerp.osv import fields, osv
25 from openerp import tools
26 from openerp.tools.translate import _
27 from openerp.tools import html2plaintext
28
29
30 class crm_claim_stage(osv.osv):
31     """ Model for claim stages. This models the main stages of a claim
32         management flow. Main CRM objects (leads, opportunities, project
33         issues, ...) will now use only stages, instead of state and stages.
34         Stages are for example used to display the kanban view of records.
35     """
36     _name = "crm.claim.stage"
37     _description = "Claim stages"
38     _rec_name = 'name'
39     _order = "sequence"
40
41     _columns = {
42         'name': fields.char('Stage Name', size=64, required=True, translate=True),
43         'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
44         'section_ids':fields.many2many('crm.case.section', 'section_claim_stage_rel', 'stage_id', 'section_id', string='Sections',
45                         help="Link between stages and sales teams. When set, this limitate the current stage to the selected sales teams."),
46         'case_default': fields.boolean('Common to All Teams',
47                         help="If you check this field, this stage will be proposed by default on each sales team. It will not assign this stage to existing teams."),
48         'fold': fields.boolean('Hide in Views when Empty',
49                         help="This stage is not visible, for example in status bar or kanban view, when there are no records in that stage to display."),
50     }
51
52     _defaults = {
53         'sequence': lambda *args: 1,
54         'fold': False,
55     }
56
57 class crm_claim(osv.osv):
58     """ Crm claim
59     """
60     _name = "crm.claim"
61     _description = "Claim"
62     _order = "priority,date desc"
63     _inherit = ['mail.thread']
64
65     def _get_default_section_id(self, cr, uid, context=None):
66         """ Gives default section by checking if present in the context """
67         return self.pool.get('crm.lead')._resolve_section_id_from_context(cr, uid, context=context) or False
68
69     def _get_default_stage_id(self, cr, uid, context=None):
70         """ Gives default stage_id """
71         section_id = self._get_default_section_id(cr, uid, context=context)
72         return self.stage_find(cr, uid, [], section_id, [('sequence', '=', '1')], context=context)
73
74     _columns = {
75         'id': fields.integer('ID', readonly=True),
76         'name': fields.char('Claim Subject', size=128, required=True),
77         'active': fields.boolean('Active'),
78         'action_next': fields.char('Next Action', size=200),
79         'date_action_next': fields.datetime('Next Action Date'),
80         'description': fields.text('Description'),
81         'resolution': fields.text('Resolution'),
82         'create_date': fields.datetime('Creation Date' , readonly=True),
83         'write_date': fields.datetime('Update Date' , readonly=True),
84         'date_deadline': fields.date('Deadline'),
85         'date_closed': fields.datetime('Closed', readonly=True),
86         'date': fields.datetime('Claim Date', select=True),
87         'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models),
88         'categ_id': fields.many2one('crm.case.categ', 'Category', \
89                             domain="[('section_id','=',section_id),\
90                             ('object_id.model', '=', 'crm.claim')]"),
91         'priority': fields.selection([('0','Low'), ('1','Normal'), ('2','High')], 'Priority'),
92         'type_action': fields.selection([('correction','Corrective Action'),('prevention','Preventive Action')], 'Action Type'),
93         'user_id': fields.many2one('res.users', 'Responsible'),
94         'user_fault': fields.char('Trouble Responsible', size=64),
95         'section_id': fields.many2one('crm.case.section', 'Sales Team', \
96                         select=True, help="Responsible sales team."\
97                                 " Define Responsible user and Email account for"\
98                                 " mail gateway."),
99         'company_id': fields.many2one('res.company', 'Company'),
100         'partner_id': fields.many2one('res.partner', 'Partner'),
101         'email_cc': fields.text('Watchers Emails', size=252, help="These email addresses will be added to the CC field of all inbound and outbound emails for this record before being sent. Separate multiple email addresses with a comma"),
102         'email_from': fields.char('Email', size=128, help="Destination email for email gateway."),
103         'partner_phone': fields.char('Phone', size=32),
104         'stage_id': fields.many2one ('crm.claim.stage', 'Stage', track_visibility='onchange',
105                 domain="['|', ('section_ids', '=', section_id), ('case_default', '=', True)]"),
106         'cause': fields.text('Root Cause'),
107     }
108
109     _defaults = {
110         'user_id': lambda s, cr, uid, c: uid,
111         'section_id': lambda s, cr, uid, c: s._get_default_section_id(cr, uid, c),
112         'date': fields.datetime.now,
113         'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
114         'priority': '1',
115         'active': lambda *a: 1,
116         'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c)
117     }
118
119     def stage_find(self, cr, uid, cases, section_id, domain=[], order='sequence', context=None):
120         """ Override of the base.stage method
121             Parameter of the stage search taken from the lead:
122             - section_id: if set, stages must belong to this section or
123               be a default case
124         """
125         if isinstance(cases, (int, long)):
126             cases = self.browse(cr, uid, cases, context=context)
127         # collect all section_ids
128         section_ids = []
129         if section_id:
130             section_ids.append(section_id)
131         for claim in cases:
132             if claim.section_id:
133                 section_ids.append(claim.section_id.id)
134         # OR all section_ids and OR with case_default
135         search_domain = []
136         if section_ids:
137             search_domain += [('|')] * len(section_ids)
138             for section_id in section_ids:
139                 search_domain.append(('section_ids', '=', section_id))
140         search_domain.append(('case_default', '=', True))
141         # AND with the domain in parameter
142         search_domain += list(domain)
143         # perform search, return the first found
144         stage_ids = self.pool.get('crm.claim.stage').search(cr, uid, search_domain, order=order, context=context)
145         if stage_ids:
146             return stage_ids[0]
147         return False
148
149     def onchange_partner_id(self, cr, uid, ids, partner_id, email=False, context=None):
150         """This function returns value of partner address based on partner
151            :param email: ignored
152         """
153         if not partner_id:
154             return {'value': {'email_from': False, 'partner_phone': False}}
155         address = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
156         return {'value': {'email_from': address.email, 'partner_phone': address.phone}}
157
158     def create(self, cr, uid, vals, context=None):
159         if context is None:
160             context = {}
161         if vals.get('section_id') and not context.get('default_section_id'):
162             context['default_section_id'] = vals.get('section_id')
163
164         # context: no_log, because subtype already handle this
165         return super(crm_claim, self).create(cr, uid, vals, context=context)
166
167     def copy(self, cr, uid, id, default=None, context=None):
168         claim = self.browse(cr, uid, id, context=context)
169         default = dict(default or {},
170             stage_id = self._get_default_stage_id(cr, uid, context=context),
171             name = _('%s (copy)') % claim.name)
172         return super(crm_claim, self).copy(cr, uid, id, default, context=context)
173
174     # -------------------------------------------------------
175     # Mail gateway
176     # -------------------------------------------------------
177
178     def message_new(self, cr, uid, msg, custom_values=None, context=None):
179         """ Overrides mail_thread message_new that is called by the mailgateway
180             through message_process.
181             This override updates the document according to the email.
182         """
183         if custom_values is None:
184             custom_values = {}
185         desc = html2plaintext(msg.get('body')) if msg.get('body') else ''
186         defaults = {
187             'name': msg.get('subject') or _("No Subject"),
188             'description': desc,
189             'email_from': msg.get('from'),
190             'email_cc': msg.get('cc'),
191             'partner_id': msg.get('author_id', False),
192         }
193         if msg.get('priority'):
194             defaults['priority'] = msg.get('priority')
195         defaults.update(custom_values)
196         return super(crm_claim, self).message_new(cr, uid, msg, custom_values=defaults, context=context)
197
198 class res_partner(osv.osv):
199     _inherit = 'res.partner'
200     def _claim_count(self, cr, uid, ids, field_name, arg, context=None):
201         Claim = self.pool['crm.claim']
202         return {
203             partner_id: Claim.search_count(cr,uid, [('partner_id', '=', partner_id)], context=context)  
204             for partner_id in ids
205         }
206
207     _columns = {
208         'claim_count': fields.function(_claim_count, string='# Claims', type='integer'),
209     }
210
211 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: