【问题标题】:How can i generate xls report in odoo如何在 odoo 中生成 xls 报告
【发布时间】:2016-06-06 06:44:48
【问题描述】:

我想使用 odoo 8 中的 Excel 报告引擎生成我自己的 excel 报告。有人请给我一个简单的 excel 报告示例或任何帮助 URL。我会非常感谢你....

【问题讨论】:

    标签: openerp odoo-8 odoo-9 odoo-view


    【解决方案1】:

    这是一段简单的代码。互联网上确实有很多例子,都有很好的解释。我建议您详细查看代码以查看它是如何工作的(顺便说一下,我也从某个地方复制了代码 - 我不记得在哪里。还可以在这里查看示例:https://github.com/OCA/reporting-engine/tree/8.0 版本 8 分支也有很多例子。

    您可以通过编辑“my_change”变量来添加列。

    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 {}
    

    解析器的代码如下。

    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")
    

    xml 文件将如下所示以设置必要的操作等。

    <?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>
    

    【讨论】:

    • 先生,它给我一个错误,请检查一下。 <_report_xls_fields>,_report_xls_fields() 需要至少 3 个参数(给定 2 个), >
    • 很难从您的 cmets 中看出您做错了什么。我看不到您是如何实现上述内容的。我怀疑您用来调用报告的操作不正确,或者您错误地实现了模块。我将做什么,我将粘贴另一个示例,其中包含用于实现上述内容的代码。第二个示例不是很安全,因为我直接从 SQL 数据库中提取数据。但你会明白的。
    • 先生,这段代码对我来说运行良好,但我想从 2 个不同的模型中选择值,比如我想从 event.event 和 event.registration 中选择值,那么什么改变对我有帮助???有可能通过这种方式吗???先生请告诉我这件事。我会非常感谢你...
    • 如果您通过其他解决方案中的代码工作,您将能够看到如何编译出现在模块中的必要数据。我建议您使用 your_obj = self.pool.get(...) 和 your_obj.browse 的组合来循环所有信息,而不是我使用的 sql 代码。你可以像这样访问多个对象。
    • 谢谢@DirkvanderMerwe:你拯救了我的一天!! :)
    【解决方案2】:

    第二个例子。首先是创建一个按钮的xml。这只是一个摘录。

    <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>
    

    下面的代码是一个带有几个按钮的向导。我删除了一些代码以节省空间。报告通过按钮激活:

    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()
    

    这是解析器的代码:

    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)
    

    【讨论】:

    • 我忘记添加了。记得导入所有必要的模块: 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 from xlwt.Style import default_style
    【解决方案3】:

    创建 Excel 文件或电子表格

    “导入 xlwt” 包功能在你的 Py 文件中创建工作表。我们可以使用 xlwt.easyxf() 定义标题、标题、编号、日期和普通样式。

    例如标题样式如下 new_style = xlwt.easyxf('font:height 230; align: wrap No;border: top粗;border:bottom粗;')

    定义边框的显示方式。定义工作簿。工作簿实际上是我们在电子表格中查看的内容。 要定义工作簿, wbk = xlwt.Workbook() sheet = wbk.add_sheet('New_sheet', cell_overwrite_ok=True) 用于写入工作表 sheet.write(4, 4, ‘Spellbound Soft Solution’,font_size) 要更改单元格的宽度和高度, sheet.col(1).width = 500*12 sheet.row(5).height = 70*5

    更多转到: http://spellboundss.com/xls-report-in-odoo/ 谢谢

    【讨论】:

      【解决方案4】:
      • 只需从应用商店添加这个report_xlsx 模块。
      • your_module_name --> 报告--> my_report.py
      • your_module_name --> 报告--> 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"
       />`
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多