~noviat/+junk/trial-v6

« back to all changes in this revision

Viewing changes to crm_activities/crm_activities.py

  • Committer: root
  • Date: 2011-04-23 13:42:06 UTC
  • Revision ID: root@r34293.ovh.net-20110423134206-0xk2v0qvbn4thai5
CR/LF correction

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
##############################################################################
2
 
#
3
 
#    OpenERP, Open Source Management Solution
4
 
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
5
 
#
6
 
#    This program is free software: you can redistribute it and/or modify
7
 
#    it under the terms of the GNU Affero General Public License as
8
 
#    published by the Free Software Foundation, either version 3 of the
9
 
#    License, or (at your option) any later version.
10
 
#
11
 
#    This program is distributed in the hope that it will be useful,
12
 
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
#    GNU Affero General Public License for more details.
15
 
#
16
 
#    You should have received a copy of the GNU Affero General Public License
17
 
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
 
#
19
 
##############################################################################
20
 
 
21
 
from osv import fields, osv
22
 
from datetime import datetime
23
 
import crm
24
 
import time
25
 
from tools.translate import _
26
 
from crm.crm import crm_case
27
 
import binascii
28
 
import tools
29
 
import logging
30
 
 
31
 
AVAILABLE_STATES = [
32
 
    ('draft', 'Draft'),
33
 
    ('open', 'Open'),
34
 
    ('cancel', 'Cancelled'),
35
 
    ('done', 'Done'),
36
 
    ('pending', 'Pending'),
37
 
    ('ready', 'Intake OK'),
38
 
    ('planned', 'Planned'),
39
 
]
40
 
 
41
 
 
42
 
class crm_case_stage(osv.osv):
43
 
    """ Stage of case """
44
 
    _inherit = "crm.case.stage"
45
 
 
46
 
    def _get_type_value(self, cr, user, context):
47
 
        return [('lead','Lead'),('opportunity','Opportunity'),('activity','Activity')]
48
 
 
49
 
    _columns = {
50
 
        'type': fields.selection(_get_type_value, 'Type'),
51
 
    }
52
 
 
53
 
crm_case_stage()
54
 
 
55
 
class crm_activities(crm_case, osv.osv):
56
 
    """ CRM Activity Case """
57
 
    _name = "crm.activities"
58
 
    _description = "Case Driven Activities"
59
 
    _order = "date_action, priority, id desc"
60
 
    _inherit = ['mailgate.thread','res.partner.address','crm.lead']
61
 
        
62
 
    def _get_stage_id(self, cr, uid, context={}):
63
 
        if context is None:
64
 
            context = {}
65
 
        stage_pool = self.pool.get('crm.case.stage')
66
 
        stage_type = context and context.get('stage_type','')
67
 
        logging.getLogger('crm_enhancements').warning("Stage Type %s", stage_type)
68
 
        if not stage_type:
69
 
            stage_type='activity'
70
 
        domain = [('type', '=', stage_type)]
71
 
        stages = stage_pool.search(cr, uid, domain, order='sequence')
72
 
        return stages[0]
73
 
 
74
 
    def action_makeMeeting(self, cr, uid, ids, context=None):
75
 
        logging.getLogger('crm_activities').warning("Context %s", context)
76
 
        """
77
 
        This opens Meeting's calendar view to schedule meeting on current Opportunity
78
 
        @param self: The object pointer
79
 
 
80
 
        @param cr: the current row, from the database cursor,
81
 
        @param uid: the current user's ID for security checks,
82
 
        @param ids: List of Opportunity to Meeting IDs
83
 
        @param context: A standard dictionary for contextual values
84
 
 
85
 
        @return : Dictionary value for created Meeting view
86
 
        """
87
 
        value = {}
88
 
        for opp in self.browse(cr, uid, ids, context=context):
89
 
            data_obj = self.pool.get('ir.model.data')
90
 
 
91
 
            # Get meeting views
92
 
            result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
93
 
            res = data_obj.read(cr, uid, result, ['res_id'])
94
 
            id1 = data_obj._get_id(cr, uid, 'crm_activities', 'crm_case_calendar_view_meet')
95
 
            id2 = data_obj._get_id(cr, uid, 'crm_activities', 'crm_case_form_view_meet')
96
 
            id3 = data_obj._get_id(cr, uid, 'crm_activities', 'crm_case_tree_view_meet')
97
 
            if id1:
98
 
                id1 = data_obj.browse(cr, uid, id1, context=context).res_id
99
 
            if id2:
100
 
                id2 = data_obj.browse(cr, uid, id2, context=context).res_id
101
 
            if id3:
102
 
                id3 = data_obj.browse(cr, uid, id3, context=context).res_id
103
 
 
104
 
            context = {
105
 
                'default_opportunity_id': opp.id,
106
 
                'default_partner_id': opp.partner_id and opp.partner_id.id or False,
107
 
                'default_user_id': context['uid'],
108
 
                'default_section_id': opp.section_id and opp.section_id.id or False,
109
 
                'default_email_from': opp.email_from,
110
 
                'default_state': 'open',
111
 
                'default_name': opp.name
112
 
            }
113
 
            logging.getLogger('crm_activities').warning("Context 2: %s", context)
114
 
            value = {
115
 
                'name': _('Meetings'),
116
 
                'context': context,
117
 
                'view_type': 'form',
118
 
                'view_mode': 'calendar,form,tree',
119
 
                'res_model': 'crm.meeting.activities',
120
 
                'view_id': False,
121
 
                'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
122
 
                'type': 'ir.actions.act_window',
123
 
                'search_view_id': res['res_id'],
124
 
                'nodestroy': True
125
 
            }
126
 
        return value
127
 
 
128
 
    def _compute_day(self, cr, uid, ids, fields, args, context=None):
129
 
        """
130
 
        @param cr: the current row, from the database cursor,
131
 
        @param uid: the current user's ID for security checks,
132
 
        @param ids: List of Openday's IDs
133
 
        @return: difference between current date and log date
134
 
        @param context: A standard dictionary for contextual values
135
 
        """
136
 
        cal_obj = self.pool.get('resource.calendar')
137
 
        res_obj = self.pool.get('resource.resource')
138
 
 
139
 
        res = {}
140
 
        for lead in self.browse(cr, uid, ids, context=context):
141
 
            for field in fields:
142
 
                res[lead.id] = {}
143
 
                duration = 0
144
 
                ans = False
145
 
                if field == 'day_open':
146
 
                    if lead.date_open:
147
 
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
148
 
                        date_open = datetime.strptime(lead.date_open, "%Y-%m-%d %H:%M:%S")
149
 
                        ans = date_open - date_create
150
 
                        date_until = lead.date_open
151
 
                elif field == 'day_close':
152
 
                    if lead.date_closed:
153
 
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
154
 
                        date_close = datetime.strptime(lead.date_closed, "%Y-%m-%d %H:%M:%S")
155
 
                        date_until = lead.date_closed
156
 
                        ans = date_close - date_create
157
 
                if ans:
158
 
                    resource_id = False
159
 
                    if lead.user_id:
160
 
                        resource_ids = res_obj.search(cr, uid, [('user_id','=',lead.user_id.id)])
161
 
                        if len(resource_ids):
162
 
                            resource_id = resource_ids[0]
163
 
 
164
 
                    duration = float(ans.days)
165
 
                    if lead.section_id and lead.section_id.resource_calendar_id:
166
 
                        duration =  float(ans.days) * 24
167
 
                        new_dates = cal_obj.interval_get(cr,
168
 
                            uid,
169
 
                            lead.section_id.resource_calendar_id and lead.section_id.resource_calendar_id.id or False,
170
 
                            datetime.strptime(lead.create_date, '%Y-%m-%d %H:%M:%S'),
171
 
                            duration,
172
 
                            resource=resource_id
173
 
                        )
174
 
                        no_days = []
175
 
                        date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S')
176
 
                        for in_time, out_time in new_dates:
177
 
                            if in_time.date not in no_days:
178
 
                                no_days.append(in_time.date)
179
 
                            if out_time > date_until:
180
 
                                break
181
 
                        duration =  len(no_days)
182
 
                res[lead.id][field] = abs(int(duration))
183
 
        return res
184
 
 
185
 
    def onchange_section_id(self, cr, uid, ids, section_id, context={}):
186
 
        v = {}
187
 
        logging.getLogger('crm_enhancements').warning("Value sent %s", section_id)
188
 
        if section_id <> 0 :
189
 
            sid = self.pool.get('crm.case.section').browse(cr,uid,section_id)
190
 
            v = { 'user_id':sid.user_id.id }
191
 
        return {'value':v}
192
 
 
193
 
    def _get_attach_ids(self, cr, uid, ids, field_name, arg, context={}):
194
 
        result = {}
195
 
        for record in self.browse(cr, uid, ids, context=context):
196
 
            if record.message_ids:
197
 
                result[record.id]=[]
198
 
                for msgid in record.message_ids:
199
 
                    for attachid in msgid.attachment_ids:
200
 
                        result[record.id].append(attachid.id)
201
 
            else:
202
 
                result[record.id]= False
203
 
        return result
204
 
 
205
 
    def _get_comms_ids(self, cr, uid, ids, field_name, arg, context={}):
206
 
        result = {}
207
 
        for record in self.browse(cr, uid, ids, context=context):
208
 
            if record.message_ids:
209
 
                result[record.id]=[]
210
 
                for msgid in record.message_ids:
211
 
                    if ( msgid.history or msgid.name.upper() == "NOTE" ) :
212
 
                        if ( field_name=='communication_ids'):
213
 
                            result[record.id].append(msgid.id)
214
 
                    elif ( field_name=='history_ids'):
215
 
                        result[record.id].append(msgid.id)
216
 
            else:
217
 
                result[record.id]= False
218
 
        return result
219
 
 
220
 
    def case_ready(self, cr, uid, ids, *args):
221
 
        """Readies Case
222
 
        @param self: The object pointer
223
 
        @param cr: the current row, from the database cursor,
224
 
        @param uid: the current user's ID for security checks,
225
 
        @param ids: List of case Ids
226
 
        @param *args: Tuple Value for additional Params
227
 
        """
228
 
        cases = self.browse(cr, uid, ids)
229
 
        cases[0].state # to fill the browse record cache
230
 
        self._history(cr, uid, cases, _('Ready'))
231
 
        self.write(cr, uid, ids, {'state': 'ready'})
232
 
        #
233
 
        # We use the cache of cases to keep the old case state
234
 
        #
235
 
        self._action(cr, uid, cases, 'ready')
236
 
        return True
237
 
 
238
 
    def case_planned(self, cr, uid, ids, *args):
239
 
        """Case is effectively planned
240
 
        @param self: The object pointer
241
 
        @param cr: the current row, from the database cursor,
242
 
        @param uid: the current user's ID for security checks,
243
 
        @param ids: List of case Ids
244
 
        @param *args: Tuple Value for additional Params
245
 
        """
246
 
        cases = self.browse(cr, uid, ids)
247
 
        cases[0].state # to fill the browse record cache
248
 
        self._history(cr, uid, cases, _('Planned'))
249
 
        self.write(cr, uid, ids, {'state': 'planned'})
250
 
        #
251
 
        # We use the cache of cases to keep the old case state
252
 
        #
253
 
        self._action(cr, uid, cases, 'planned')
254
 
        return True
255
 
    
256
 
    _columns = {
257
 
        # Overridden from res.partner.address:
258
 
        'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
259
 
            select=True, help="Optional linked partner, usually after conversion of the lead"),
260
 
        'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
261
 
                                 domain="[('partner_id','=',partner_id)]"),
262
 
 
263
 
        # From crm.case
264
 
        'id': fields.integer('ID'),
265
 
        'name': fields.char('Name', size=64),
266
 
        'active': fields.boolean('Active', required=False),
267
 
        'date_action_last': fields.datetime('Last Action', readonly=1),
268
 
        'date_action_next': fields.datetime('Next Action', readonly=1),
269
 
        'email_from': fields.char('Email', size=128, help="E-mail address of the contact"),
270
 
        'section_id': fields.many2one('crm.case.section', 'Section', \
271
 
                        select=True, help='Sales team to which this case belongs to. Defines responsible user and e-mail address for the mail gateway.'),
272
 
        'create_date': fields.datetime('Creation Date' , readonly=True),
273
 
        'email_cc': fields.text('Global CC', 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"),
274
 
        'description': fields.text('Notes'),
275
 
        'write_date': fields.datetime('Update Date' , readonly=True),
276
 
 
277
 
        # Lead fields
278
 
        'categ_id': fields.many2one('crm.case.categ', 'Category', \
279
 
            domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
280
 
        'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
281
 
            domain="['|',('section_id','=',section_id),('section_id','=',False)]"),
282
 
        'channel_id': fields.many2one('res.partner.canal', 'Channel'),
283
 
 
284
 
        'contact_name': fields.char('Contact Name', size=64),
285
 
        'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner that will be created while converting the into opportunity'),
286
 
        'optin': fields.boolean('Opt-In', help="If opt-in is checked, this contact has accepted to receive emails."),
