[REF] purchase: search view of purchase order and form view of merge order wizard
[odoo/odoo.git] / addons / base_module_quality / base_module_quality.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 import os
22
23 import pooler
24 import osv
25 import tools
26 from tools import config
27 from tools.translate import _
28 from osv import osv, fields
29
30 class abstract_quality_check(object):
31     '''
32         This Class is abstract class for all test
33     '''
34
35     def __init__(self):
36         '''
37         this method should initialize the variables
38         '''
39         #This float have to store the rating of the module.
40         #Used to compute the final score (average of all scores).
41         #0 <= self.score <= 1
42         self.score = 0.0
43
44         #This char have to store the name of the test.
45         self.name = ""
46
47         #This char have to store the aim of the test and eventually a note.
48         self.note = ""
49
50         #This char have to store the result.
51         #Used to display the result of the test.
52         self.result = ""
53
54         #This char have to store the result with more details.
55         #Used to provide more details if necessary.
56         self.result_details = ""
57
58         # This boolean variable defines that if you do not want to calculate score and just only need detail
59         # or summary report for some test then you will make it False.
60         self.bool_count_score = True
61
62         #This bool defines if the test can be run only if the module
63         #is installed.
64         #True => the module have to be installed.
65         #False => the module can be uninstalled.
66         self.bool_installed_only = True
67
68         #This variable is used to give result of test more weight,
69         #because some tests are more critical than others.
70         self.ponderation = 1.0
71
72         #Specify test got an error on module
73         self.error = False
74
75         #Specify the minimal score for the test (in percentage(%))
76         self.min_score = 50
77
78         #Specify whether test should be consider for Quality checking of the module
79         self.active = True
80
81         #This variable used to give message if test result is good or not
82         self.message = ''
83
84         #The tests have to subscribe itselfs in this list, that contains
85         #all the test that have to be performed.
86         self.tests = []
87         self.list_folders = os.listdir(config['addons_path'] +
88             '/base_module_quality/')
89         for item in self.list_folders:
90             self.item = item
91             path = config['addons_path']+'/base_module_quality/'+item
92             if os.path.exists(path + '/' + item + '.py') and item not in ['report', 'wizard', 'security']:
93                 item2 = 'base_module_quality.' + item +'.' + item
94                 x_module = __import__(item2)
95                 x_file = getattr(x_module, item)
96                 x_obj = getattr(x_file, item)
97                 self.tests.append(x_obj)
98 #        raise 'Not Implemented'
99
100     def run_test(self, cr, uid, module_path=""):
101         '''
102         this method should do the test and fill the score, result and result_details var
103         '''
104         raise osv.except_osv(_('Programming Error'), _('Test Is Not Implemented'))
105
106     def get_objects(self, cr, uid, module):
107         # This function returns all object of the given module..
108         pool = pooler.get_pool(cr.dbname)
109         ids2 = pool.get('ir.model.data').search(cr, uid,
110             [('module', '=', module), ('model', '=', 'ir.model')])
111         model_list = []
112         model_data = pool.get('ir.model.data').browse(cr, uid, ids2)
113         for model in model_data:
114             model_list.append(model.res_id)
115         obj_list = []
116         for mod in pool.get('ir.model').browse(cr, uid, model_list):
117             obj_list.append(str(mod.model))
118         return obj_list
119
120     def get_model_ids(self, cr, uid, models=[]):
121         # This function returns all ids of the given objects..
122         if not models:
123             return []
124         pool = pooler.get_pool(cr.dbname)
125         return pool.get('ir.model').search(cr, uid, [('model', 'in', models)])
126
127     def get_ids(self, cr, uid, object_list):
128         #This method return dictionary with ids of records of object for module
129         pool = pooler.get_pool(cr.dbname)
130         result_ids = {}
131         for obj in object_list:
132             ids = pool.get(obj).search(cr, uid, [])
133             ids = filter(lambda id: id != None, ids or [])
134             result_ids[obj] = ids
135         return result_ids
136
137     def format_table(self, header=[], data_list={}): #This function can work forwidget="text_wiki"
138         detail = ""
139         detail += (header[0]) % tuple(header[1])
140         frow = '\n|-'
141         for i in header[1]:
142             frow += '\n| %s'
143         for key, value in data_list.items():
144             detail += (frow) % tuple(value)
145         detail = detail + '\n|}'
146         return detail
147
148     def format_html_table(self, header=[], data_list=[]): #This function can work for widget="html_tag"
149         # function create html table....
150         detail = ""
151         detail += (header[0]) % tuple(header[1])
152         frow = '<tr>'
153         for i in header[1]:
154             frow += '<td>%s</td>'
155         frow += '</tr>'
156         for key, value in data_list.items():
157             detail += (frow) % tuple(value)
158         return detail
159
160     def add_quatation(self, x_no, y_no):
161         return x_no/y_no
162
163     def get_style(self):
164         # This function return style tag with specified styles for html pages
165         style = '''
166             <style>
167                 .divstyle {
168                 border:1px solid #aaaaaa;
169                 background-color:#f9f9f9;
170                 padding:5px;
171                 }
172                 .tablestyle
173                 {
174                 border:1px dashed gray;
175                 }
176                 .tdatastyle
177                 {
178                 border:0.5px solid gray;
179                 }
180                 .head
181                 {
182                 color: black;
183                 background: none;
184                 font-weight: normal;
185                 margin: 0;
186                 padding-top: .5em;
187                 padding-bottom: .17em;
188                 border-bottom: 1px solid #aaa;
189                 }
190                 }
191           </style> '''
192         return style
193
194
195 class module_quality_check(osv.osv):
196     _name = 'module.quality.check'
197     _columns = {
198         'name': fields.char('Rated Module', size=64, ),
199         'final_score': fields.char('Final Score (%)', size=10,),
200         'check_detail_ids': fields.one2many('module.quality.detail', 'quality_check_id', 'Tests',)
201     }
202
203     def check_quality(self, cr, uid, module_name, module_state=None):
204         '''
205         This function will calculate score of openerp module
206         It will return data in below format:
207             Format: {'final_score':'80.50', 'name': 'sale',
208                     'check_detail_ids':
209                         [(0,0,{'name':'workflow_test', 'score':'100', 'ponderation':'0', 'summary': text_wiki format data, 'detail': html format data, 'state':'done', 'note':'XXXX'}),
210                         ((0,0,{'name':'terp_test', 'score':'60', 'ponderation':'1', 'summary': text_wiki format data, 'detail': html format data, 'state':'done', 'note':'terp desctioption'}),
211                          ..........]}
212         So here the detail result is in html format and summary will be in text_wiki format.
213         '''
214         #list_folders = os.listdir(config['addons_path']+'/base_module_quality/')
215         pool = pooler.get_pool(cr.dbname)
216         obj_module = pool.get('ir.module.module')
217         if not module_state:
218             module_id = obj_module.search(cr, uid, [('name', '=', module_name)])
219             if module_id:
220                 module_state = obj_module.browse(cr, uid, module_id[0]).state
221
222         abstract_obj = abstract_quality_check()
223         score_sum = 0.0
224         ponderation_sum = 0.0
225         create_ids = []
226         for test in abstract_obj.tests:
227             ad = tools.config['addons_path']
228             if module_name == 'base':
229                 ad = tools.config['root_path']+'/addons'
230             module_path = os.path.join(ad, module_name)
231             val = test.quality_test()
232             if val.active:
233                 if not val.bool_installed_only or module_state == "installed":
234                     val.run_test(cr, uid, str(module_path))
235                     if not val.error:
236                         data = {
237                             'name': val.name,
238                             'score': val.score * 100,
239                             'ponderation': val.ponderation,
240                             'summary': val.result,
241                             'detail': val.result_details,
242                             'state': 'done',
243                             'note': val.note,
244                             'message': val.message
245                         }
246                         if val.bool_count_score:
247                             score_sum += val.score * val.ponderation
248                             ponderation_sum += val.ponderation
249                     else:
250                         data = {
251                             'name': val.name,
252                             'score': 0,
253                             'summary': val.result,
254                             'state': 'skipped',
255                             'note': val.note,
256                         }
257                 else:
258                     data = {
259                         'name': val.name,
260                         'note': val.note,
261                         'score': 0,
262                         'state': 'skipped',
263                         'summary': _("The module has to be installed before running this test.")
264                     }
265                 create_ids.append((0, 0, data))
266         final_score = ponderation_sum and '%.2f' % (score_sum / ponderation_sum * 100) or 0
267         data = {
268             'name': module_name,
269             'final_score': final_score,
270             'check_detail_ids' : create_ids,
271         }
272         return data
273
274 module_quality_check()
275
276 class module_quality_detail(osv.osv):
277     _name = 'module.quality.detail'
278     _columns = {
279         'quality_check_id': fields.many2one('module.quality.check', 'Quality'),
280         'name': fields.char('Name',size=128),
281         'score': fields.float('Score (%)'),
282         'ponderation': fields.float('Ponderation', help='Some tests are more critical than others, so they have a bigger weight in the computation of final rating'),
283         'note': fields.text('Note'),
284         'summary': fields.text('Summary'),
285         'detail': fields.text('Details'),
286         'message': fields.char('Message', size=64),
287         'state': fields.selection([('done','Done'),('skipped','Skipped'),], 'State', size=6, help='The test will be completed only if the module is installed or if the test may be processed on uninstalled module.'),
288     }
289
290 module_quality_detail()
291
292 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: