7e70df3dc4a6c215f4f291f1cace662413d31170
[odoo/odoo.git] / addons / crm_profiling / crm_profiling.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
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 osv import fields,osv
23 from osv import orm
24
25 from tools.translate import _
26
27 def _get_answers(cr, uid, ids):
28     query = """
29     select distinct(answer)
30     from profile_question_yes_rel
31     where profile=ANY(%s)"""
32
33     cr.execute(query,(ids,))
34     ans_yes = [x[0] for x in cr.fetchall()]
35
36     query = """
37     select distinct(answer)
38     from profile_question_no_rel
39     where profile=ANY(%s)"""
40
41     cr.execute(query,(ids,))
42     ans_no = [x[0] for x in cr.fetchall()]
43
44     return [ans_yes, ans_no]
45
46
47 def _get_parents(cr, uid, ids):
48     ids_to_check = ids
49     cr.execute("""
50      select distinct(parent_id)
51      from crm_segmentation
52      where parent_id is not null
53      and id=ANY(%s)""",(ids,))
54
55     parent_ids = [x[0] for x in cr.fetchall()]
56
57     trigger = False
58     for x in parent_ids:
59         if x not in ids_to_check:
60             ids_to_check.append(x)
61             trigger = True
62
63     if trigger:
64         ids_to_check = _get_parents(cr, uid, ids_to_check)
65
66     return ids_to_check
67
68
69 def test_prof(cr, uid, seg_id, pid, answers_ids = []):
70 #return True if the partner pid fetch the segmentation rule seg_id
71     ids_to_check = _get_parents(cr, uid, [seg_id])
72     [yes_answers, no_answers] = _get_answers(cr, uid, ids_to_check)
73     temp = True
74     for y_ans in yes_answers:
75         if y_ans not in answers_ids:
76             temp = False
77             break
78     if temp:
79         for ans in answers_ids:
80             if ans in no_answers:
81                 temp = False
82                 break
83     if temp:
84         return True
85     return False
86
87
88 def _recompute_categ(self, cr, uid, pid, answers_ids):
89     ok =  []
90     cr.execute('''
91         select r.category_id
92         from res_partner_category_rel r left join crm_segmentation s on (r.category_id = s.categ_id)
93         where r.partner_id = %s and (s.exclusif = false or s.exclusif is null)
94         ''', (pid,))
95     for x in cr.fetchall():
96         ok.append(x[0])
97
98     query = '''
99         select id, categ_id
100         from crm_segmentation
101         where profiling_active = true'''
102     if ok != []:
103         query = query +''' and categ_id not in(%s)'''% ','.join([str(i) for i in ok ])
104     query = query + ''' order by id '''
105
106     cr.execute(query)
107     segm_cat_ids = cr.fetchall()
108
109     for (segm_id, cat_id) in segm_cat_ids:
110         if test_prof(cr, uid, segm_id, pid, answers_ids):
111             ok.append(cat_id)
112     return ok
113
114
115 class question(osv.osv):
116     _name="crm_profiling.question"
117     _description= "Question"
118     _columns={
119         'name': fields.char("Question",size=128, required=True),
120         'answers_ids': fields.one2many("crm_profiling.answer","question_id","Avalaible answers",),
121         }
122
123 question()
124
125
126 class questionnaire(osv.osv):
127     _name="crm_profiling.questionnaire"
128     _description= "Questionnaire"
129
130     def build_form(self, cr, uid, data, context):
131         query = """
132         select name, id
133         from crm_profiling_question
134         where id in ( select question from profile_questionnaire_quest_rel where questionnaire = %s)"""
135         res = cr.execute(query, (data['form']['questionnaire_name'],))
136         result = cr.fetchall()
137         quest_fields={}
138         quest_form='''<?xml version="1.0"?>
139             <form string="%s">''' % _('Questionnaire')
140         for name, oid in result:
141             quest_form = quest_form + '<field name="quest_form%d"/><newline/>' % (oid,)
142             quest_fields['quest_form%d' % (oid,)] = {'string': name, 'type': 'many2one', 'relation': 'crm_profiling.answer', 'domain': [('question_id','=',oid)] }
143         quest_form = quest_form + '''</form>'''
144         return quest_form, quest_fields
145
146     _columns = {
147         'name': fields.char("Questionnaire",size=128, required=True),
148         'description':fields.text("Description", required=True),
149         'questions_ids': fields.many2many('crm_profiling.question','profile_questionnaire_quest_rel','questionnaire', 'question', "Questions"),
150     }
151
152 questionnaire()
153
154
155 class answer(osv.osv):
156     _name="crm_profiling.answer"
157     _description="Answer"
158     _columns={
159         "name": fields.char("Answer",size=128, required=True),
160         "question_id": fields.many2one('crm_profiling.question',"Question"),
161         }
162 answer()
163
164
165 class partner(osv.osv):
166     _inherit="res.partner"
167     _columns={
168         "answers_ids": fields.many2many("crm_profiling.answer","partner_question_rel","partner","answer","Answers"),
169         }
170
171     def _questionnaire_compute(self, cr, uid, data, context):
172         temp = []
173         for x in data['form']:
174             if x.startswith("quest_form") and data['form'][x] != 0 :
175                 temp.append(data['form'][x])
176
177         query = "select answer from partner_question_rel where partner=%s"
178         cr.execute(query, (data['id'],))
179         for x in cr.fetchall():
180             temp.append(x[0])
181
182         self.write(cr, uid, [data['id']],{'answers_ids':[[6,0,temp]]}, context)
183         return {}
184
185
186     def write(self, cr, uid, ids, vals, context=None):
187         if not context:
188             context={}
189         if 'answers_ids' in vals:
190             vals['category_id']=[[6, 0, _recompute_categ(self, cr, uid, ids[0], vals['answers_ids'][0][2])]]
191         return super(partner, self).write(cr, uid, ids, vals, context=context)
192
193 partner()
194
195
196 class crm_segmentation(osv.osv):
197     _inherit="crm.segmentation"
198     _columns={
199         "answer_yes": fields.many2many("crm_profiling.answer","profile_question_yes_rel","profile","answer","Included Answers"),
200         "answer_no": fields.many2many("crm_profiling.answer","profile_question_no_rel","profile","answer","Excluded Answers"),
201         'parent_id': fields.many2one('crm.segmentation', 'Parent Profile'),
202         'child_ids': fields.one2many('crm.segmentation', 'parent_id', 'Child Profiles'),
203         'profiling_active': fields.boolean('Use The Profiling Rules', help='Check this box if you want to use this tab as part of the segmentation rule. If not checked, the criteria beneath will be ignored')
204         }
205     _constraints = [
206         (orm.orm.check_recursion, 'Error ! You can not create recursive profiles.', ['parent_id'])
207     ]
208
209     def process_continue(self, cr, uid, ids, start=False):
210         categs = self.read(cr,uid,ids,['categ_id','exclusif','partner_id', 'sales_purchase_active', 'profiling_active'])
211         for categ in categs:
212             if start:
213                 if categ['exclusif']:
214                     cr.execute('delete from res_partner_category_rel where category_id=%s', (categ['categ_id'][0],))
215
216             id = categ['id']
217
218             cr.execute('select id from res_partner order by id ')
219             partners = [x[0] for x in cr.fetchall()]
220
221             if categ['sales_purchase_active']:
222                 to_remove_list=[]
223                 cr.execute('select id from crm_segmentation_line where segmentation_id=%s', (id,))
224                 line_ids = [x[0] for x in cr.fetchall()]
225
226                 for pid in partners:
227                     if (not self.pool.get('crm.segmentation.line').test(cr, uid, line_ids, pid)):
228                         to_remove_list.append(pid)
229                 for pid in to_remove_list:
230                     partners.remove(pid)
231
232             if categ['profiling_active']:
233                 to_remove_list=[]
234                 for pid in partners:
235
236                     cr.execute('select distinct(answer) from partner_question_rel where partner=%s',(pid,))
237                     answers_ids = [x[0] for x in cr.fetchall()]
238
239                     if (not test_prof(cr, uid, id, pid, answers_ids)):
240                         to_remove_list.append(pid)
241                 for pid in to_remove_list:
242                     partners.remove(pid)
243
244             for partner_id in partners:
245                 cr.execute('insert into res_partner_category_rel (category_id,partner_id) values (%s,%s)', (categ['categ_id'][0],partner_id))
246             cr.commit()
247
248             self.write(cr, uid, [id], {'state':'not running', 'partner_id':0})
249             cr.commit()
250         return True
251
252 crm_segmentation()
253 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
254