287
 
        'optout': fields.boolean('Opt-Out', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."),
288
 
        'type':fields.selection([
289
 
            ('activity','Activity'),
290
 
        ],'Type', help="Type is used to separate different types of production entities"),
291
 
        'priority': fields.selection(crm.crm.AVAILABLE_PRIORITIES, 'Priority'),
292
 
        'date_closed': fields.datetime('Closed', readonly=True),
293
 
        'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('type','=','lead')]"),
294
 
        'user_id': fields.many2one('res.users', 'Responsible',help='By Default Salesman is Administrator when create New User'),
295
 
        'engineer_id': fields.many2one('res.users', 'Planned for',help='The appointed engineer to execute the call'),
296
 
        'referred': fields.char('Referred By', size=64),
297
 
        'date_open': fields.datetime('Opened', readonly=True),
298
 
        'day_open': fields.function(_compute_day, string='Days to Open', \
299
 
                                method=True, multi='day_open', type="float", store=True),
300
 
        'day_close': fields.function(_compute_day, string='Days to Close', \
301
 
                                method=True, multi='day_close', type="float", store=True),
302
 
        'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True,
303
 
                                  help='The state is set to \'Draft\', when a case is created.\
304
 
                                  \nIf the case is in progress the state is set to \'Open\'.\
305
 
                                  \nWhen the case is over, the state is set to \'Done\'.\
306
 
                                  \nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
307
 
        'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
308
 
 
309
 
        # Opportunity fields
310
 
        'probability': fields.float('Probability (%)',group_operator="avg"),
311
 
        'planned_revenue': fields.float('Expected Revenue'),
312
 
        'ref': fields.reference('Reference', selection=crm.crm._links_get, size=128),
313
 
        'ref2': fields.reference('Reference 2', selection=crm.crm._links_get, size=128),
314
 
        'phone': fields.char("Phone", size=64),
315
 
        'date_deadline': fields.date('Expected Closing'),
316
 
        'date_action': fields.date('Next Action Date'),
317
 
        'title_action': fields.char('Next Action', size=64),
318
 
 
319
 
        # CRM enhancements fields
320
 
        'attachment_ids' : fields.function(_get_attach_ids,method=True,type="many2many",string="Attachments",relation="ir.attachment"),
321
 
        'communication_ids' : fields.function(_get_comms_ids,method=True,type="many2many",string="Communication Items",relation="mailgate.message"),
322
 
        'history_ids' : fields.function(_get_comms_ids,method=True,type="many2many",string="History Items",relation="mailgate.message"),
323
 
 
324
 
    }
325
 
 
326
 
 
327
 
    _defaults = {
328
 
        'active': lambda *a: 1,
329
 
        'user_id': crm_case._get_default_user,
330
 
        'email_from': crm_case._get_default_email,
331
 
        'state': lambda *a: 'open',
332
 
        'type': lambda *a: 'activity',
333
 
        'section_id': crm_case._get_section,
334
 
        'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
335
 
        'priority': lambda *a: crm.crm.AVAILABLE_PRIORITIES[2][0],
336
 
        'stage_id': _get_stage_id,
337
 
    }
338
 
 
339
 
    def message_new(self, cr, uid, msg, context=None):
340
 
        """
341
 
        Automatically calls when new email message arrives
342
 
 
343
 
        @param self: The object pointer
344
 
        @param cr: the current row, from the database cursor,
345
 
        @param uid: the current user's ID for security checks
346
 
        """
347
 
        mailgate_pool = self.pool.get('email.server.tools')
348
 
        subject = msg.get('subject')
349
 
        body = msg.get('body')
350
 
        msg_from = msg.get('from')
351
 
        priority = msg.get('priority')
352
 
 
353
 
        vals = {
354
 
            'name': subject,
355
 
            'email_from': msg_from,
356
 
            'email_cc': msg.get('cc'),
357
 
            'description': body,
358
 
            'user_id': False,
359
 
        }
360
 
        if msg.get('priority', False):
361
 
            vals['priority'] = priority
362
 
 
363
 
        res = mailgate_pool.get_partner(cr, uid, msg.get('from') or msg.get_unixfrom())
364
 
        if res:
365
 
            vals.update(res)
366
 
        res = self.create(cr, uid, vals, context)
367
 
        attachments = msg.get('attachments', [])
368
 
        for attachment in attachments or []:
369
 
            data_attach = {
370
 
                'name': attachment,
371
 
                'datas':binascii.b2a_base64(str(attachments.get(attachment))),
372
 
                'datas_fname': attachment,
373
 
                'description': 'Mail attachment',
374
 
                'res_model': self._name,
375
 
                'res_id': res,
376
 
            }
377
 
            self.pool.get('ir.attachment').create(cr, uid, data_attach)
378
 
 
379
 
        return res
380
 
 
381
 
crm_activities()
382
 
 
383
 
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:        
 
1
##############################################################################
 
2
#
 
3
#    OpenERP, Open Source Management Solution
 
4
#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
 
5
#
 
6
#    This program is free software: you can redistribute it and/or modify
 
7
#    it under the terms of the GNU Affero General Public License as
 
8
#    published by the Free Software Foundation, either version 3 of the
 
