bzr revid: fp@tinyerp.com-20090427171844-sv7caeq5igf7ci6d
This commit is contained in:
Fabien Pinckaers
2009-04-27 19:18:44 +02:00
13 changed files with 154 additions and 78 deletions
+3 -2
View File
@@ -366,8 +366,9 @@ class account_move_line(osv.osv):
'centralisation': fields.selection([('normal','Normal'),('credit','Credit Centralisation'),('debit','Debit Centralisation')], 'Centralisation', size=6),
'balance': fields.function(_balance, method=True, string='Balance'),
'state': fields.selection([('draft','Draft'), ('valid','Valid')], 'Status', readonly=True),
'tax_code_id': fields.many2one('account.tax.code', 'Tax Account'),
'tax_amount': fields.float('Tax/Base Amount', digits=(16,2), select=True),
'tax_code_id': fields.many2one('account.tax.code', 'Tax Account', help="The Account can either be a base tax code or tax code account."),
'tax_amount': fields.float('Tax/Base Amount', digits=(16,2), select=True, help="If the Tax account is tax code account, this field will contain the taxed amount.If the tax account is base tax code,\
this field will contain the basic amount(without tax)."),
'invoice': fields.function(_invoice, method=True, string='Invoice',
type='many2one', relation='account.invoice', fnct_search=_invoice_search),
'account_tax_id':fields.many2one('account.tax', 'Tax'),
+1
View File
@@ -113,6 +113,7 @@ class res_partner(osv.osv):
for id in ids:
res[id] = {}.fromkeys(field_names, 0)
for pid,type,val in cr.fetchall():
if val is None: val=0
res[pid][maps[type]] = (type=='receivable') and val or -val
return res
-5
View File
@@ -64,15 +64,10 @@ class partner_balance(report_sxw.rml_parse):
full_str_date.append(str(date))
return full_str_date
#
def transform_period_into_date_array(self,data):
## Get All Period Date
#
# If we have no period we will take all perdio in the FiscalYear.
if not data['form']['periods'][0][2] :
periods_id = self.pool.get('account.period').search(self.cr, self.uid, [('fiscalyear_id','=',data['form']['fiscalyear'])])
else:
+5 -2
View File
@@ -208,8 +208,11 @@ class crossovered_budget_lines(osv.osv):
elapsed = min(strToDate(line.date_to),strToDate(date_to)) - max(strToDate(line.date_from),strToDate(date_from))
if strToDate(date_to) < strToDate(line.date_from):
elapsed = strToDate(date_to) - strToDate(date_to)
theo_amt=float(elapsed.days/float(total.days))*line.planned_amount
if total.days:
theo_amt = float(elapsed.days/float(total.days))*line.planned_amount
else:
theo_amt = line.planned_amount
res[line.id]=theo_amt
return res
@@ -2,3 +2,5 @@
"access_analytic_user_funct_user","analytic user funct user","model_analytic_user_funct_grid","account.group_account_manager",1,0,0,0
"access_analytic_user_funct_manager","analytic user funct manager","model_analytic_user_funct_grid","account.group_account_manager",1,1,1,1
"access_analytic_user_funct_account_manager","analytic user funct account manager","model_analytic_user_funct_grid","account.group_account_manager",1,1,1,1
"access_analytic_user_funct_grid_hr_user","analytic user funct grid hr user","model_analytic_user_funct_grid","hr.group_hr_user",1,0,0,0
"access_analytic_user_funct_grid_hr_manager","analytic user funct grid hr manager","model_analytic_user_funct_grid","hr.group_hr_manager",1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_analytic_user_funct_user analytic user funct user model_analytic_user_funct_grid account.group_account_manager 1 0 0 0
3 access_analytic_user_funct_manager analytic user funct manager model_analytic_user_funct_grid account.group_account_manager 1 1 1 1
4 access_analytic_user_funct_account_manager analytic user funct account manager model_analytic_user_funct_grid account.group_account_manager 1 1 1 1
5 access_analytic_user_funct_grid_hr_user analytic user funct grid hr user model_analytic_user_funct_grid hr.group_hr_user 1 0 0 0
6 access_analytic_user_funct_grid_hr_manager analytic user funct grid hr manager model_analytic_user_funct_grid hr.group_hr_manager 1 1 1 1
@@ -229,7 +229,13 @@ class report_creator(osv.osv):
filter_list.append(' ')
filter_list.append(filter_id.condition)
ret_str = ",\n".join(from_list)
if len(from_list) == 1 and filter_ids:
from_list.append(' ')
ret_str = "\n where \n".join(from_list)
else:
ret_str = ",\n".join(from_list)
if where_list:
ret_str+="\n where \n"+" and\n".join(where_list)
ret_str = ret_str.strip()
@@ -261,23 +267,28 @@ class report_creator(osv.osv):
fields.append('\t'+f.group_method+'('+t+'.'+f.field_id.name+')'+' as field'+str(i))
i+=1
models = self._path_get(cr, uid, obj.model_ids, obj.filter_ids)
check=self._id_get(cr, uid, ids[0], context)
check = self._id_get(cr, uid, ids[0], context)
if check<>False:
fields.insert(0,(check+' as id'))
result[obj.id] = """select
%s
from
%s
""" % (',\n'.join(fields), models)
if groupby:
result[obj.id] += "group by\n\t"+', '.join(groupby)
if where_plus:
result[obj.id] += "\nhaving \n\t"+"\n\t and ".join(where_plus)
if limit:
result[obj.id] += " limit "+str(limit)
if offset:
result[obj.id] += " offset "+str(offset)
if models:
result[obj.id] = """select
%s
from
%s
""" % (',\n'.join(fields), models)
if groupby:
result[obj.id] += "group by\n\t"+', '.join(groupby)
if where_plus:
result[obj.id] += "\nhaving \n\t"+"\n\t and ".join(where_plus)
if limit:
result[obj.id] += " limit "+str(limit)
if offset:
result[obj.id] += " offset "+str(offset)
else:
result[obj.id] = False
return result
_columns = {
'name': fields.char('Report Name',size=64, required=True),
'type': fields.selection([('list','Rows And Columns Report'),], 'Report Type',required=True),#('sum','Summation Report')
@@ -122,20 +122,25 @@ def _set_filter_value(self, cr, uid, data, context):
model_pool = pooler.get_pool(cr.dbname).get(model_name)
table_name = model_pool._table
model_name = model_pool._description
if field_type == 'boolean' and value_data == 1:
value_data = 'true'
else:
value_data = 'false'
if field_type:
if field_type == 'many2many' and value_data and len(value_data):
fields_list = set_field_operator(self,table_name+"."+field_data['name'],field_data['ttype'],form_data['operator'],value_data[0][2])
else:
fields_list = set_field_operator(self,table_name+"."+field_data['name'],field_data['ttype'],form_data['operator'],value_data)
if fields_list and value_data:
create_dict = {
'name':model_name + "/" +field_data['field_description'] +" "+ mapping_fields[form_data['operator']] + " " + str(fields_list[2]),
'name':model_name + "/" +field_data['field_description'] +" "+ mapping_fields[form_data['operator']] + " " + str(fields_list[2]) + " ",
'expression':' '.join(fields_list),
'report_id':data['id'],
'condition' : form_data['condition']
}
pooler.get_pool(cr.dbname).get('base_report_creator.report.filter').create(cr,uid,create_dict)
#end if field_type == 'many2many' and value_data and len(value_data):
# pooler.get_pool(cr.dbname).get('custom.report.filter').create(cr,uid,form_data)
+15 -2
View File
@@ -28,6 +28,19 @@ import tempfile
#
# This should be the indexer
#
def _to_unicode(s):
try:
return s.decode('utf-8')
except UnicodeError:
try:
return s.decode('latin')
except UnicodeError:
try:
return s.encode('ascii')
except UnicodeError:
return s
def content_index(content, filename=None, content_type=None):
fname,ext = os.path.splitext(filename)
result = ''
@@ -35,7 +48,7 @@ def content_index(content, filename=None, content_type=None):
(stdin,stdout) = os.popen2('antiword -', 'b')
stdin.write(content)
stdin.close()
result = stdout.read().decode('latin1','replace').encode('utf-8','replace')
result = _to_unicode(stdout.read())
elif ext == '.pdf':
file_descriptor, file_name = tempfile.mkstemp(suffix=ext)
os.write(file_descriptor, content)
@@ -46,7 +59,7 @@ def content_index(content, filename=None, content_type=None):
elif ext in ('.xls','.ods','.odt','.odp'):
s = StringIO.StringIO(content)
o = odt2txt.OpenDocumentTextFile(s)
result = o.toString().encode('ascii','replace')
result = _to_unicode(o.toString())
s.close()
elif ext in ('.txt','.py','.patch','.html','.csv','.xml'):
result = content
@@ -23,6 +23,8 @@
import time
from report import report_sxw
import pooler
import datetime
class attendance_print(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
@@ -31,26 +33,33 @@ class attendance_print(report_sxw.rml_parse):
'time': time,
'lst': self._lst,
'total': self._lst_total,
'get_employees':self._get_employees,
})
def _sign(self, dt):
if abs(dt.days)>1:
format = '%d day'+(((abs(dt.days)>=2) and 's') or '')+' %H:%M:%S'
else:
format = '%H:%M:%S'
if dt.seconds<0:
return dt.strftime('- '+format)
else:
return dt.strftime(format)
def _get_employees(self, emp_ids):
emp_obj_list = self.pool.get('hr.employee').browse(self.cr,self.uid,emp_ids)
return emp_obj_list
# def _sign(self, dt):
# if abs(dt.days) > 1:
# format = '%d day'+(((abs(dt.days)>=2) and 's') or '')+' %H:%M:%S'
# else:
# format = '%H:%M:%S'
# if dt.seconds<0:
# return dt.strftime('- '+format)
# else:
# return dt.strftime(format)
def _lst(self, employee_id, dt_from, dt_to, max, *args):
self.cr.execute('select name as date, create_date, action, create_date-name as delay from hr_attendance where employee_id=%s and name<=%s and name>=%s and action in (%s,%s) order by name', (employee_id, dt_to, dt_from, 'sign_in', 'sign_out'))
self.cr.execute("select name as date, create_date, action, create_date-name as delay from hr_attendance where employee_id=%s and to_char(name,'YYYY-mm-dd')<=%s and to_char(name,'YYYY-mm-dd')>=%s and action in (%s,%s) order by name", (employee_id, dt_to, dt_from, 'sign_in', 'sign_out'))
res = self.cr.dictfetchall()
for r in res:
if r['action']=='sign_out':
r['delay'] = - r['delay']
if r['action'] == 'sign_out':
r['delay'] = -r['delay']
temp = r['delay'].seconds
r['delay'] = self._sign(r['delay'])
# r['delay'] = self._sign(r['delay'])
r['delay'] = str(r['delay']).split('.')[0]
if abs(temp) < max*60:
r['delay2'] = r['delay']
else:
@@ -58,21 +67,26 @@ class attendance_print(report_sxw.rml_parse):
return res
def _lst_total(self, employee_id, dt_from, dt_to, max, *args):
self.cr.execute('select name as date, create_date, action, create_date-name as delay from hr_attendance where employee_id=%s and name<=%s and name>=%s and action in (%s,%s)', (employee_id, dt_to, dt_from, 'sign_in', 'sign_out'))
self.cr.execute("select name as date, create_date, action, create_date-name as delay from hr_attendance where employee_id=%s and to_char(name,'YYYY-mm-dd')<=%s and to_char(name,'YYYY-mm-dd')>=%s and action in (%s,%s) order by name", (employee_id, dt_to, dt_from, 'sign_in', 'sign_out'))
res = self.cr.dictfetchall()
if not res:
return ('/','/')
total = 0
total2 = 0
total2 = datetime.timedelta(seconds = 0, minutes = 0, hours = 0)
total = datetime.timedelta(seconds = 0, minutes = 0, hours = 0)
for r in res:
if r['action']=='sign_out':
r['delay'] = - r['delay']
if r['action'] == 'sign_out':
r['delay'] = -r['delay']
total += r['delay']
if abs(r['delay'].seconds) < max*60:
total2 += r['delay']
return (self._sign(total),total2 and self._sign(total2))
result_dict = {
'total' : total and str(total).split('.')[0],
'total2' : total2 and str(total2).split('.')[0]
}
# return (self._sign(total),total2 and self._sign(total2))
return [result_dict]
report_sxw.report_sxw('report.hr.attendance.error', 'hr.employee', 'addons/hr_attendance/report/attendance_errors.rml',parser=attendance_print, header=2)
@@ -86,7 +86,7 @@
</stylesheet>
<images/>
<story>
<para style="terp_default_8">[[ repeatIn(objects,'employee') ]]</para>
<para style="terp_default_8">[[ repeatIn(get_employees(data['form']['emp_ids']),'employee') ]]</para>
<para style="terp_header_Centre">Attendance Errors</para>
<para style="P1">[[ employee.name ]]</para>
<para style="terp_default_8">
@@ -140,13 +140,13 @@
<blockTable colWidths="357.0,99.0,63.0" style="Table_employee_total">
<tr>
<td>
<para style="terp_default_Bold_9">Total period:</para>
<para style="terp_default_Bold_9">Total period:<font face="Times">[[ repeatIn(total(employee.id,data['form']['init_date'], data['form']['end_date'], data['form']['max_delay']),'total')]] </font></para>
</td>
<td>
<para style="terp_default_Centre_9_Bold">[[ total(employee.id,data['form']['init_date'], data['form']['end_date'], data['form']['max_delay'])[0] ]]</para>
<para style="terp_default_Centre_9_Bold">[[ total['total'] ]]</para>
</td>
<td>
<para style="terp_default_Centre_9_Bold">[[ total(employee.id,data['form']['init_date'], data['form']['end_date'], data['form']['max_delay'])[1] ]]</para>
<para style="terp_default_Centre_9_Bold">[[ total['total2'] ]]</para>
</td>
</tr>
</blockTable>
@@ -22,6 +22,7 @@
import wizard
import time
import pooler
_date_form = '''<?xml version="1.0"?>
<form string="Select a time span">
@@ -38,6 +39,27 @@ _date_fields = {
'max_delay': {'string':'Max. Delay (Min)', 'type':'integer', 'default':lambda *a: 120, 'required':True},
}
def _check_data(self, cr, uid, data, *args):
date_from = data['form']['init_date']
date_to = data['form']['end_date']
emp_ids = (','.join([str(x) for x in data['ids']]))
cr.execute("select id from hr_attendance where employee_id in (%s) and to_char(name,'YYYY-mm-dd')<='%s' and to_char(name,'YYYY-mm-dd')>='%s' and action in ('%s','%s') order by name" %(emp_ids, date_to, date_from, 'sign_in', 'sign_out'))
attendance_ids = [x[0] for x in cr.fetchall()]
if not attendance_ids:
raise wizard.except_wizard(_('No Data Available'), _('No records found for your selection!'))
attendance_records = pooler.get_pool(cr.dbname).get('hr.attendance').browse(cr,uid,attendance_ids)
emp_ids = []
for rec in attendance_records:
if rec.employee_id.id not in emp_ids:
emp_ids.append(rec.employee_id.id)
data['form']['emp_ids'] = emp_ids
return data['form']
class wiz_attendance(wizard.interface):
states = {
'init': {
@@ -45,7 +67,7 @@ class wiz_attendance(wizard.interface):
'result': {'type': 'form', 'arch':_date_form, 'fields':_date_fields, 'state':[('print','Print Attendance Report'),('end','Cancel') ]}
},
'print': {
'actions': [],
'actions': [_check_data],
'result': {'type': 'print', 'report': 'hr.attendance.error', 'state':'end'}
}
}
+21 -20
View File
@@ -25,6 +25,7 @@ import datetime
import pooler
import base64
from tools.translate import _
import tools
form = """<?xml version="1.0"?>
<form string="Select Fiscal Year">
@@ -32,7 +33,7 @@ form = """<?xml version="1.0"?>
<newline/>
<field name="fyear" />
<newline/>
<field name="mand_id" help="Should be provided when subcription of INTERVAT service is done"/>
<field name="mand_id" help="Should be provided when subscription of INTERVAT service is done"/>
<newline/>
<field name="limit_amount" help="Limit under which the partners will not be included into the listing"/>
<newline/>
@@ -73,7 +74,7 @@ class wizard_vat(wizard.interface):
cref = company_vat + seq_controlref
dnum = cref + seq_declarantnum
p_id_list=pooler.get_pool(cr.dbname).get('res.partner').search(cr,uid,[('vat_subjected','!=',False)])
p_id_list = pooler.get_pool(cr.dbname).get('res.partner').search(cr,uid,[('vat_subjected','!=',False)])
if not p_id_list:
raise wizard.except_wizard(_('Data Insufficient!'),_('No partner has a VAT Number asociated with him.'))
@@ -81,7 +82,7 @@ class wizard_vat(wizard.interface):
period_ids = pooler.get_pool(cr.dbname).get('account.period').search(cr, uid, [('fiscalyear_id', '=', data['form']['fyear'])])
period = "("+','.join(map(lambda x: str(x), period_ids)) +")"
street=zip_city=country=''
street = zip_city = country = ''
addr = pooler.get_pool(cr.dbname).get('res.partner').address_get(cr, uid, [obj_cmpny.partner_id.id], ['invoice'])
if addr.get('invoice',False):
ads=pooler.get_pool(cr.dbname).get('res.partner.address').browse(cr,uid,[addr['invoice']])[0]
@@ -90,24 +91,24 @@ class wizard_vat(wizard.interface):
if not zip_city:
zip_city = ''
if ads.street:
street=ads.street
street = ads.street
if ads.street2:
street +=ads.street2
street += ads.street2
if ads.country_id:
country=ads.country_id.code
country = ads.country_id.code
sender_date=time.strftime('%Y-%m-%d')
data_file='<?xml version="1.0"?>\n<VatList xmlns="http://www.minfin.fgov.be/VatList" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.minfin.fgov.be/VatList VatList.xml" RecipientId="VAT-ADMIN" SenderId="'+ str(company_vat) + '"'
data_file +=' ControlRef="'+ cref + '" MandataireId="'+ data['form']['mand_id'] + '" SenderDate="'+ str(sender_date)+ '"'
sender_date = time.strftime('%Y-%m-%d')
data_file = '<?xml version="1.0"?>\n<VatList xmlns="http://www.minfin.fgov.be/VatList" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.minfin.fgov.be/VatList VatList.xml" RecipientId="VAT-ADMIN" SenderId="'+ str(company_vat) + '"'
data_file +=' ControlRef="'+ cref + '" MandataireId="'+ tools.ustr(data['form']['mand_id']) + '" SenderDate="'+ str(sender_date)+ '"'
if data['form']['test_xml']:
data_file += ' Test="0"'
data_file += ' VersionTech="1.2">'
data_file +='\n<AgentRepr DecNumber="1">\n\t<CompanyInfo>\n\t\t<VATNum>'+str(company_vat)+'</VATNum>\n\t\t<Name>'+str(obj_cmpny.name)+'</Name>\n\t\t<Street>'+ str(street) +'</Street>\n\t\t<CityAndZipCode>'+ str(zip_city) +'</CityAndZipCode>'
data_file +='\n\t\t<Country>'+ str(country) +'</Country>\n\t</CompanyInfo>\n</AgentRepr>'
data_comp ='\n<CompanyInfo>\n\t<VATNum>'+str(company_vat)+'</VATNum>\n\t<Name>'+str(obj_cmpny.name)+'</Name>\n\t<Street>'+ str(street) +'</Street>\n\t<CityAndZipCode>'+ str(zip_city) +'</CityAndZipCode>\n\t<Country>'+ str(country) +'</Country>\n</CompanyInfo>'
data_period ='\n<Period>'+ str(obj_year.date_stop[:4]) +'</Period>'
error_message=[]
data_file += '\n<AgentRepr DecNumber="1">\n\t<CompanyInfo>\n\t\t<VATNum>'+str(company_vat)+'</VATNum>\n\t\t<Name>'+tools.ustr(obj_cmpny.name)+'</Name>\n\t\t<Street>'+ tools.ustr(street) +'</Street>\n\t\t<CityAndZipCode>'+ tools.ustr(zip_city) +'</CityAndZipCode>'
data_file += '\n\t\t<Country>'+ tools.ustr(country) +'</Country>\n\t</CompanyInfo>\n</AgentRepr>'
data_comp = '\n<CompanyInfo>\n\t<VATNum>'+str(company_vat)+'</VATNum>\n\t<Name>'+tools.ustr(obj_cmpny.name)+'</Name>\n\t<Street>'+ tools.ustr(street) +'</Street>\n\t<CityAndZipCode>'+ tools.ustr(zip_city) +'</CityAndZipCode>\n\t<Country>'+ tools.ustr(country) +'</Country>\n</CompanyInfo>'
data_period = '\n<Period>'+ tools.ustr(obj_year.date_stop[:4]) +'</Period>'
error_message = []
for p_id in p_id_list:
record = {} # this holds record per partner
@@ -125,7 +126,7 @@ class wizard_vat(wizard.interface):
continue
query = 'select b.code,sum(credit)-sum(debit) from account_move_line l left join account_account a on (l.account_id=a.id) left join account_account_type b on (a.user_type=b.id) where b.code in ('"'produit'"','"'tax'"') and l.partner_id='+str(p_id)+' and l.period_id in '+period+' group by b.code'
cr.execute(query)
line_info=cr.fetchall()
line_info = cr.fetchall()
if not line_info:
continue
@@ -172,13 +173,13 @@ class wizard_vat(wizard.interface):
seq +=1
sum_tax +=line['amount']
sum_turnover +=line['turnover']
data_clientinfo +='\n<ClientList SequenceNum="'+str(seq)+'">\n\t<CompanyInfo>\n\t\t<VATNum>'+line['vat'] +'</VATNum>\n\t\t<Country>'+line['country'] +'</Country>\n\t</CompanyInfo>\n\t<Amount>'+str(int(line['amount'] * 100)) +'</Amount>\n\t<TurnOver>'+str(int(line['turnover'] * 100)) +'</TurnOver>\n</ClientList>'
data_clientinfo +='\n<ClientList SequenceNum="'+str(seq)+'">\n\t<CompanyInfo>\n\t\t<VATNum>'+line['vat'] +'</VATNum>\n\t\t<Country>'+tools.ustr(line['country']) +'</Country>\n\t</CompanyInfo>\n\t<Amount>'+str(int(line['amount'] * 100)) +'</Amount>\n\t<TurnOver>'+str(int(line['turnover'] * 100)) +'</TurnOver>\n</ClientList>'
data_decl ='\n<DeclarantList SequenceNum="1" DeclarantNum="'+ dnum + '" ClientNbr="'+ str(seq) +'" TurnOverSum="'+ str(int(sum_turnover * 100)) +'" TaxSum="'+ str(int(sum_tax * 100)) +'" />'
data_file += str(data_decl) + str(data_comp) + str(data_period) + str(data_clientinfo) + '\n</VatList>'
data_file += tools.ustr(data_decl) + tools.ustr(data_comp) + tools.ustr(data_period) + tools.ustr(data_clientinfo) + '\n</VatList>'
data['form']['msg']='Save the File with '".xml"' extension.'
data['form']['file_save']=base64.encodestring(data_file)
data['form']['msg'] = 'Save the File with '".xml"' extension.'
data['form']['file_save'] = base64.encodestring(data_file.encode('utf8'))
return data['form']
states = {
@@ -1,3 +1,11 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_report_sale_order_product,report.sale.order.product,model_report_sale_order_product,sale.group_sale_manager,1,0,0,0
access_report_sale_order_category,report.sale.order.category,model_report_sale_order_category,sale.group_sale_manager,1,0,0,0
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_report_sale_order_product","report.sale.order.product","model_report_sale_order_product","sale.group_sale_manager",1,0,0,0
"access_report_sale_order_category","report.sale.order.category","model_report_sale_order_category","sale.group_sale_manager",1,0,0,0
"access_report_turnover_per_month","report.turnover.per.month","model_report_turnover_per_month","sale.group_sale_manager",1,0,0,0
"access_report_turnover_per_product","report.turnover.per.product","model_report_turnover_per_product","sale.group_sale_manager",1,0,0,0
"access_report_sale_order_created","report.sale.order.created","model_report_sale_order_created","sale.group_sale_manager",1,0,0,0
"access_report_sale_order_product_user","report.sale.order.product","model_report_sale_order_product","sale.group_sale_user",1,0,0,0
"access_report_sale_order_category_user","report.sale.order.category","model_report_sale_order_category","sale.group_sale_user",1,0,0,0
"access_report_turnover_per_month_user","report.turnover.per.month","model_report_turnover_per_month","sale.group_sale_user",1,0,0,0
"access_report_turnover_per_product_user","report.turnover.per.product","model_report_turnover_per_product","sale.group_sale_user",1,0,0,0
"access_report_sale_order_created_user","report.sale.order.created","model_report_sale_order_created","sale.group_sale_user",1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_report_sale_order_product report.sale.order.product model_report_sale_order_product sale.group_sale_manager 1 0 0 0
3 access_report_sale_order_category report.sale.order.category model_report_sale_order_category sale.group_sale_manager 1 0 0 0
4 access_report_turnover_per_month report.turnover.per.month model_report_turnover_per_month sale.group_sale_manager 1 0 0 0
5 access_report_turnover_per_product report.turnover.per.product model_report_turnover_per_product sale.group_sale_manager 1 0 0 0
6 access_report_sale_order_created report.sale.order.created model_report_sale_order_created sale.group_sale_manager 1 0 0 0
7 access_report_sale_order_product_user report.sale.order.product model_report_sale_order_product sale.group_sale_user 1 0 0 0
8 access_report_sale_order_category_user report.sale.order.category model_report_sale_order_category sale.group_sale_user 1 0 0 0
9 access_report_turnover_per_month_user report.turnover.per.month model_report_turnover_per_month sale.group_sale_user 1 0 0 0
10 access_report_turnover_per_product_user report.turnover.per.product model_report_turnover_per_product sale.group_sale_user 1 0 0 0
11 access_report_sale_order_created_user report.sale.order.created model_report_sale_order_created sale.group_sale_user 1 0 0 0