bzr revid: fp@tinyerp.com-20090109063431-pzzbjcsymkucist2
This commit is contained in:
Fabien Pinckaers 2009-01-09 07:34:31 +01:00
commit aa188ff423
15 changed files with 207 additions and 172 deletions

View File

@ -166,15 +166,14 @@ class account_account(osv.osv):
def _get_children_and_consol(self, cr, uid, ids, context={}): def _get_children_and_consol(self, cr, uid, ids, context={}):
#this function search for all the children and all consolidated children (recursively) of the given account ids #this function search for all the children and all consolidated children (recursively) of the given account ids
res = self.search(cr, uid, [('parent_id', 'child_of', ids)]) ids2 = self.search(cr, uid, [('parent_id', 'child_of', ids)], context=context)
for id in res: ids3 = []
this = self.browse(cr, uid, id, context) for rec in self.browse(cr, uid, ids2, context=context):
for child in this.child_consol_ids: for child in rec.child_consol_ids:
if child.id not in res: ids3.append[child.id]
res.append(child.id) if ids3:
if len(res) != len(ids): ids3 = self._get_children_and_consol(cr, uid, ids3, context)
return self._get_children_and_consol(cr, uid, res, context) return ids2+ids3
return res
def __compute(self, cr, uid, ids, field_names, arg, context={}, query=''): def __compute(self, cr, uid, ids, field_names, arg, context={}, query=''):
#compute the balance/debit/credit accordingly to the value of field_name for the given account ids #compute the balance/debit/credit accordingly to the value of field_name for the given account ids
@ -1224,15 +1223,15 @@ class account_tax(osv.osv):
# #
'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="Use this code for the VAT declaration."), 'base_code_id': fields.many2one('account.tax.code', 'Base Code', help="Use this code for the VAT declaration."),
'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="Use this code for the VAT declaration."), 'tax_code_id': fields.many2one('account.tax.code', 'Tax Code', help="Use this code for the VAT declaration."),
'base_sign': fields.float('Base Code Sign', help="Usualy 1 or -1."), 'base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."),
'tax_sign': fields.float('Tax Code Sign', help="Usualy 1 or -1."), 'tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
# Same fields for refund invoices # Same fields for refund invoices
'ref_base_code_id': fields.many2one('account.tax.code', 'Refund Base Code', help="Use this code for the VAT declaration."), 'ref_base_code_id': fields.many2one('account.tax.code', 'Refund Base Code', help="Use this code for the VAT declaration."),
'ref_tax_code_id': fields.many2one('account.tax.code', 'Refund Tax Code', help="Use this code for the VAT declaration."), 'ref_tax_code_id': fields.many2one('account.tax.code', 'Refund Tax Code', help="Use this code for the VAT declaration."),
'ref_base_sign': fields.float('Base Code Sign', help="Usualy 1 or -1."), 'ref_base_sign': fields.float('Base Code Sign', help="Usually 1 or -1."),
'ref_tax_sign': fields.float('Tax Code Sign', help="Usualy 1 or -1."), 'ref_tax_sign': fields.float('Tax Code Sign', help="Usually 1 or -1."),
'include_base_amount': fields.boolean('Include in base amount', help="Indicate if the amount of tax must be included in the base amount for the computation of the next taxes"), 'include_base_amount': fields.boolean('Include in base amount', help="Indicate if the amount of tax must be included in the base amount for the computation of the next taxes"),
'company_id': fields.many2one('res.company', 'Company', required=True), 'company_id': fields.many2one('res.company', 'Company', required=True),
'description': fields.char('Internal Name',size=32), 'description': fields.char('Internal Name',size=32),

View File

@ -791,6 +791,7 @@ class account_move_line(osv.osv):
move_id = vals.get('move_id', False) move_id = vals.get('move_id', False)
journal = self.pool.get('account.journal').browse(cr, uid, context['journal_id']) journal = self.pool.get('account.journal').browse(cr, uid, context['journal_id'])
is_new_move = False
if not move_id: if not move_id:
if journal.centralisation: if journal.centralisation:
# use the first move ever created for this journal and period # use the first move ever created for this journal and period
@ -815,10 +816,7 @@ class account_move_line(osv.osv):
vals['move_id'] = move_id vals['move_id'] = move_id
else: else:
raise osv.except_osv(_('No piece number !'), _('Can not create an automatic sequence for this piece !\n\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.')) raise osv.except_osv(_('No piece number !'), _('Can not create an automatic sequence for this piece !\n\nPut a sequence in the journal definition for automatic numbering or create a sequence manually for this piece.'))
else: is_new_move = True
if 'date' in vals:
self.pool.get('account.move').write(cr, uid, [move_id], {'date':vals['date']}, context=context)
del vals['date']
ok = not (journal.type_control_ids or journal.account_control_ids) ok = not (journal.type_control_ids or journal.account_control_ids)
if ('account_id' in vals): if ('account_id' in vals):
@ -931,6 +929,8 @@ class account_move_line(osv.osv):
if data['tax_code_id']: if data['tax_code_id']:
self.create(cr, uid, data, context) self.create(cr, uid, data, context)
if not is_new_move and 'date' in vals:
self.pool.get('account.move').write(cr, uid, [move_id], {'date':vals['date']}, context=context)
if check: if check:
tmp = self.pool.get('account.move').validate(cr, uid, [vals['move_id']], context) tmp = self.pool.get('account.move').validate(cr, uid, [vals['move_id']], context)
if journal.entry_posted and tmp: if journal.entry_posted and tmp:

View File

@ -297,7 +297,7 @@
<para style="terp_default_8"> <para style="terp_default_8">
<font color="white"> </font> <font color="white"> </font>
</para> </para>
<blockTable colWidths="211.0,62.0,63.0,63.0,36.0,89.0" style="Table_Header_Invoice_Line"> <blockTable colWidths="211.0,62.0,63.0,63.0,40.0,85.0" style="Table_Header_Invoice_Line">
<tr> <tr>
<td> <td>
<para style="terp_tblheader_Details">Description</para> <para style="terp_tblheader_Details">Description</para>
@ -312,7 +312,7 @@
<para style="terp_tblheader_Details_Right">Unit Price</para> <para style="terp_tblheader_Details_Right">Unit Price</para>
</td> </td>
<td> <td>
<para style="terp_tblheader_Details_Right">Disc. (%)</para> <para style="terp_tblheader_Details_Right">Disc.(%)</para>
</td> </td>
<td> <td>
<para style="terp_tblheader_Details_Centre">Price</para> <para style="terp_tblheader_Details_Centre">Price</para>
@ -350,7 +350,7 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<para style="terp_default_Note">[[ format(l.note or removeParentNode('tr')) ]]</para> <para style="terp_default_Note">[[ format(l.note) or removeParentNode('tr') ]]</para>
<para style="terp_default_Note"> <para style="terp_default_Note">
<font color="white"> </font> <font color="white"> </font>
</para> </para>
@ -463,7 +463,7 @@
<blockTable colWidths="530.0" style="Table_Main_Table"> <blockTable colWidths="530.0" style="Table_Main_Table">
<tr> <tr>
<td> <td>
<!-- <para style="terp_default_8">[[ format(o.amount_tax or removeParentNode('blockTable')) ]]</para> --> <!-- <para style="terp_default_8">[[ format(o.amount_tax) or removeParentNode('blockTable') ]]</para> -->
<blockTable colWidths="54.0,58.0,67.0" style="Table_Tax_Header"> <blockTable colWidths="54.0,58.0,67.0" style="Table_Tax_Header">
<tr> <tr>
<td> <td>
@ -541,7 +541,7 @@
<blockTable colWidths="530.0" style="Table_Coment_Payment_Term"> <blockTable colWidths="530.0" style="Table_Coment_Payment_Term">
<tr> <tr>
<td> <td>
<para style="terp_default_9">[[ format(o.comment or removeParentNode('blockTable')) ]]</para> <para style="terp_default_9">[[ format(o.comment) or removeParentNode('blockTable') ]]</para>
</td> </td>
</tr> </tr>
</blockTable> </blockTable>
@ -551,7 +551,7 @@
<blockTable colWidths="530.0" style="Table_Payment_Terms"> <blockTable colWidths="530.0" style="Table_Payment_Terms">
<tr> <tr>
<td> <td>
<para style="terp_default_9">[[ format((o.payment_term and o.payment_term.note) or removeParentNode('blockTable')) ]]</para> <para style="terp_default_9">[[ format(o.payment_term and o.payment_term.note) or removeParentNode('blockTable') ]]</para>
</td> </td>
</tr> </tr>
</blockTable> </blockTable>

View File