9
#    License, or (at your option) any later version.
 
10
#
 
11
#    This program is distributed in the hope that it will be useful,
 
12
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
#    GNU Affero General Public License for more details.
 
15
#
 
16
#    You should have received a copy of the GNU Affero General Public License
 
17
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
#
 
19
##############################################################################
 
20
 
 
21
from osv import fields, osv
 
22
from datetime import datetime
 
23
import crm
 
24
import time
 
25
from tools.translate import _
 
26
from crm.crm import crm_case
 
27
import binascii
 
28
import tools
 
29
import logging
 
30
 
 
31
AVAILABLE_STATES = [
 
32
    ('draft', 'Draft'),
 
33
    ('open', 'Open'),
 
34
    ('cancel', 'Cancelled'),
 
35
    ('done', 'Done'),
 
36
    ('pending', 'Pending'),
 
37
    ('ready', 'Intake OK'),
 
38
    ('planned', 'Planned'),
 
39
]
 
40
 
 
41
 
 
42
class crm_case_stage(osv.osv):
 
43
    """ Stage of case """
 
44
    _inherit = "crm.case.stage"
 
45
 
 
46
    def _get_type_value(self, cr, user, context):
 
47
        return [('lead','Lead'),('opportunity','Opportunity'),('activity','Activity')]
 
48
 
 
49
    _columns = {
 
50
        'type': fields.selection(_get_type_value, 'Type'),
 
51
    }
 
52
 
 
53
crm_case_stage()
 
54
 
 
55
class crm_activities(crm_case, osv.osv):
 
56
    """ CRM Activity Case """
 
57
    _name = "crm.activities"
 
58
    _description = "Case Driven Activities"
 
59
    _order = "date_action, priority, id desc"
 
60
    _inherit = ['mailgate.thread','res.partner.address','crm.lead']
 
61
        
 
62
    def _get_stage_id(self, cr, uid, context={}):
 
63
        if context is None:
 
64
            context = {}
 
65
        stage_pool = self.pool.get('crm.case.stage')
 
66
        stage_type = context and context.get('stage_type','')
 
67
        logging.getLogger('crm_enhancements').warning("Stage Type %s", stage_type)
 
68
        if not stage_type:
 
69
            stage_type='activity'
 
70
        domain = [('type', '=', stage_type)]
 
71
        stages = stage_pool.search(cr, uid, domain, order='sequence')
 
72
        return stages[0]
 
73
 
 
74
    def action_makeMeeting(self, cr, uid, ids, context=None):
 
75
        logging.getLogger('crm_activities').warning("Context %s", context)
 
76
        """
 
77
        This opens Meeting's calendar view to schedule meeting on current Opportunity
 
78
        @param self: The object pointer
 
79
 
 
80
        @param cr: the current row, from the database cursor,
 
81
        @param uid: the current user's ID for security checks,
 
82
        @param ids: List of Opportunity to Meeting IDs
 
83
        @param context: A standard dictionary for contextual values
 
84
 
 
85
        @return : Dictionary value for created Meeting view
 
86
        """
 
87
        value = {}
 
88
        for opp in self.browse(cr, uid, ids, context=context):
 
89
            data_obj = self.pool.get('ir.model.data')
 
90
 
 
91
            # Get meeting views
 
92
            result = data_obj._get_id(cr, uid, 'crm', 'view_crm_case_meetings_filter')
 
93
            res = data_obj.read(cr, uid, result, ['res_id'])
 
94
            id1 = data_obj._get_id(cr, uid, 'crm_activities', 'crm_case_calendar_view_meet')
 
95
            id2 = data_obj._get_id(cr, uid, 'crm_activities', 'crm_case_form_view_meet')
 
96
            id3 = data_obj._get_id(cr, uid, 'crm_activities', 'crm_case_tree_view_meet')
 
97
            if id1:
 
98
                id1 = data_obj.browse(cr, uid, id1, context=context).res_id
 
99
            if id2:
 
100
                id2 = data_obj.browse(cr, uid, id2, context=context).res_id
 
101
            if id3:
 
102
                id3 = data_obj.browse(cr, uid, id3, context=context).res_id
 
103
 
 
104
            context = {
 
105
                'default_opportunity_id': opp.id,
 
106
                'default_partner_id': opp.partner_id and opp.partner_id.id or False,
 
107
                'default_user_id': context['uid'],
 
108
                'default_section_id': opp.section_id and opp.section_id.id or False,
 
109
                'default_email_from': opp.email_from,
 
110
                'default_state': 'open',
 
111
                'default_name': opp.name
 
112
            }
 
113
            logging.getLogger('crm_activities').warning("Context 2: %s", context)
 
