How can i generate xls report in odoo - odoo
I want to generate my own excel report using Excel report engine in odoo 8. someone please send me a simple excel report sample or any helping URL. I'll be very thankful to you ....
Here is a simple piece of code. There is really a lot of examples on the internet with good explanations. I suggest you go through the code in detail to see how it works (by the way I have copied the code also from somewhere - I cannot remember where. Also have a look at the examples here:https://github.com/OCA/reporting-engine/tree/8.0
The version 8 branch also have a number of examples.
You can add columns by editing the "my_change" variable.
from openerp.osv import orm
from openerp.addons.report_xls.utils import rowcol_to_cell, _render
from openerp.tools.translate import _
class account_move_line(orm.Model):
_inherit = 'abc.salesforecast'
# override list in custom module to add/drop columns or change order
def _report_xls_fields(self, cr, uid, context=None):
return [
'contract', 'proposal', 'description',
#'amount_currency', 'currency_name',
]
# Change/Add Template entries
def _report_xls_template(self, cr, uid, context=None):
"""
Template updates, e.g.
my_change = {
'move':{
'header': [1, 20, 'text', _('My Move Title')],
'lines': [1, 0, 'text', _render("line.move_id.name or ''")],
'totals': [1, 0, 'text', None]},
}
return my_change
"""
return {}
The code for the parser is as follows.
import xlwt
import time
from datetime import datetime
from openerp.osv import orm
from openerp.report import report_sxw
from openerp.addons.report_xls.report_xls import report_xls
from openerp.addons.report_xls.utils import rowcol_to_cell, _render
from openerp.tools.translate import translate, _
from openerp import pooler
import logging
_logger = logging.getLogger(__name__)
class contract_sales_forecast_xls_parser(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(contract_sales_forecast_xls_parser, self).__init__(cr, uid, name, context=context)
forecast_obj = self.pool.get('msr.salesforecast')
self.context = context
wanted_list = forecast_obj._report_xls_fields(cr, uid, context)
template_changes = forecast_obj._report_xls_template(cr, uid, context)
self.localcontext.update({
'datetime': datetime,
'wanted_list': wanted_list,
'template_changes': template_changes,
'_': self._,
})
def _(self, src):
lang = self.context.get('lang', 'en_US')
return translate(self.cr, _ir_translation_name, 'report', lang, src) or src
class contract_sales_forecast_xls(report_xls):
def __init__(self, name, table, rml=False, parser=False, header=True, store=False):
super(contract_sales_forecast_xls, self).__init__(name, table, rml, parser, header, store)
# Cell Styles
_xs = self.xls_styles
# header
rh_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rh_cell_style = xlwt.easyxf(rh_cell_format)
self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center'])
self.rh_cell_style_right = xlwt.easyxf(rh_cell_format + _xs['right'])
# lines
aml_cell_format = _xs['borders_all']
self.aml_cell_style = xlwt.easyxf(aml_cell_format)
self.aml_cell_style_center = xlwt.easyxf(aml_cell_format + _xs['center'])
self.aml_cell_style_date = xlwt.easyxf(aml_cell_format + _xs['left'], num_format_str = report_xls.date_format)
self.aml_cell_style_decimal = xlwt.easyxf(aml_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
# totals
rt_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rt_cell_style = xlwt.easyxf(rt_cell_format)
self.rt_cell_style_right = xlwt.easyxf(rt_cell_format + _xs['right'])
self.rt_cell_style_decimal = xlwt.easyxf(rt_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
# XLS Template
self.col_specs_template = {
'contract':{
'header': [1, 20, 'text', _render("_('Contract Number')")],
'lines': [1, 0, 'text', _render("msr_contract_id or ''")],
'totals': [1, 0, 'text', None]},
'proposal':{
'header': [1, 42, 'text', _render("_('Proposal Number')")],
'lines': [1, 0, 'text', _render("msr_proposal or ''")],
'totals': [1, 0, 'text', None]},
'description':{
'header': [1, 42, 'text', _render("_('Description')")],
'lines': [1, 0, 'text', _render("name or ''")],
'totals': [1, 0, 'text', None]},
}
def generate_xls_report(self, _p, _xs, data, objects, wb):
wanted_list = _p.wanted_list
self.col_specs_template.update(_p.template_changes)
_ = _p._
#report_name = objects[0]._description or objects[0]._name
report_name = _("Sales forecast from current contracts")
ws = wb.add_sheet(report_name[:31])
ws.panes_frozen = True
ws.remove_splits = True
ws.portrait = 0 # Landscape
ws.fit_width_to_pages = 1
row_pos = 0
# set print header/footer
ws.header_str = self.xls_headers['standard']
ws.footer_str = self.xls_footers['standard']
# Title
cell_style = xlwt.easyxf(_xs['xls_title'])
c_specs = [
('report_name', 1, 0, 'text', report_name),
]
row_data = self.xls_row_template(c_specs, ['report_name'])
row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=cell_style)
row_pos += 1
# Column headers
c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={'_': _p._}), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.rh_cell_style, set_column_size=True)
ws.set_horz_split_pos(row_pos)
# account move lines
for line in objects:
c_specs = map(lambda x: self.render(x, self.col_specs_template, 'lines'), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.xls_write_row(ws, row_pos, row_data, row_style=self.aml_cell_style)
# Totals
contract_sales_forecast_xls('report.contract.sales.forecast.xls',
'abc.salesforecast',
parser="contract_sales_forecast_xls_parser")
The xml file will look as follows to setup the necessary actions etc.
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="action_contract_sales_forecast_xls" model="ir.actions.report.xml">
<field name="name">Export Selected Lines To Excel</field>
<field name="model">abc.salesforecast</field>
<field name="type">ir.actions.report.xml</field>
<field name="report_name">contract.sales.forecast.xls</field>
<field name="report_type">xls</field>
<field name="auto" eval="False"/>
</record>
<record model="ir.values" id="contract_sales_forecast_xls_values">
<field name="name">Export Selected Lines</field>
<field name="key2">client_action_multi</field>
<field name="value" eval="'ir.actions.report.xml,' +str(ref('action_contract_sales_forecast_xls'))" />
<field name="model">abc.salesforecast</field>
</record>
</data>
</openerp>
A second example. First the xml to create a button. This is only an extract.
<form string = "Contract Search Wizard" version="7.0">
<sheet>
<group>
<button icon="gtk-ok" name="print_contract_list" string="Print Contract List" type="object" />
<button icon="gtk-ok" name="export_contract_product" string="Export Contract vs. Product Pivot Table" type="object" />
<button icon="gtk-ok" name="export_contract_country" string="Export Contract vs. Country Pivot Table" type="object" />
<button icon="gtk-cancel" special="cancel" string="Cancel" />
</group>
</sheet>
</form>
The below code is a wizard with several buttons. I removed some code to save space. The report is activated from a button:
class abc_contract_search_wizard(osv.osv):
def _prd_report_xls_fields(self, cr, uid, context=None):
SQLstring = "SELECT abc_product_list.name FROM abc_product_list;"
cr.execute(SQLstring)
tbl_products = cr.dictfetchall()
header_list=['contract_id','contract_name','exclusive']
for t in tbl_products:
header_list.append(t['name'])
return header_list
# Change/Add Template entries
def _prd_report_xls_template(self, cr, uid, context=None):
"""
Template updates, e.g.
my_change = {
'move':{
'header': [1, 20, 'text', _('My Move Title')],
'lines': [1, 0, 'text', _render("line.move_id.name or ''")],
'totals': [1, 0, 'text', None]},
}
return my_change
"""
SQLstring = "SELECT abc_product_list.name FROM abc_product_list;"
cr.execute(SQLstring)
tbl_products = cr.dictfetchall()
abc_tmpl = {
'contract_id':
{
'header':[1,20, 'text', _render("_('Contract ID')")],
'lines':[1,0, 'text', _render("line.abc_contract_id.name or ''")],
'totals':[1, 0, 'text', None],
},
'contract_name' :
{
'header':[1,40, 'text', _render("_('Contract Name')")],
'lines':[1,0, 'text', _render("line.abc_contract_name or ''")],
'totals':[1, 0, 'text', None],
},
'exclusive':
{
'header':[1,10, 'text', _render("_('Exlusive')")],
'lines':[1,0, 'text', _render("line.abc_country.name or ''")],
'totals':[1, 0, 'text', None],
},
}
for t in tbl_products:
abc_tmpl[t['name']]={
'header':[1,3, 'text', _render("_('" + t['name']+"')")],
'lines':[1,0, 'text', _render("line.abc_contract_id.name or ''")],
'totals':[1, 0, 'text', None],
}
return abc_tmpl
_name='abc.contract.search.wizard'
_columns={
'country':fields.many2one('abc.countries','Country'),
'product':fields.many2one('abc.product.list','Product'),
'start_date':fields.date('Start Date'),
'end_date':fields.date('End Date'),
'partner':fields.many2one('res.partner','Partner'),
'product_type':fields.many2one('abc.product.type','Product Type'),
'regions':fields.many2one('abc.regions', 'Regions'),
'exclusive':fields.boolean('Exclusive'),
'contract_type':fields.many2one('abc.contract.types','Contract Type'),
}
def find_product(self, tbl_contractproducts, product_id):
is_there=False
for t in tbl_contractproducts:
if product_id==t['product_id']:
is_there=True
return is_there
def get_contract_products(self, cr, uid, ids, context, contract_id, tbl_products):
products={}
SQLstring = "SELECT abc_contract_product_list.product_id, abc_contract_product_list.contract_id FROM abc_contract_product_list " \
+ "WHERE (((abc_contract_product_list.contract_id) =" + str(contract_id) + "));"
cr.execute(SQLstring)
tbl_contractproducts = cr.dictfetchall()
for t in tbl_products:
if self.find_product(tbl_contractproducts,t['product_id']):
products[t['product_name']]='X'
else:
products[t['product_name']]=''
return products
def export_contract_product(self, cr, uid, ids, context=None):
rst = self.browse(cr, uid, ids)[0]
country_id = rst.country.id
product_id = rst.product.id
start_date = rst.start_date
end_date = rst.end_date
product_type_id = rst.product_type.id
partner_id = rst.partner.id
region_id = rst.regions.id
exclusive = rst.exclusive
contract_type_id = rst.contract_type.id
SQLwhere = ""
SQLstring = "SELECT DISTINCT abc_official_documents.id, abc_official_documents.contract_id, abc_official_documents.name AS doc_name, abc_official_documents.contract_exclusive_agreemnet " \
+ "FROM res_partner INNER JOIN (((abc_contract_countries INNER JOIN (((abc_contract_product_list INNER JOIN (abc_product_type INNER JOIN abc_product_list " \
+ "ON abc_product_type.id = abc_product_list.product_type) ON abc_contract_product_list.product_id = abc_product_list.id) INNER JOIN abc_official_documents ON "\
+ "abc_contract_product_list.contract_id = abc_official_documents.id) INNER JOIN abc_contract_types ON abc_official_documents.contract_type = abc_contract_types.id) "\
+ "ON abc_contract_countries.contract_id = abc_official_documents.id) INNER JOIN abc_countries ON abc_contract_countries.country_id = abc_countries.id) INNER JOIN "\
+ "abc_regions ON abc_countries.country_region = abc_regions.id) ON res_partner.id = abc_official_documents.contract_partner_id "
if country_id:
SQLwhere = " AND ((abc_contract_countries.country_id) = " + str(country_id) + ")"
if product_id:
SQLwhere = SQLwhere + " AND ((abc_contract_product_list.product_id) = " + str(product_id) + ")"
if start_date:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_start_date) < " + str(start_date) + ")"
if end_date:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_termination_date) < " + str(end_date) + ")"
if partner_id:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_partner_id) = " + str(partner_id) +")"
if region_id:
SQLwhere = SQLwhere + " AND ((abc_countries.country_region) = " + str(region_id) + ")"
if exclusive:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_exclusive_agreemnet) = true )"
if contract_type_id:
SQLwhere = SQLwhere + " AND ((abc_official_documents.contract_type) = " + str(contract_type_id) + ")"
if product_type_id:
SQLwhere = SQLwhere + " AND ((abc_product_list.product_type) = " +str(product_type_id) + ")"
SQLwhere = SQLwhere[-(len(SQLwhere)-5):] #Vat die eerste "AND" weg (5 karakters)
if ((not SQLwhere) | (len(SQLwhere)==0)):
SQLstring = SQLstring + " LIMIT 100;"
else:
SQLstring = SQLstring + "WHERE (" + SQLwhere + ") LIMIT 100;"
cr.execute(SQLstring)
tblContracts = cr.dictfetchall()
SQLstring = "SELECT abc_product_list.id AS product_id, abc_product_list.name as product_name FROM abc_product_list;"
cr.execute(SQLstring)
tbl_products = cr.dictfetchall()
pivot_table = []
datas={'ids':context.get('active_ids', [])}
for t in tblContracts:
if t:
if t['contract_exclusive_agreemnet']:
excl="Yes"
else:
excl = "No"
contract_table = {
'contract_id': t['contract_id'],
'contract_name': t['doc_name'],
'exclusive':excl,
}
product_table=self.get_contract_products(cr, uid, ids, context, t['id'], tbl_products)
full_table = dict(contract_table.items() + product_table.items())
pivot_table.append(full_table)
datas['contract_list']= pivot_table
return {
'type':'ir.actions.report.xml',
'report_name': 'contract_products',
'datas':datas,
}
abc_contract_search_wizard()
Here is the code for the parser:
class contract_products_parser(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(contract_products_parser, self).__init__(cr, uid, name, context=context)
forc_obj = self.pool.get('abc.contract.search.wizard')
self.context = context
wanted_list = forc_obj._prd_report_xls_fields(cr, uid, context)
template_changes = forc_obj._prd_report_xls_template(cr, uid, context)
self.localcontext.update({
'datetime': datetime,
'wanted_list': wanted_list,
'template_changes': template_changes,
'_': self._,
})
def _(self, src):
lang = self.context.get('lang', 'en_US')
return translate(self.cr, _ir_translation_name, 'report', lang, src) or src
class contract_products_xls(report_xls):
def __init__(self, name, table, rml=False, parser=False, header=True, store=False):
super(contract_products_xls, self).__init__(name, table, rml, parser, header, store)
# Cell Styles
_xs = self.xls_styles
# header
rh_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rh_cell_style = xlwt.easyxf(rh_cell_format)
self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center'])
self.rh_cell_style_right = xlwt.easyxf(rh_cell_format + _xs['right'])
# lines
aml_cell_format = _xs['borders_all']
self.aml_cell_style = xlwt.easyxf(aml_cell_format)
self.aml_cell_style_center = xlwt.easyxf(aml_cell_format + _xs['center'])
self.aml_cell_style_date = xlwt.easyxf(aml_cell_format + _xs['left'], num_format_str = report_xls.date_format)
self.aml_cell_style_decimal = xlwt.easyxf(aml_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
# totals
rt_cell_format = _xs['bold'] + _xs['fill'] + _xs['borders_all']
self.rt_cell_style = xlwt.easyxf(rt_cell_format)
self.rt_cell_style_right = xlwt.easyxf(rt_cell_format + _xs['right'])
self.rt_cell_style_decimal = xlwt.easyxf(rt_cell_format + _xs['right'], num_format_str = report_xls.decimal_format)
self.col_specs_template = {
}
def get_c_specs(self, wanted, col_specs, rowtype, data):
"""
returns 'evaluated' col_specs
Input:
- wanted: element from the wanted_list
- col_specs : cf. specs[1:] documented in xls_row_template method
- rowtype : 'header' or 'data'
- render_space : type dict, (caller_space + localcontext)
if not specified
"""
row = col_specs[wanted][rowtype][:]
row[3]=data[wanted]
row.insert(0, wanted)
return row
return True
def new_xls_write_row(self, ws, row_pos, row_data, header, headrot_style, dark_style,
row_style=default_style, set_column_size=False ):
r = ws.row(row_pos)
orig_style=row_style
for col, size, spec in row_data:
data = spec[4]
if header:
if (col!=0) & (col!=1) & (col!=2):
row_style=headrot_style #+ 'align: rotation 90;'
else:
if data=="X":
row_style=dark_style #+ 'pattern: pattern solid, fore_color 0;'
else:
row_style=orig_style
formula = spec[5].get('formula') and \
xlwt.Formula(spec[5]['formula']) or None
style = spec[6] and spec[6] or row_style
if not data:
# if no data, use default values
data = report_xls.xls_types_default[spec[3]]
if size != 1:
if formula:
ws.write_merge(
row_pos, row_pos, col, col + size - 1, data, style)
else:
ws.write_merge(
row_pos, row_pos, col, col + size - 1, data, style)
else:
if formula:
ws.write(row_pos, col, formula, style)
else:
spec[5]['write_cell_func'](r, col, data, style)
if set_column_size:
ws.col(col).width = spec[2] * 256
return row_pos + 1
def generate_xls_report(self, _p, _xs, data, objects, wb):
wanted_list = _p.wanted_list
self.col_specs_template.update(_p.template_changes)
_ = _p._
#report_name = objects[0]._description or objects[0]._name
report_name = _("Export Contract Countries")
ws = wb.add_sheet(report_name[:31])
ws.panes_frozen = True
ws.remove_splits = True
ws.portrait = 0 # Landscape
ws.fit_width_to_pages = 1
row_pos = 0
_xs = self.xls_styles
headrot_style = _xs['bold'] + _xs['fill'] + _xs['borders_all'] + 'align: rotation 90'
xlwt_headrot=xlwt.easyxf(headrot_style)
dark_style = _xs['borders_all']+'pattern: pattern solid, fore_color 0;'
#self.rh_cell_style = xlwt.easyxf(rh_cell_format)
#self.rh_cell_style_center = xlwt.easyxf(rh_cell_format + _xs['center'])
# set print header/footer
ws.header_str = self.xls_headers['standard']
ws.footer_str = self.xls_footers['standard']
# Title
cell_style = xlwt.easyxf(_xs['xls_title'])
c_specs = [
('report_name', 1, 0, 'text', report_name),
]
row_data = self.xls_row_template(c_specs, ['report_name'])
row_pos = self.new_xls_write_row(ws, row_pos, row_data, False, xlwt_headrot , xlwt.easyxf(dark_style), row_style=cell_style )
row_pos += 1
# Column headers
c_specs = map(lambda x: self.render(x, self.col_specs_template, 'header', render_space={'_': _p._}), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.new_xls_write_row(ws, row_pos, row_data, True, xlwt_headrot, xlwt.easyxf(dark_style), row_style=self.rh_cell_style, set_column_size=True)
ws.set_horz_split_pos(row_pos)
# account move lines
for line in data['contract_list']:
c_specs = map(lambda x: self.get_c_specs(x, self.col_specs_template, 'lines', line), wanted_list)
row_data = self.xls_row_template(c_specs, [x[0] for x in c_specs])
row_pos = self.new_xls_write_row(ws, row_pos, row_data, False, xlwt_headrot, xlwt.easyxf(dark_style), row_style=self.aml_cell_style)
contract_products_xls('report.contract_products',
'abc.contract.search.wizard',
parser=contract_products_parser)
To Create an Excel file or a spreadsheet
“import xlwt” package functionality to create sheet in your Py file.We can define the title, header, number, date, and normal style using xlwt.easyxf().
For example title style is given below
new_style = xlwt.easyxf(‘font:height 230; align: wrap No;border: top thick;border: bottom thick;’)
Define how the border should appear.define the workbook. Workbook is actually what we view in our spreadsheet.
To define workbook,
wbk = xlwt.Workbook()
sheet = wbk.add_sheet(‘New_sheet’, cell_overwrite_ok=True)
for write in to the sheet
sheet.write(4, 4, ‘Spellbound Soft Solution’,font_size)
To change the width and height of a cell,
sheet.col(1).width = 500*12
sheet.row(5).height = 70*5
for more goto :
http://spellboundss.com/xls-report-in-odoo/
Thanks
Simply add this report_xlsx module from the app store.
your_module_name --> report--> my_report.py
your_module_name --> report--> my_report.xml
my_report.py
try:
from openerp.addons.report_xlsx.report.report_xlsx import ReportXlsx
except ImportError:
class ReportXlsx(object):
def __init__(self, *args, **kwargs):
pass
class PartnerXlsx(ReportXlsx):
def generate_xlsx_report(self, workbook, data, partners):
for obj in partners:
report_name = obj.name
# One sheet by partner
sheet = workbook.add_worksheet(report_name[:31])
bold = workbook.add_format({'bold': True})
sheet.write(0, 0, obj.name, bold)
PartnerXlsx('report.res.partner.xlsx', 'res.partner')
my_report.xml
`<report
id="partner_xlsx"
model="res.partner"
string="Print to XLSX"
report_type="xlsx"
name="res.partner.xlsx"
file="res.partner.xlsx"
attachment_use="False"
/>`
Related
Add lines to stock picking move lines
In my method, I delete lines from stock.pickings and want to add different lines from my model. but i get an error AttributeError: 'stock.move' object has no attribute 'get' #api.multi def _action_procurement_create(self): res = super(SaleOrderLine, self)._action_procurement_create() order_line_bom = self.env['sale.order.line.bom'].search([('sale_order_line_id', '=', self.id )]) stock_move_lines = self.env['stock.move'] created_stock_move_lines = self.env['stock.move'] vals = {} for order in self.order_id: if self.product_id.bom_ids: order.picking_ids.move_lines.state = 'draft' for move_line in order.picking_ids.move_lines: move_line.unlink() for bom_line in order_line_bom: vals['product_id'] = bom_line.product_id.id, vals['product_uom'] = 1, vals['location_id'] = 1, vals['name'] = bom_line.product_id.name, vals['location_dest_id'] = 1, created_stock_move_lines += stock_move_lines.create(vals) order.create(stock_move_lines)
You have defined: stock_move_lines = self.env['stock.move'] Then you try to pass it to create method: order.create(stock_move_lines) As documented in model.py :param dict vals: values for the model's fields, as a dictionary:: {'field_name': field_value, ...} see :meth:`~.write` for details
Please try may it's help you : #api.multi def _action_procurement_create(self): res = super(SaleOrderLine, self)._action_procurement_create() order_line_bom = self.env['sale.order.line.bom'].search([('sale_order_line_id', '=', self.id )]) stock_move_lines = self.env['stock.move'] created_stock_move_lines = self.env['stock.move'] vals = {} for order in self.order_id: if self.product_id.bom_ids: order.picking_ids.move_lines.state = 'draft' for move_line in order.picking_ids.move_lines: move_line.unlink() for bom_line in order_line_bom: vals = { 'product_id': bom_line.product_id.id, 'product_uom': 1, 'location_id': 1, 'name': bom_line.product_id.name, 'location_dest_id': 1, } created_stock_move_lines += stock_move_lines.create(vals) order.create(stock_move_lines)
How to create sample sale order and sale order line in odoo?
I am trying to create a sample order in sales order.In the sample order form, products are sold to customers as complimentary copy(books in my case) without charging any money so I have created a separate sub-menu in sales menu.Here I take only product and quantity as input. Sample order number will be the next number from the sales order(like SO360).So I am fetching sales order number as parent_id in my inherited module.I am not able to create sale order line(data in order lines tab) class SaleOrder(models.Model): _inherit = 'sale.order' # Fields is_sample = fields.Boolean(string="Sample Order", default=False) parent_id = fields.Many2one('sale.order', string="Parent Sales Order") sample_ids = fields.One2many('sale.order', 'parent_id', string="Sample Orders") # Methods #api.model #api.returns('sale.order') def create(self, vals): if vals.get('is_sample', False) and vals.get('name', '/') == '/': IrSeq = self.env['ir.sequence'] ref = IrSeq.next_by_code('sale.order.sample.ref') or '/' parent = self.search([('id', '=', vals.get('parent_id'))]) vals['name'] = parent.name + ref vals['user_id'] = parent.user_id.id return super(SaleOrder, self).create(vals) class SampleOrderWizard(models.TransientModel): _name = 'sale.order.sample.wizard' _description = 'Sample Sale Order Wizard' # Field default values # def _get_parent(self): res = False if self.env.context \ and 'active_id' in list(self.env.context.iterkeys()): res = self.env.context['active_id'] return res def _get_new_sale_line(self, orig_sale, orig_sale_line, wizard_line): """Internal function to get the fields of the sale order line. Modules enhancing this one should add their own fields to the return value.""" res = { 'order_id': orig_sale.id, 'product_id': orig_sale_line.product_id.id, 'name': orig_sale_line.name, 'sequence': orig_sale_line.sequence, 'price_unit': orig_sale_line.price_unit, 'product_uom': orig_sale_line.product_uom.id, 'product_uom_qty': wizard_line and wizard_line.qty or 0, 'product_uos_qty': wizard_line and wizard_line.qty or 0, } # Simple check for installation of sale_line_code module if hasattr(orig_sale_line, 'order_line_ref'): res.update({'order_line_ref': orig_sale_line.order_line_ref}) return res def _get_order_lines(self, sale): res = [] for line in sale.order_line: wizard_line = False for wzline in self.wizard_lines: if wzline.product == line.product_id: wizard_line = wzline break if wizard_line: res.append( (0, 0, self._get_new_sale_line(sale, line, wizard_line)) ) return res def _get_wizard_lines(self): res = [] if self._get_parent(): SaleOrder = self.env['sale.order'] parent = SaleOrder.search([('id', '=', self._get_parent())]) for line in parent.order_line: res.append((0, 0, { 'product': line.product_id, 'qty': 1, })) return res # Fields # order = fields.Many2one('sale.order', default=_get_parent, readonly=True) wizard_lines = fields.One2many('sale.order.sample.wizard.line', 'wizard', default=_get_wizard_lines) order_date = fields.Datetime(default=fields.Datetime.now()) # Methods # #api.one def create_order(self): sale_vals = { 'user_id': self.order.user_id.id, 'partner_id': self.order.partner_id.id, 'parent_id': self.order.id, 'date_order': self.order_date, 'client_order_ref': self.order.client_order_ref, 'company_id': self.order.company_id.id, 'is_sample': True, 'order_line': self._get_order_lines(self.order) } self.env['sale.order'].create(sale_vals) return {'type': 'ir.actions.act_window_close'} class SampleOrderWizardLine(models.TransientModel): _name = 'sale.order.sample.wizard.line' _description = 'Sample Order Wizard Line' wizard = fields.Many2one('sale.order.sample.wizard') product = fields.Many2one('product.product', domain=[('sale_ok', '=', True)]) qty = fields.Float(string="Quantity", default=1.0, digits_compute=dp.get_precision('Product UoS'))
Odoo computed fields: result in unsupported operand type(s)
In Odoo 8 i have a computed field with a function which result in a error. Can't seem to make things work and need some help. My test code: from openerp import models, fields, api, _ from openerp.tools.translate import _ import openerp.addons.decimal_precision as dp class plano(models.Model): _name = 'plano' _description = "variabelen plaat toeslagen, rillen kenmerken." name = fields.Char('Plano naam', required=True) constructie_id = fields.Char('Fefco constructie') testB_p1 = fields.Char('Breedte P1', help = 'Tekst veld P1 (variabele breedte P1)') toeslagB_p1 = fields.Float('toeslag breedte P1 (variabel Breedte P1)', digits=(3, 1)) testL_p1 = fields.Char('Lengte P1', help = 'Tekst veld P1 (variabele lengte P1)') toeslagL_p1 = fields.Float('toeslag lengte P1 (variabel lengte P1)', digits=(3, 1)) Kw = fields.Float('Kwaliteit dikte in mm', digits=(3, 0), help = "Wordt uit gerelateerd veld van model Quality gehaald.") class calc(models.Model): #api.depends('name') def _functionb_p1(self): val1 = 0.0 if plano.testB_p1 != 'H+': val1 = calc.hoogte + (2.0 * plano.Kw) + 2.0 elif plano.testB_p1 != 'B': val1 = calc.breedte + (plano.toeslagB_p1 * plano.Kw) return val1 _name = "calc" _description = "kostprijs berekening." name = fields.Many2one('plano', help = "Kostprijs berekening nummer e.g. C1234") lengte = fields.Float('Lengte in mm', digits=(4, 0), help = "Lengte in mm") breedte = fields.Float('Breedte in mm', digits=(4, 0)) hoogte = fields.Float('Hoogte in mm', digits=(4, 0)) aantal = fields.Float('Aantal stuks', digits=(4, 0)) planob_p1 = fields.Float('Plano Breedte P1') planobt_p1 = fields.Float('Plano Breedte toeslag P1') val1 = fields.Float(compute = '_functionb_p1', store=True, string = 'Aanmaak Plano breedte P1', help = "Berekening vanuit functie _functionb_p1") ERROR: File "....8.0\test\models\calc.py", line 47, in _functionb_p1 val1 = calc.hoogte + (2.0 * plano.Kw) + 2.0 TypeError: unsupported operand type(s) for *: 'float' and 'Float'
The TypeError is very weird. I never had such problems with Odoo Float... But some hints to your computing function. It should use #api.multi or #api.one (second is deprecated) as additional decorator. And then you should have a connection between plano and calc models. Your model relation (there is no one) doesn't allow the calculation you're looking for, because you need a plano instance/record and a calc instance/record. You're computing your value on calc model, so i will try to get you the right method, with one condition: there is a Many2One field on calc model named plano_id. #api.multi #api.depends('name') def _functionb_p1(self): for calc in self: val1 = 0.0 plano = calc.plano_id if plano.testB_p1 != 'H+': val1 = calc.hoogte + (2.0 * plano.Kw) + 2.0 elif calc.plano_id.testB_p1 != 'B': val1 = calc.breedte + (plano.toeslagB_p1 * plano.Kw) calc.val1 = val1 # my condition! plano_id = fields.Many2One(comodel_name="plano", string="Plano")
Multiple creations on Odoo/Openerp res.partner table fail when one by one succeed
Here is what I am trying to do, I have a CSV file that has some records that I want to import on my installation. The following code works when I put a return None statement on the end of the loop. (Which you will find commented out Upon the click of a button this method will be executed in order to loop through all the rows on the CSV and depending on the conditions create a new res.partner record. (this has been implemented via XML-RPC calls and it worked flawlessly.) The problem is this: When I stop the execution after the import of one CSV row, everything works (the record on res.partner is created), when I leave it running with the loop no records are created on the table res.partner (I get no errors, no exceptions whatsoever. I even get the newly created record's id upon the invocation of res_partner_obj.create() ). Note: You will find lots of irrelevant code to my problem (which is why the records on res.partner are not created). I just put it there for the sake of completeness) def gms_import_test(self, cr, uid, vals, context=None, check=True): start_time = time.time() res_partner_obj = self.pool.get('res.partner') sales_teams_obj = self.pool.get('crm.case.section') res_partner_title_obj = self.pool.get('res.partner.title') customer_kunden_obj = self.pool.get('customer.kundengruppe') res_country_obj = self.pool.get('res.country') account_account_obj = self.pool.get('account.account') crm_phonecall_obj = self.pool.get('crm.phonecall') account_account_type_obj = self.pool.get('account.account.type') # sys.path[0] == module's path + /addons/gmsimport/+ file's name with open(sys.path[0] + '/addons/gmsimport/' + '21.9.2015.try8.csv') as csv_file: # TODO THESE MUST CHANGE UPON DEPLOYMENT TO DIFFERENT MACHINES csv_reader = csv.reader(csv_file, delimiter='~', quotechar='^') # Get the teams sales_team_direct_sales_ID = sales_teams_obj.search(cr, uid, [('name', '=', 'Direct Sales')]) sales_team_0_ID = sales_teams_obj.search(cr, uid, [('name', '=', '0')]) sales_team_1_ID = sales_teams_obj.search(cr, uid, [('name', '=', '1')]) sales_team_2_ID = sales_teams_obj.search(cr, uid, [('name', '=', '2')]) sales_team_3_ID = sales_teams_obj.search(cr, uid, [('name', '=', '3')]) sales_team_4_ID = sales_teams_obj.search(cr, uid, [('name', '=', '4')]) sales_team_5_ID = sales_teams_obj.search(cr, uid, [('name', '=', '5')]) sales_team_6_ID = sales_teams_obj.search(cr, uid, [('name', '=', '6')]) sales_team_7_ID = sales_teams_obj.search(cr, uid, [('name', '=', '7')]) sales_team_8_ID = sales_teams_obj.search(cr, uid, [('name', '=', '8')]) sales_team_9_ID = sales_teams_obj.search(cr, uid, [('name', '=', '9')]) # Search for the titles, create them if they do not exist damen_und_herren_title_ID = res_partner_title_obj.search(cr, uid, [('name', '=', 'Sehr geehrte Damen und Herren')]) if not damen_und_herren_title_ID: damen_und_herren_title_ID = res_partner_title_obj.create(cr, uid, {'name':'Sehr geehrte Damen und Herren'}) if type(damen_und_herren_title_ID) is list: damen_und_herren_title_ID = damen_und_herren_title_ID[0] frau_title_ID = res_partner_title_obj.search(cr, uid, [('name', '=', 'Sehr geehrte Frau')]) if not frau_title_ID: frau_title_ID = res_partner_title_obj.create(cr, uid, {'name':'Sehr geehrte Frau'}) if type(frau_title_ID) is list: frau_title_ID = frau_title_ID[0] herr_title_ID = res_partner_title_obj.search(cr, uid, [('name', '=', 'Sehr geehrter Herr')]) if not herr_title_ID: herr_title_ID = res_partner_title_obj.create(cr, uid, {'name':'Sehr geehrter Herr'}) if type(herr_title_ID) is list: herr_title_ID = herr_title_ID[0] account_type_id = account_account_type_obj.search(cr, uid, [('name', '=', 'Receivable')]) # Checking to see whether there exists the "1200 - Forderungen aus Lieferungen und Leistungen account" forderungen_account = account_account_obj.search(cr, uid, [('code', '=', 1200)]) if type(forderungen_account) is list and len(forderungen_account) > 0: forderungen_account = forderungen_account[0] account_payable_ID = account_account_obj.search(cr, uid, [('code', '=', 'Kunden - Diverse1')]) if type(account_payable_ID) is list: account_payable_ID = account_payable_ID[0] next(csv_reader, None) # To skip header row. row_counter = 2 empty_name_counter = 0 for row in csv_reader: print 'PROCESS IN ROW: ' + str(row_counter) final_customer_name = None if len(str(row[15]).strip()) > 0: # If Firma is not empty, customer's name == Firma + Zusatz final_customer_name = row[15] + ' ' + row[64] else: # If Firma is empty, customer's name == Vorname + Name final_customer_name = row[63] + ' ' + row[45] if final_customer_name: empty_name_counter += 1 logging.info("Customer name is " + str(final_customer_name)) # search for the customer's existance, if exists do not add her customer_id = res_partner_obj.search(cr, uid, [('name', '=', final_customer_name)]) print 'Searching with customer name ' + final_customer_name if not customer_id: # Customer does not exist, only then make the calls # Fields with relations that must be treated in a special way # x_kundengruppe, country_id, name print 'customer.kundengruppe ' + str(row[6]) x_kundengruppe_id = customer_kunden_obj.search(cr, uid, [('name', '=', row[6].decode('utf8'))]) if not x_kundengruppe_id: # kundergruppe does not exist (create a record on the model customer.kundengruppe and store its id) print 'Creating kundengruppe' x_kundengruppe_id = customer_kunden_obj.create(cr, uid, {'name':row[6]}) country_id = [] if str(row[27]).strip(): if str(row[27]) == 'Great Britain': country_id = res_country_obj.search(cr, uid, [('name', '=', 'United Kingdom')]) else: country_id = res_country_obj.search(cr, uid, [('name', '=', row[27])]) mittarbeitergrupe = None if row[16] == '0 bis 4': mittarbeitergrupe = '0_4' elif row[16] == '5 bis 9': mittarbeitergrupe = '5_9' elif row[16] == '10 bis 19': mittarbeitergrupe = '10_19' elif row[16] == '20 bis 34': mittarbeitergrupe = '20_34' elif row[16] == '35 bis 49': mittarbeitergrupe = '35_49' elif row[16] == '50 bis 99': mittarbeitergrupe = '50_99' elif row[16] == 'über 100': mittarbeitergrupe = 'uber_100' final_customer_number_list = [] final_customer_number = None print row[10] if len(row[10]) < 8: # Get row[10] length. Subtract it from 8. That's how many zeros must be put. Create a new string with zeros in front and number postfixed zeros = 8 - len(row[10]) # final_customer_number_list.append('\'') for y in range(0, zeros): final_customer_number_list.append(str(0)) final_customer_number_list.append(str(row[10])) # final_customer_number_list.append('\'') final_customer_number = ''.join(final_customer_number_list) print 'Customer\'s number length < 8. Prefixing ' + str(zeros) + ' zeros' print 'final x_customer_number: ' + str(final_customer_number) else: final_customer_number = str(row[10]) # Make the country_id from an array to a single int variable if len(country_id) > 0: print 'SETTING COUNTRY ID TO ' + str(country_id) country_id = country_id[0] if type(x_kundengruppe_id) is list and len(x_kundengruppe_id) > 0: x_kundengruppe_id = x_kundengruppe_id[0] comment_section = self.assemble_internal_log(row) final_title = self.assemble_customer_title(row, damen_und_herren_title_ID, frau_title_ID, herr_title_ID) # Check x_mitarbeiter if len(row[2].strip()) == 0: row[2] = 0 else: row[2] = int(row[2]) fields_to_be_inserted = { 'x_kundengruppe':x_kundengruppe_id, 'x_customer_number':final_customer_number, # (customer number cannot be less than 8 digits) 'vat':row[12], 'email':row[14], 'name':final_customer_name, 'x_mittarbeitergruppe':mittarbeitergrupe, 'title':final_title, 'x_a_kunde':row[23], 'website':row[24], 'country_id':country_id, 'mobile':filter(lambda x: x.isdigit(), row[44]), 'city':row[46], 'zip':row[49], 'function':str(row[50]), 'street':row[57] + str(row[21]), # street and House No 'fax':filter(lambda x: x.isdigit(), row[59]), 'phone':filter(lambda x: x.isdigit(), row[60]), 'comment':comment_section, 'x_mitarbeiter':row[2], 'property_account_payable':account_payable_ID, } log_entries = [] # column_index_list = [67, 68, 76, 77, 85, 86, 94, 95, 103, 104, 112, 113, 121, 122, 130, 131, 139, 140, 148, 149, 157, 158, 166, 167, 175, 176, 184, 185, 193, 194, 202, 203, 211, 212, 220, 221, 229, 230, 238, 239, 247, 248] column_index_list = [67, 76, 85, 94, 103, 112, 121, 130, 139, 148, 157, 166, 175, 184, 193, 202, 211, 220, 229, 238, 247] # search through the CSV to find those fields that contain (log note/date) and put them in internal log for x in column_index_list: if len(row[x].strip()) > 0: print 'Log entry found, adding to the list' log_entries.append(row[x + 1] + '||||' + row[x]) if customer_id: # Customer exists, do not add her print 'Customer ' + final_customer_name + ' exists. We do not add this one.' logging.info('Customer ' + final_customer_name + ' exists. We do not add this one.') else: try: logging.info('Creating customer ' + str(final_customer_name) + ', ' + str(row[15])) created_customer_id = res_partner_obj.create(cr, uid, fields_to_be_inserted) print 'CREATED CUSTOMER: ' + str(final_customer_name) + ' ID: ' + str(created_customer_id) sales_team_id = None # If PLZ field is not empty and is a 5 digit number if row[49] and str(row[49]).isdigit() and len(str(row[49])) == 5: # Check the first digit and assign to it a Sales Team if int(str(row[49])[0]) == 1: sales_team_id = sales_team_1_ID elif int(str(row[49])[0]) == 2: sales_team_id = sales_team_2_ID elif int(str(row[49])[0]) == 3: sales_team_id = sales_team_3_ID elif int(str(row[49])[0]) == 4: sales_team_id = sales_team_4_ID elif int(str(row[49])[0]) == 5: sales_team_id = sales_team_5_ID elif int(str(row[49])[0]) == 6: sales_team_id = sales_team_6_ID elif int(str(row[49])[0]) == 7: sales_team_id = sales_team_7_ID elif int(str(row[49])[0]) == 8: sales_team_id = sales_team_8_ID elif int(str(row[49])[0]) == 9: sales_team_id = sales_team_9_ID # If the PLZ field is not empty and is a 4 digit number elif row[49] and str(row[49]).isdigit() and len(str(row[49])) == 4: # int(row[49]) >= 0 and int(row[49]) <= 9999: sales_team_id = sales_team_0_ID # Everything else goes to the Direct Sales team else: sales_team_id = sales_team_direct_sales_ID if len(sales_team_id) > 0: print 'SECTION ID: ' + str(sales_team_id) res_partner_obj.write(cr, uid, created_customer_id, {'section_id':str(sales_team_id[0])}) # personal account for each customer # Check if account exists for certain customer account_id = account_account_obj.search(cr, uid, [('name', '=', final_customer_name)]) if not account_id: print 'Creating and linking new account for customer ' + final_customer_name + ' CODE: ' + str(row[10]) # Creating account (parent_id can be empty. If so, do not change the parent_id field; let it be) account_id = account_account_obj.create(cr, uid, {'code': row[10], 'name': final_customer_name, 'type':'receivable', 'user_type': account_type_id[0], 'parent_id': forderungen_account }) # In any case assign the account to the customer if type(account_id) is list: account_id = account_id[0] print 'ACCOUNT ID TO LINK' + str(account_id) res_partner_obj.write(cr, uid, created_customer_id, {'property_account_receivable':account_id}) except Exception, e: #pass print '===> ERROR ' + str(e) # If error on account creation, no problem keep going for log_entry in log_entries: log = log_entry.split('||||', 2) crm_phonecall_obj.create(cr, uid, {'date':log[0], 'name':log[1], 'state':'done', 'partner_id':created_customer_id}) if time.time() - start_time > 500: print '500 secs passed' return None row_counter += 1 #return None
product_id_change return can't update fields.selection to form
product_id_change return can't update form of fields.selection...? columns={ 'expr_date':fields.selection('Expire Date',type='selection'),} def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, uom=False, qty_uos=0, uos=False, name='', partner_id=False, lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False, context=None): lang = lang or context.get('lang', False) if not partner_id: raise osv.except_osv(_('No Customer Defined!'), _('Before choosing a product,\n select a customer in the sales form.')) warning = {} product_uom_obj = self.pool.get('product.uom') partner_obj = self.pool.get('res.partner') product_obj = self.pool.get('product.product') context = {'lang': lang, 'partner_id': partner_id} if partner_id: lang = partner_obj.browse(cr, uid, partner_id).lang context_partner = {'lang': lang, 'partner_id': partner_id} if not product: return {'value': {'th_weight': 0, 'product_uos_qty': qty}, 'domain': {'product_uom': [], 'product_uos': []}} if not date_order: date_order = time.strftime(DEFAULT_SERVER_DATE_FORMAT) result = {} warning_msgs = '' product_obj = product_obj.browse(cr, uid, product, context=context_partner) uom2 = False if uom: uom2 = product_uom_obj.browse(cr, uid, uom) if product_obj.uom_id.category_id.id != uom2.category_id.id: uom = False if uos: if product_obj.uos_id: uos2 = product_uom_obj.browse(cr, uid, uos) if product_obj.uos_id.category_id.id != uos2.category_id.id: uos = False else: uos = False fpos = fiscal_position and self.pool.get('account.fiscal.position').browse(cr, uid, fiscal_position) or False if update_tax: # The quantity only have changed result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, fpos, product_obj.taxes_id) if not flag: result['name'] = self.pool.get('product.product').name_get(cr, uid, [product_obj.id], context=context_partner)[0][1] if product_obj.description_sale: result['name'] += '\n' + product_obj.description_sale domain = {} if (not uom) and (not uos): result['product_uom'] = product_obj.uom_id.id if product_obj.uos_id: result['product_uos'] = product_obj.uos_id.id result['product_uos_qty'] = qty * product_obj.uos_coeff uos_category_id = product_obj.uos_id.category_id.id else: result['product_uos'] = False result['product_uos_qty'] = qty uos_category_id = False result['th_weight'] = qty * product_obj.weight domain = {'product_uom': [('category_id', '=', product_obj.uom_id.category_id.id)], 'product_uos': [('category_id', '=', uos_category_id)]} elif uos and not uom: # only happens if uom is False result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id result['product_uom_qty'] = qty_uos / product_obj.uos_coeff result['th_weight'] = result['product_uom_qty'] * product_obj.weight elif uom: # whether uos is set or not default_uom = product_obj.uom_id and product_obj.uom_id.id q = product_uom_obj._compute_qty(cr, uid, uom, qty, default_uom) if product_obj.uos_id: result['product_uos'] = product_obj.uos_id.id result['product_uos_qty'] = qty * product_obj.uos_coeff else: result['product_uos'] = False result['product_uos_qty'] = qty result['th_weight'] = q * product_obj.weight # Round the quantity up if not uom2: uom2 = product_obj.uom_id # get unit price if not pricelist: warn_msg = _('You have to select a pricelist or a customer in the sales form !\n' 'Please set one before choosing a product.') warning_msgs += _("No Pricelist ! : ") + warn_msg + "\n\n" else: price = self.pool.get('product.pricelist').price_get(cr, uid, [pricelist], product, qty or 1.0, partner_id, { 'uom': uom or result.get('product_uom'), 'date': date_order, })[pricelist] if price is False: warn_msg = _("Cannot find a pricelist line matching this product and quantity.\n" "You have to change either the product, the quantity or the pricelist.") warning_msgs += _("No valid pricelist line found ! :") + warn_msg + "\n\n" else: result.update({'price_unit': price}) cr.execute("select s.expr_date from stock_move s where s.product_id= %s", (product,)) date_all=[] data=cr.fetchall() print data for date in data: date_all.append((' ',date)) result.update({'expr_date':date_all}) print 'Expr Date is ..................',result if warning_msgs: warning = { 'title': _('Configuration Error!'), 'message' : warning_msgs } return {'value':result, 'domain': domain, 'warning': warning}