@ -51,18 +51,19 @@ def _data_load(self, cr, uid, data, context):
def _data_save(self, cr, uid, data, context): def _data_save(self, cr, uid, data, context):
if not data['form']['sure']: if not data['form']['sure']:
raise wizard.except_wizard(_('UserError'), _('Closing of fiscal year canceled, please check the box !')) raise wizard.except_wizard(_('UserError'), _('Closing of fiscal year cancelled, please check the box !'))
pool = pooler.get_pool(cr.dbname) pool = pooler.get_pool(cr.dbname)
fy_id = data['form']['fy_id'] fy_id = data['form']['fy_id']
new_fyear = pool.get('account.fiscalyear').browse(cr, uid, data['form']['fy2_id'])
start_jp = new_fyear.start_journal_period_id
if data['form']['report_new']: if data['form']['report_new']:
periods_fy2 = pool.get('account.fiscalyear').browse(cr, uid, data['form']['fy2_id']).period_ids periods_fy2 = pool.get('account.fiscalyear').browse(cr, uid, data['form']['fy2_id']).period_ids
if not periods_fy2: if not periods_fy2:
raise wizard.except_wizard(_('UserError'), raise wizard.except_wizard(_('UserError'),
_('There are no periods defined on New Fiscal Year.')) _('There are no periods defined on New Fiscal Year.'))
period=periods_fy2[0] period=periods_fy2[0]
new_fyear = pool.get('account.fiscalyear').browse(cr, uid, data['form']['fy2_id'])
start_jp = new_fyear.start_journal_period_id
if not start_jp: if not start_jp:
raise wizard.except_wizard(_('UserError'), raise wizard.except_wizard(_('UserError'),
_('The new fiscal year should have a journal for new entries define on it')) _('The new fiscal year should have a journal for new entries define on it'))
@ -98,7 +99,7 @@ def _data_save(self, cr, uid, data, context):
'period_id': period.id, 'period_id': period.id,
'account_id': account.id 'account_id': account.id
}, {'journal_id': new_journal.id, 'period_id':period.id}) }, {'journal_id': new_journal.id, 'period_id':period.id})
if accnt_type_data.close_method=='unreconciled': if accnt_type_data.close_method == 'unreconciled':
offset = 0 offset = 0
limit = 100 limit = 100
while True: while True:
@ -162,8 +163,8 @@ def _data_save(self, cr, uid, data, context):
cr.execute('UPDATE account_period SET state = %s ' \ cr.execute('UPDATE account_period SET state = %s ' \
'WHERE fiscalyear_id = %s', ('done',fy_id)) 'WHERE fiscalyear_id = %s', ('done',fy_id))
cr.execute('UPDATE account_fiscalyear ' \ cr.execute('UPDATE account_fiscalyear ' \
'SET state = %s, end_journal_period_id = %s' \ 'SET state = %s, end_journal_period_id = %s ' \
'WHERE id = %s', ('done',start_jp.id,fy_id)) 'WHERE id = %s', ('done', start_jp and start_jp.id or None, fy_id))
return {} return {}
class wiz_journal_close(wizard.interface): class wiz_journal_close(wizard.interface):

View File

@ -287,11 +287,11 @@
</td> </td>
</tr> </tr>
</blockTable> </blockTable>
<para style="P19">[[ format(o.comment or '') ]]</para> <para style="P19">[[ format(o.comment) or '' ]]</para>
<para style="P19"> <para style="P19">
<font color="white"> </font> <font color="white"> </font>
</para> </para>
<para style="P19">[[ format((o.payment_term and o.payment_term.note) or '') ]]</para> <para style="P19">[[ format(o.payment_term and o.payment_term.note) or '' ]]</para>
</story> </story>
</document> </document>

View File

@ -287,11 +287,11 @@
</td> </td>
</tr> </tr>
</blockTable> </blockTable>
<para style="P19">[[ format(o.comment or '') ]]</para> <para style="P19">[[ format(o.comment) or '' ]]</para>
<para style="P19"> <para style="P19">
<font color="white"> </font> <font color="white"> </font>
</para> </para>
<para style="P19">[[ format((o.payment_term and o.payment_term.note) or '') ]]</para> <para style="P19">[[ format(o.payment_term and o.payment_term.note) or '' ]]</para>
<section> <section>
<para style="P19">[[ repeatIn((spcl_msg(data['form']) and spcl_msg(data['form']).splitlines()) or [], 'note') ]]</para> <para style="P19">[[ repeatIn((spcl_msg(data['form']) and spcl_msg(data['form']).splitlines()) or [], 'note') ]]</para>
<para style="P19">[[ note or removeParentNode('para') ]]</para> <para style="P19">[[ note or removeParentNode('para') ]]</para>

View File

@ -21,11 +21,12 @@
############################################################################## ##############################################################################
import pooler import pooler
import os import os
import osv
from tools import config from tools import config
class abstract_quality_check(object): class abstract_quality_check(object):
''' '''
This Class provide... This Class provides...
''' '''
def __init__(self): def __init__(self):
@ -40,6 +41,9 @@ class abstract_quality_check(object):
#This char have to store the name of the test. #This char have to store the name of the test.
self.name = "" self.name = ""
#This char have to store the aim of the test and eventually a note.
self.note = ""
#This char have to store the result. #This char have to store the result.
#Used to display the result of the test. #Used to display the result of the test.
self.result = "" self.result = ""
@ -77,7 +81,8 @@ class abstract_quality_check(object):
''' '''
this method should do the test and fill the score, result and result_details var this method should do the test and fill the score, result and result_details var
''' '''
raise 'Not Implemented'
raise osv.except_osv(_('Programming Error'), _('Test Is Not Implemented'))
def get_objects(self, cr, uid, module): def get_objects(self, cr, uid, module):
# This function returns all object of the given module.. # This function returns all object of the given module..
@ -103,14 +108,12 @@ class abstract_quality_check(object):
def format_table(self, header=[], data_list=[]): def format_table(self, header=[], data_list=[]):
detail = "" detail = ""
header_list = [] detail += (header[0]) % tuple(header[1])
final_list = [] frow = '\n|-'
for head in data_list[1]: for i in header[1]:
header_list.append(head) frow += '\n| %s'
detail += (header[0]) % tuple(header_list) for key, value in data_list.items():
for res in data_list[0]: detail += (frow) % tuple(value)
data_list[0][res].append(res)
detail += (header[1]) % tuple(data_list[0][res])
detail = detail + '\n|}' detail = detail + '\n|}'
return detail return detail

View File

@ -21,8 +21,8 @@
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Result"> <form string="Result">
<field name="name" nolabel="1" readonly="1"/> <field name="name" readonly="1" search="1"/>
<field name="final_score" nolabel="1" readonly="1"/> <field name="final_score" readonly="1" search="1"/>
<separator colspan="4" string="Tests"/> <separator colspan="4" string="Tests"/>
<field name="test_ids" nolabel="1" colspan="4" height="350" width="800" readonly="1"/> <field name="test_ids" nolabel="1" colspan="4" height="350" width="800" readonly="1"/>
</form> </form>
@ -38,8 +38,11 @@
<page string="Summary"> <page string="Summary">
<field name="name" readonly="1"/> <field name="name" readonly="1"/>
<field name="score" readonly="1"/> <field name="score" readonly="1"/>
<field name="ponderation" readonly="1"/> <field name="note" readonly="1" colspan="4"/>
<field name="summary" widget="text_wiki" nolabel="1" colspan="4" height="350" width="800" readonly="1"/> <field name="summary" widget="text_wiki" nolabel="1" colspan="4" height="350" width="800" readonly="1"/>
<field name="ponderation" readonly="1"/>
<field name="state" readonly="1"/>
</page> </page>
<page string="Detail"> <page string="Detail">
<field name="detail" widget="text_wiki" nolabel="1" colspan="4" readonly="1"/> <field name="detail" widget="text_wiki" nolabel="1" colspan="4" readonly="1"/>
@ -55,8 +58,9 @@
<field name="type">tree</field> <field name="type">tree</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="Result"> <tree string="Result">
<field name="name"/> <field name="name" required="1"/>
<field name="score"/> <field name="state"/>
<field name="score" required="1"/>
<field name="ponderation"/> <field name="ponderation"/>
</tree> </tree>
</field> </field>

View File