114
            value = {
 
115
                'name': _('Meetings'),
 
116
                'context': context,
 
117
                'view_type': 'form',
 
118
                'view_mode': 'calendar,form,tree',
 
119
                'res_model': 'crm.meeting.activities',
 
120
                'view_id': False,
 
121
                'views': [(id1, 'calendar'), (id2, 'form'), (id3, 'tree')],
 
122
                'type': 'ir.actions.act_window',
 
123
                'search_view_id': res['res_id'],
 
124
                'nodestroy': True
 
125
            }
 
126
        return value
 
127
 
 
128
    def _compute_day(self, cr, uid, ids, fields, args, context=None):
 
129
        """
 
130
        @param cr: the current row, from the database cursor,
 
131
        @param uid: the current user's ID for security checks,
 
132
        @param ids: List of Openday's IDs
 
133
        @return: difference between current date and log date
 
134
        @param context: A standard dictionary for contextual values
 
135
        """
 
136
        cal_obj = self.pool.get('resource.calendar')
 
137
        res_obj = self.pool.get('resource.resource')
 
138
 
 
139
        res = {}
 
140
        for lead in self.browse(cr, uid, ids, context=context):
 
141
            for field in fields:
 
142
                res[lead.id] = {}
 
143
                duration = 0
 
144
                ans = False
 
145
                if field == 'day_open':
 
146
                    if lead.date_open:
 
147
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
 
148
                        date_open = datetime.strptime(lead.date_open, "%Y-%m-%d %H:%M:%S")
 
149
                        ans = date_open - date_create
 
150
                        date_until = lead.date_open
 
151
                elif field == 'day_close':
 
152
                    if lead.date_closed:
 
153
                        date_create = datetime.strptime(lead.create_date, "%Y-%m-%d %H:%M:%S")
 
154
                        date_close = datetime.strptime(lead.date_closed, "%Y-%m-%d %H:%M:%S")
 
155
                        date_until = lead.date_closed
 
156
                        ans = date_close - date_create
 
157
                if ans:
 
158
                    resource_id = False
 
159
                    if lead.user_id:
 
160
                        resource_ids = res_obj.search(cr, uid, [('user_id','=',lead.user_id.id)])
 
161
                        if len(resource_ids):
 
162
                            resource_id = resource_ids[0]
 
163
 
 
164
                    duration = float(ans.days)
 
165
                    if lead.section_id and lead.section_id.resource_calendar_id:
 
166
                        duration =  float(ans.days) * 24
 
167
                        new_dates = cal_obj.interval_get(cr,
 
168
                            uid,
 
169
                            lead.section_id.resource_calendar_id and lead.section_id.resource_calendar_id.id or False,
 
170
                            datetime.strptime(lead.create_date, '%Y-%m-%d %H:%M:%S'),
 
171
                            duration,
 
172
                            resource=resource_id
 
173
                        )
 
174
                        no_days = []
 
175
                        date_until = datetime.strptime(date_until, '%Y-%m-%d %H:%M:%S')
 
176
                        for in_time, out_time in new_dates:
 
177
                            if in_time.date not in no_days:
 
178
                                no_days.append(in_time.date)
 
179
                            if out_time > date_until:
 
180
                                break
 
181
                        duration =  len(no_days)
 
182
                res[lead.id][field] = abs(int(duration))
 
183
        return res
 
184
 
 
185
    def onchange_section_id(self, cr, uid, ids, section_id, context={}):
 
186
        v = {}
 
187
        logging.getLogger('crm_enhancements').warning("Value sent %s", section_id)
 
188
        if section_id <> 0 :
 
189
            sid = self.pool.get('crm.case.section').browse(cr,uid,section_id)
 
190
            v = { 'user_id':sid.user_id.id }
 
191
        return {'value':v}
 
192
 
 
193
    def _get_attach_ids(self, cr, uid, ids, field_name, arg, context={}):
 
194
        result = {}
 
195
        for record in self.browse(cr, uid, ids, context=context):
 
196
            if record.message_ids:
 
197
                result[record.id]=[]
 
198
                for msgid in record.message_ids:
 
199
                    for attachid in msgid.attachment_ids:
 
200
                        result[record.id].append(attachid.id)
 
201
            else:
 
202
                result[record.id]= False
 
203
        return result
 
204
 
 
205
    def _get_comms_ids(self, cr, uid, ids, field_name, arg, context={}):
 
206
        result = {}
 
207
        for record in self.browse(cr, uid, ids, context=context):
 
208
            if record.message_ids:
 
209
                result[record.id]=[]
 
210
                for msgid in record.message_ids:
 
211
                    if ( msgid.history or msgid.name.upper() == "NOTE" ) :
 
212
                        if ( field_name=='communication_ids'):
 
213
                            result[record.id].append(msgid.id)
 
214
                    elif ( field_name=='history_ids'):
 
215
                        result[record.id].append(msgid.id)
 
216
            else:
 
217
                result[record.id]= False
 
218
        return result
 
219
 
 
220
    def case_ready(self, cr, uid, ids, *args):
 
221
        """Readies Case
 
222
        @param self: The object pointer
 
223
        @param cr: the current row, from the database cursor,
 
224
        @param uid: the current user's ID for security checks,
 
225
        @param ids: List of case Ids
 
226
        @param *args: Tuple Value for additional Params
 
227
        """
 
228
        cases = self.browse(cr, uid, ids)
 
229
        cases[0].state # to fill the browse record cache
 
230
        self._history(cr, uid, cases, _('Ready'))
 
231
        self.write(cr, uid, ids, {'state': 'ready'})
 
232
        #
 
233
        # We use the cache of cases to keep the old case state
 
234
        #
 
235
        self._action(cr, uid, cases, 'ready')
 
236
        return True
 
237
 
 
238
    def case_planned(self, cr, uid, ids, *args):
 
239
        """Case is effectively planned
 
240
        @param self: The object pointer
 
241
        @param cr: the current row, from the database cursor,
 
242
        @param uid: the current user's ID for security checks,
 
243
        @param ids: List of case Ids
 
244
        @param *args: Tuple Value for additional Params
 
245
        """
 
246
        cases = self.browse(cr, uid, ids)
 
247
        cases[0].state # to fill the browse record cache
 
248
        self._history(cr, uid, cases, _('Planned'))
 
249
        self.write(cr, uid, ids, {'state': 'planned'})
 
250
        #
 
251
        # We use the cache of cases to keep the old case state
 
252
        #
 
253
        self._action(cr, uid, cases, 'planned')
 
254
        return True
 