@ -32,10 +32,11 @@ class quality_test(base_module_quality.abstract_quality_check):
def __init__(self): def __init__(self):
super(quality_test, self).__init__() super(quality_test, self).__init__()
self.name = _("Method Test") self.name = _("Method Test")
self.note = _("""
This test checks if the module classes are raising exception when calling basic methods or not.
""")
self.bool_installed_only = True self.bool_installed_only = True
self.ponderation = 1.0 self.ponderation = 1.0
self.result_det = {}
self.data_list = []
return None return None
def run_test(self, cr, uid, module_path): def run_test(self, cr, uid, module_path):
@ -44,51 +45,41 @@ class quality_test(base_module_quality.abstract_quality_check):
obj_list = self.get_objects(cr, uid, module_name) obj_list = self.get_objects(cr, uid, module_name)
ok_count = 0 ok_count = 0
ex_count = 0 ex_count = 0
result_dict = {}
for obj in obj_list: for obj in obj_list:
temp = [] temp = [obj]
try: try:
res = pool.get(obj).search(cr, uid, []) res = pool.get(obj).search(cr, uid, [])
temp.append('Ok') temp.append(_('Ok'))
ok_count += 1 ok_count += 1
except: except:
temp.append('Exception') temp.append(_('Exception'))
ex_count += 1 ex_count += 1
try: try:
res1 = pool.get(obj).fields_view_get(cr, uid,) res1 = pool.get(obj).fields_view_get(cr, uid,)
temp.append('Ok') temp.append(_('Ok'))
ok_count += 1 ok_count += 1
except: except:
temp.append('Exception') temp.append(_('Exception'))
ex_count += 1 ex_count += 1
try: try:
res2 = pool.get(obj).read(cr, uid, []) res2 = pool.get(obj).read(cr, uid, [])
temp.append('Ok') temp.append(_('Ok'))
ok_count += 1 ok_count += 1
except: except:
temp.append('Exception') temp.append(_('Exception'))
ex_count += 1 ex_count += 1
self.result_det[obj] = temp result_dict[obj] = temp
self.data_list.append(self.result_det)
self.score = (ok_count + ex_count) and float(ok_count)/float(ok_count + ex_count) or 0.0 self.score = (ok_count + ex_count) and float(ok_count)/float(ok_count + ex_count) or 0.0
self.result = self.get_result() self.result = self.get_result(result_dict)
self.result_details = self.get_result_details()
return None return None
def get_result(self):
summary = """
This test checks if the module classes are raising exception when calling basic methods or no.
"""
return summary
def get_result_details(self): def get_result(self, dict):
header_list = [] header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-16s \n! %-20s \n! %-16s ', [_('Object Name'), 'search()', 'fields_view_get()', 'read()'])
header_list.append('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-16s \n! %-20s \n! %-16s ')
header_list.append('\n|-\n| %s \n| %s \n| %s \n| %s ')
header_view = ['Object Name', 'search()', 'fields_view_get', 'read']
self.data_list.append(header_view)
detail = "" detail = ""
if not self.error: if not self.error:
detail += self.format_table(header=header_list, data_list=self.data_list) detail += self.format_table(header, dict)
return detail return detail
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -32,6 +32,7 @@ class quality_test(base_module_quality.abstract_quality_check):
def __init__(self): def __init__(self):
super(quality_test, self).__init__() super(quality_test, self).__init__()
self.name = _("Pylint Test") self.name = _("Pylint Test")
self.note = _("""This test uses Pylint and checks if the module satisfies the coding standard of Python. See http://www.logilab.org/project/name/pylint for further info.\n """)
self.bool_installed_only = False self.bool_installed_only = False
self.ponderation = 1.0 self.ponderation = 1.0
return None return None
@ -47,7 +48,8 @@ class quality_test(base_module_quality.abstract_quality_check):
n = 0 n = 0
score = 0.0 score = 0.0
self.result += "\nThis test checks if the module satisfies the current coding standard used by OpenERP. \n\n" dict = {}
self.result_details += '<nowiki>'
for file in list_files: for file in list_files:
if file.split('.')[-1] == 'py' and not file.endswith('__init__.py') and not file.endswith('__terp__.py'): if file.split('.')[-1] == 'py' and not file.endswith('__init__.py') and not file.endswith('__terp__.py'):
file_path = os.path.join(module_path, file) file_path = os.path.join(module_path, file)
@ -65,36 +67,24 @@ class quality_test(base_module_quality.abstract_quality_check):
rightchar += 1 rightchar += 1
try: try:
score += float(res[leftchar+1:rightchar]) score += float(res[leftchar+1:rightchar])
self.result += file + ": " + res[leftchar+1:rightchar] + "/10\n" #self.result += file + ": " + res[leftchar+1:rightchar] + "/10\n"
dict[file] = [file, res[leftchar+1:rightchar]]
except: except:
score += 0 score += 0
self.result += file + ": "+_("Unable to parse the result. Check the details.")+"\n" #self.result += file + ": "+_("Unable to parse the result. Check the details.")+"\n"
dict[file] = [file, _("Unable to parse the result. Check the details.")]
self.result_details += res self.result_details += res
self.result_details += '</nowiki>'
average_score = n and score / n or score average_score = n and score / n or score
self.score = (average_score + 10) /20 self.score = (max(average_score,0)) / 10
self.result = self.get_result(dict)
return None return None
def get_result(self, cr, uid, module_path): def get_result(self, dict):
self.run_test(cr, uid, module_path) header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-10s \n', [_('File Name'), _('Result (/10)'),])
if not self.bool_installed_only or module_state=="installed": if not self.error:
summary =""" return self.format_table(header, data_list=dict)
===Pylint Test===: return ""
This test checks if the module satisfies the current coding standard used by OpenERP.
""" + "Score: " + str(self.score) + "/10\n"
else:
summary =""" \n===Pylint Test===:
The module has to be installed before running this test.\n\n """
header_list = ""
self.error = True
return summary
def get_result_details(self):
detail = "\n===Pylint Test===\n" + self.result
return detail
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -35,12 +35,15 @@ class quality_test(base_module_quality.abstract_quality_check):
def __init__(self): def __init__(self):
super(quality_test, self).__init__() super(quality_test, self).__init__()
self.name = _("Speed Test")
self.bool_installed_only = True self.bool_installed_only = True
self.ponderation = 1.0 self.ponderation = 1.0
self.result_det = {} self.name = _("Speed Test")
self.data_list = [] self.note = _("""
This test checks the speed of the module. Note that at least 5 demo data is needed in order to run it.
""")
return None return None
def run_test(self, cr, uid, module_path): def run_test(self, cr, uid, module_path):
pool = pooler.get_pool(cr.dbname) pool = pooler.get_pool(cr.dbname)
module_name = module_path.split('/')[-1] module_name = module_path.split('/')[-1]
@ -48,66 +51,69 @@ class quality_test(base_module_quality.abstract_quality_check):
obj_counter = 0 obj_counter = 0
score = 0 score = 0
obj_ids = self.get_ids(cr, uid, obj_list) obj_ids = self.get_ids(cr, uid, obj_list)
result_dict = {}
result_dict2 = {}
self.result_details += _("O(1) means that the number of SQL requests to read the object does not depand on the number of objects we are reading. This feature is hardly wished.\n")
for obj in obj_ids: for obj in obj_ids:
obj_counter += 1 obj_counter += 1
ids = obj_ids[obj] ids = obj_ids[obj]
ids = ids[:100] ids = ids[:100]
size = len(ids) size = len(ids)
if size: if size:
c1 = cr.count list = []
#we perform the operation twice, and count the number of queries in the second run. This allows to avoid the cache effect. (like translated terms that asks for more queries)
pool.get(obj).read(cr, uid, [ids[0]]) pool.get(obj).read(cr, uid, [ids[0]])
c = cr.count
pool.get(obj).read(cr, uid, [ids[0]]) pool.get(obj).read(cr, uid, [ids[0]])
code_base_complexity = cr.count - c1 code_base_complexity = cr.count - c
pool.get(obj).read(cr, uid, ids[:size/2]) pool.get(obj).read(cr, uid, ids[:size/2])
c = cr.count
pool.get(obj).read(cr, uid, ids[:size/2]) pool.get(obj).read(cr, uid, ids[:size/2])
code_half_complexity = cr.count - c1 code_half_complexity = cr.count - c
pool.get(obj).read(cr, uid, ids) pool.get(obj).read(cr, uid, ids)
c = cr.count
pool.get(obj).read(cr, uid, ids) pool.get(obj).read(cr, uid, ids)
code_size_complexity = cr.count - c1 code_size_complexity = cr.count - c
if size < 5: if size < 5:
self.score += -2 list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Warning! Not enough demo data")]
list = [size, code_base_complexity, code_half_complexity, code_size_complexity, "Warning! Not enough demo data"]
self.result_det[obj] = list
else: else:
if code_size_complexity <= (code_base_complexity + size): if code_size_complexity <= (code_base_complexity + size):
complexity = "O(1)" complexity = _("O(1)")
score = 10 score += 1
list2 = [obj, _("Efficient")]
else: else:
complexity = "O(n) or worst" complexity = _("O(n) or worst")
score = 0 list2 = [obj, _("Not Efficient")]
list = [size, code_base_complexity, code_half_complexity, code_size_complexity, complexity]
self.result_det[obj] = list list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, complexity]
else: else:
score += -5 list = [obj, size, "", "", "", _("Warning! Object has no demo data")]
list = [size, "", "", "", "Warning! Object has no demo data"] list2 = [obj, _("No demo data")]
self.result_det[obj] = list result_dict[obj] = list
self.data_list.append(self.result_det) result_dict2[obj] = list2
self.score = obj_counter and score/obj_counter or 0.0
self.result = self.get_result() self.score = obj_counter and score / obj_counter or 0.0
self.result_details = self.get_result_details() self.result_details += self.get_result_details(result_dict)
self.result += self.get_result(result_dict2)
return None return None
def get_result(self): def get_result(self, dict):
summary = """ header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-10s \n', [_('Object Name'), _('Result'),])
This test checks the speed of the module.
"""
return summary
def get_result_details(self):
header_list = []
header_list.append('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-10s \n! %-10s \n! %-10s \n! %-10s \n! %-20s')
header_list.append('\n|-\n| %s \n| %s \n| %s \n| %s \n| %s \n| %s ')
header_view = ['Object Name', 'Size-Number of Records (S)', '1', 'S/2', 'S', 'Complexity using query']
detail = ""
self.data_list.append(header_view)
if not self.error: if not self.error:
detail += self.format_table(header=header_list, data_list=self.data_list) return self.format_table(header, data_list=dict)
return detail return ""
def get_result_details(self, dict):
header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-10s \n! %-10s \n! %-10s \n! %-10s \n! %-20s', [_('Object Name'), _('N (Number of Records)'), _('1'), _('N/2'), _('N'), _('Reading Complexity')])
if not self.error:
return self.format_table(header, data_list=dict)
return ""
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:

View File

@ -35,14 +35,18 @@ class quality_test(base_module_quality.abstract_quality_check):
# ''' # '''
super(quality_test, self).__init__() super(quality_test, self).__init__()
self.name = _("Terp Test") self.name = _("Terp Test")
self.note = _("This test checks if the module satisfies the current coding standard used by OpenERP.")
self.bool_installed_only = False self.bool_installed_only = False
self.no_terp = False self.no_terp = False
self.ponderation = 2 self.ponderation = 2
return None return None
def run_test(self, cr, uid, module_path): def run_test_terp(self, cr, uid, module_path):
list_files = os.listdir(module_path) list_files = os.listdir(module_path)
current_module = module_path.split('/')[-1]
for i in list_files: for i in list_files:
path = os.path.join(module_path, i) path = os.path.join(module_path, i)
if os.path.isdir(path): if os.path.isdir(path):
@ -55,53 +59,81 @@ class quality_test(base_module_quality.abstract_quality_check):
feel_bad_factor = 0 feel_bad_factor = 0
if '__terp__.py' not in list_files: if '__terp__.py' not in list_files:
self.no_terp = True self.no_terp = True
if self.no_terp: self.result += _("The module does not contain the __terp__.py file")
self.result += "The module does not contain the __terp__.py file" return None
terp_file = os.path.join(module_path,'__terp__.py') terp_file = os.path.join(module_path,'__terp__.py')
res = eval(tools.file_open(terp_file).read()) res = eval(tools.file_open(terp_file).read())
terp_keys = ['category', 'name', 'description', 'author', 'website', 'update_xml', 'init_xml', 'depends', 'version', 'active', 'installable', 'demo_xml'] terp_keys = ['category', 'name', 'description', 'author', 'website', 'update_xml', 'init_xml', 'depends', 'version', 'active', 'installable', 'demo_xml', 'certificate']
for key in terp_keys: for key in terp_keys:
if key in res: if key in res:
feel_good_factor += 1 feel_good_factor += 1 # each tag should appear
if isinstance(res[key],(str,unicode)): if isinstance(res[key],(str,unicode)):
if not res[key]: if not res[key]:
feel_bad_factor += 1 feel_bad_factor += 1
else: else:
if key == 'description' and res[key] and len(str(res[key]))>=25:
if key == 'description' and res[key] and len(str(res[key])) >= 150: # no. of chars should be >=150
feel_good_factor += 1 feel_good_factor += 1
if res['description'].count('\n') >= 4:# description contains minimum 5 lines if res['description'].count('\n') >= 4:# description contains minimum 5 lines
feel_good_factor += 1 feel_good_factor += 1
if key == 'website': if key == 'website':
ptrn = re.compile('https?://[\w\.]*') # reg ex matching on temporary basis. ptrn = re.compile('https?://[\w\.]*') # reg ex matching on temporary basis.Website is correctly formatted
result = ptrn.search(str(res[key])) result = ptrn.search(str(res[key]))
if result: if result:
feel_good_factor += 1 feel_good_factor += 1
else:
feel_bad_factor += 1
if isinstance(res[key],bool):
if key == 'active':
if current_module != 'base':
if res[key]:
feel_bad_factor += 1
else:
if not res[key]:
feel_bad_factor += 1
if key == 'installable' and not res[key]: # installable tag is provided and True
feel_bad_factor +=1
else: else:
feel_bad_factor += 1 feel_bad_factor += 1
self.score = round((feel_good_factor) / float(feel_good_factor + feel_bad_factor),2) score = round((feel_good_factor) / float(feel_good_factor + feel_bad_factor),2)
self.result += "\nThis test checks if the module satisfies the current coding standard for __terp__.py file used by OpenERP."
# self.result += "__terp__.py : "+ str(self.score) + "/10\n" # self.result += "__terp__.py : "+ str(self.score) + "/10\n"
return [_('__terp__.py file'), score]
def run_test(self, cr, uid, module_path):
terp_score = self.run_test_terp(cr, uid, module_path)
self.score = terp_score[1]
self.result = self.get_result({'__terp__.py': terp_score})
return None return None
def get_result(self, cr, uid, module_path, module_state): def get_result(self, dict):
# self.run_test(cr, uid, module_path) header = ('{| border="1" cellspacing="0" cellpadding="5" align="left" \n! %-40s \n! %-10s \n', [_('Object Name'), _('Result (/1)'),])
# summary = "\n===TERP Test===:\n" if not self.error:
if self.no_terp: return self.format_table(header, data_list=dict)
summary += """ return ""
The module does not contain the __terp__.py file.\n\n """
# else:
# summary += """
# This test checks if the module satisfies the current coding standard for __terp__.py file used by OpenERP.
# """ + "Score: " + str(self.score) + "/10\n"
return summary
def get_result_details(self): #~ def get_result(self, cr, uid, module_path, module_state):
detail = "\n===TERP Test===\n" + self.result #~ # self.run_test(cr, uid, module_path)
return detail #~ # summary = "\n===TERP Test===:\n"
#~ if self.no_terp:
#~ summary += """
#~ The module does not contain the __terp__.py file.\n\n """
#~ # else:
#~ # summary += """
#~ # This test checks if the module satisfies the current coding standard for __terp__.py file used by OpenERP.
#~ # """ + "Score: " + str(self.score) + "/10\n"
#~ return summary
#~ def get_result_details(self):
#~ detail = "\n===TERP Test===\n" + self.result
#~ return detail

View File

@ -35,8 +35,8 @@ class wiz_quality_check(osv.osv):
_name = 'wizard.quality.check' _name = 'wizard.quality.check'
_columns = { _columns = {
'name': fields.char('Rated Module', size=64, ), 'name': fields.char('Rated Module', size=64, ),
'final_score': fields.char('Final Score', size=10,), 'final_score': fields.char('Final Score (%)', size=10,),
'test_ids' : fields.one2many('quality.check.detail', 'quality_check_id', 'Test Details',) 'test_ids' : fields.one2many('quality.check.detail', 'quality_check_id', 'Tests',)
} }
wiz_quality_check() wiz_quality_check()
@ -46,10 +46,12 @@ class quality_check_detail(osv.osv):
_columns = { _columns = {
'quality_check_id': fields.many2one('wizard.quality.check', 'Quality'), 'quality_check_id': fields.many2one('wizard.quality.check', 'Quality'),
'name': fields.char('Name',size=128,), 'name': fields.char('Name',size=128,),
'score': fields.float('Score',), 'score': fields.float('Score (%)',),
'ponderation': fields.float('Ponderation',), 'ponderation': fields.float('Ponderation',help='Some tests are more critical than others, so they have a bigger weight in the computation of final rating'),
'note': fields.text('Note',),
'summary': fields.text('Summary',), 'summary': fields.text('Summary',),
'detail' : fields.text('Details',), 'detail' : fields.text('Details',),
'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.'),
} }
quality_check_detail() quality_check_detail()
@ -58,8 +60,10 @@ class create_quality_check(wizard.interface):
def _create_quality_check(self, cr, uid, data, context={}): def _create_quality_check(self, cr, uid, data, context={}):
pool = pooler.get_pool(cr.dbname) pool = pooler.get_pool(cr.dbname)
if data['id']: print data, context
module_data = pool.get('ir.module.module').browse(cr, uid, [data['id']])[0] objs = []
for id in data['ids']:
module_data = pool.get('ir.module.module').browse(cr, uid, id)
#list_folders = os.listdir(config['addons_path']+'/base_module_quality/') #list_folders = os.listdir(config['addons_path']+'/base_module_quality/')
abstract_obj = base_module_quality.abstract_quality_check() abstract_obj = base_module_quality.abstract_quality_check()
score_sum = 0.0 score_sum = 0.0
@ -76,10 +80,12 @@ class create_quality_check(wizard.interface):
val.run_test(cr, uid, str(module_path)) val.run_test(cr, uid, str(module_path))
data = { data = {
'name': val.name, 'name': val.name,
'score': val.score, 'score': val.score * 100,
'ponderation': val.ponderation, 'ponderation': val.ponderation,
'summary': val.result, 'summary': val.result,
'detail': val.result_details, 'detail': val.result_details,
'state': 'done',
'note': val.note,
} }
create_ids.append((0,0,data)) create_ids.append((0,0,data))
score_sum += val.score * val.ponderation score_sum += val.score * val.ponderation
@ -87,7 +93,9 @@ class create_quality_check(wizard.interface):
else: else:
data = { data = {
'name': val.name, 'name': val.name,
'note': val.note,
'score': 0, 'score': 0,
'state': 'skipped',
'summary': _("The module has to be installed before running this test.") 'summary': _("The module has to be installed before running this test.")
} }
create_ids.append((0,0,data)) create_ids.append((0,0,data))
@ -99,12 +107,13 @@ class create_quality_check(wizard.interface):
'test_ids' : create_ids, 'test_ids' : create_ids,
} }
obj = pool.get('wizard.quality.check').create(cr, uid, data, context) obj = pool.get('wizard.quality.check').create(cr, uid, data, context)
return obj objs.append(obj)
return objs
def _open_quality_check(self, cr, uid, data, context): def _open_quality_check(self, cr, uid, data, context):
obj_id = self._create_quality_check(cr, uid, data, context) obj_ids = self._create_quality_check(cr, uid, data, context)
return { return {
'domain': "[('id','=', "+ str(obj_id)+")]", 'domain': "[('id','in', ["+','.join(map(str,obj_ids))+"])]",
'name': _('Quality Check'), 'name': _('Quality Check'),
'view_type': 'form', 'view_type': 'form',
'view_mode': 'tree,form', 'view_mode': 'tree,form',

View File

@ -395,7 +395,7 @@
<blockTable colWidths="534.0" style="Table8"> <blockTable colWidths="534.0" style="Table8">
<tr> <tr>
<td> <td>
<para style="P3">[[ format(o.quotation_notes or '') ]]</para> <para style="P3">[[ format(o.quotation_notes) or '' ]]</para>
</td> </td>
</tr> </tr>
</blockTable> </blockTable>

View File

@ -174,7 +174,7 @@ product_ul()
#---------------------------------------------------------- #----------------------------------------------------------
class product_category(osv.osv): class product_category(osv.osv):
def name_get(self, cr, uid, ids, context={}): def name_get(self, cr, uid, ids, context=None):
if not len(ids): if not len(ids):
return [] return []
reads = self.read(cr, uid, ids, ['name','parent_id'], context) reads = self.read(cr, uid, ids, ['name','parent_id'], context)
@ -187,7 +187,7 @@ class product_category(osv.osv):
return res return res
def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context): def _name_get_fnc(self, cr, uid, ids, prop, unknow_none, context):
res = self.name_get(cr, uid, ids) res = self.name_get(cr, uid, ids, context)
return dict(res) return dict(res)
_name = "product.category" _name = "product.category"