255
    
 
256
    _columns = {
 
257
        # Overridden from res.partner.address:
 
258
        'partner_id': fields.many2one('res.partner', 'Partner', ondelete='set null',
 
259
            select=True, help="Optional linked partner, usually after conversion of the lead"),
 
260
        'partner_address_id': fields.many2one('res.partner.address', 'Partner Contact', \
 
261
                                 domain="[('partner_id','=',partner_id)]"),
 
262
 
 
263
        # From crm.case
 
264
        'id': fields.integer('ID'),
 
265
        'name': fields.char('Name', size=64),
 
266
        'active': fields.boolean('Active', required=False),
 
267
        'date_action_last': fields.datetime('Last Action', readonly=1),
 
268
        'date_action_next': fields.datetime('Next Action', readonly=1),
 
269
        'email_from': fields.char('Email', size=128, help="E-mail address of the contact"),
 
270
        'section_id': fields.many2one('crm.case.section', 'Section', \
 
271
                        select=True, help='Sales team to which this case belongs to. Defines responsible user and e-mail address for the mail gateway.'),
 
272
        'create_date': fields.datetime('Creation Date' , readonly=True),
 
273
        'email_cc': fields.text('Global CC', 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"),
 
274
        'description': fields.text('Notes'),
 
275
        'write_date': fields.datetime('Update Date' , readonly=True),
 
276
 
 
277
        # Lead fields
 
278
        'categ_id': fields.many2one('crm.case.categ', 'Category', \
 
279
            domain="['|',('section_id','=',section_id),('section_id','=',False), ('object_id.model', '=', 'crm.lead')]"),
 
280
        'type_id': fields.many2one('crm.case.resource.type', 'Campaign', \
 
281
            domain="['|',('section_id','=',section_id),('section_id','=',False)]"),
 
282
        'channel_id': fields.many2one('res.partner.canal', 'Channel'),
 
283
 
 
284
        'contact_name': fields.char('Contact Name', size=64),
 
285
        'partner_name': fields.char("Customer Name", size=64,help='The name of the future partner that will be created while converting the into opportunity'),
 
286
        'optin': fields.boolean('Opt-In', help="If opt-in is checked, this contact has accepted to receive emails."),
 
287
        'optout': fields.boolean('Opt-Out', help="If opt-out is checked, this contact has refused to receive emails or unsubscribed to a campaign."),
 
288
        'type':fields.selection([
 
289
            ('activity','Activity'),
 
290
        ],'Type', help="Type is used to separate different types of production entities"),
 
291
        'priority': fields.selection(crm.crm.AVAILABLE_PRIORITIES, 'Priority'),
 
292
        'date_closed': fields.datetime('Closed', readonly=True),
 
293
        'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('type','=','activity')]"),
 
294
        'user_id': fields.many2one('res.users', 'Responsible',help='By Default Salesman is Administrator when create New User'),
 
295
        'engineer_id': fields.many2one('res.users', 'Planned for',help='The appointed engineer to execute the call'),
 
296
        'referred': fields.char('Referred By', size=64),
 
297
        'date_open': fields.datetime('Opened', readonly=True),
 
298
        'day_open': fields.function(_compute_day, string='Days to Open', \
 
299
                                method=True, multi='day_open', type="float", store=True),
 
300
        'day_close': fields.function(_compute_day, string='Days to Close', \
 
301
                                method=True, multi='day_close', type="float", store=True),
 
302
        'state': fields.selection(AVAILABLE_STATES, 'State', size=16, readonly=True,
 
303
                                  help='The state is set to \'Draft\', when a case is created.\
 
304
                                  \nIf the case is in progress the state is set to \'Open\'.\
 
305
                                  \nWhen the case is over, the state is set to \'Done\'.\
 
306
                                  \nIf the case needs to be reviewed then the state is set to \'Pending\'.'),
 
307
        'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
 
308
 
 
309
        # Opportunity fields
 
310
        'probability': fields.float('Probability (%)',group_operator="avg"),
 
311
        'planned_revenue': fields.float('Expected Revenue'),
 
312
        'ref': fields.reference('Reference', selection=crm.crm._links_get, size=128),
 
313
        'ref2': fields.reference('Reference 2', selection=crm.crm._links_get, size=128),
 
314
        'phone': fields.char("Phone", size=64),
 
315
        'date_deadline': fields.date('Expected Closing'),
 
316
        'date_action': fields.date('Next Action Date'),
 
317
        'title_action': fields.char('Next Action', size=64),
 
318
 
 
319
        # CRM enhancements fields
 
320
        'attachment_ids' : fields.function(_get_attach_ids,method=True,type="many2many",string="Attachments",relation="ir.attachment"),
 
321
        'communication_ids' : fields.function(_get_comms_ids,method=True,type="many2many",string="Communication Items",relation="mailgate.message"),
 
322
        'history_ids' : fields.function(_get_comms_ids,method=True,type="many2many",string="History Items",relation="mailgate.message"),
 
323
 
 
324
    }
 
325
 
 
326
 
 
327
    _defaults = {
 
328
        'active': lambda *a: 1,
 
329
        'user_id': crm_case._get_default_user,
 
330
        'email_from': crm_case._get_default_email,
 
331
        'state': lambda *a: 'open',
 
332
        'type': lambda *a: 'activity',
 
333
        'section_id': crm_case._get_section,
 
334
        'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
 
335
        'priority': lambda *a: crm.crm.AVAILABLE_PRIORITIES[2][0],
 
336
        'stage_id': _get_stage_id,
 
337
    }
 
338
 
 
339
    def message_new(self, cr, uid, msg, context=None):
 
340
        """
 
341
        Automatically calls when new email message arrives
 
342
 
 
343
        @param self: The object pointer
 
344
        @param cr: the current row, from the database cursor,
 
345
        @param uid: the current user's ID for security checks
 
346
        """
 
347
        mailgate_pool = self.pool.get('email.server.tools')
 
348
        subject = msg.get('subject')
 
349
        body = msg.get('body')
 
350
        msg_from = msg.get('from')
 
351
        priority = msg.get('priority')
 
352
 
 
353
        vals = {
 
354
            'name': subject,
 
355
            'email_from': msg_from,
 
356
            'email_cc': msg.get('cc'),
 
357
            'description': body,
 
358
            'user_id': False,
 
359
        }
 
360
        if msg.get('priority', False):
 
361
            vals['priority'] = priority
 
362
 
 
363
        res = mailgate_pool.get_partner(cr, uid, msg.get('from') or msg.get_unixfrom())
 
364
        if res:
 
365
            vals.update(res)
 
366
        res = self.create(cr, uid, vals, context)
 
367
        attachments = msg.get('attachments', [])
 
368
        for attachment in attachments or []:
 
369
            data_attach = {
 
370
                'name': attachment,
 
371
                'datas':binascii.b2a_base64(str(attachments.get(attachment))),
 
372
                'datas_fname': attachment,
 
373
                'description': 'Mail attachment',
 
374
                'res_model': self._name,
 
375
                'res_id': res,
 
376
            }
 
377
            self.pool.get('ir.attachment').create(cr, uid, data_attach)
 
378
 
 
379
        return res
 
380
 
 
381
crm_activities()
 
382
 
 
383
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: