Search code examples
pythonodooodoo-8wkhtmltopdfodoo-9

custom report through python odoo 9


How to pass multiple module data to a QWeb report? Is there something similar to passing dictionary in rendering html from controller?

class account(model.Models):
    _name = 'account.main'      

    name = fields.Char()


class accountSub(model.Models):
    _name = 'account.sub'

    name = fields.Char()    

class PrintWizard(model.Models):
    _name = 'print.report'


    account = fields.Many2one('erp.account')

    @api.multi
    def print_report(self):
       ctx = self.env.context.copy()
       ctx.update({'domain':[('name','=',self.account.name)]})
       self.with_context(ctx)
       return {'name': 'Report',
            'type': 'ir.actions.report.xml',
            'report_name': 'erp.report_id',
            'report_type': 'qweb-pdf'}


class ErpReport(models.AbstractModel):
   _name = "report.erp.report_id"

   @api.multi
   def print_report(self)
       domain = self.env.context.get('domain')
       print(domain) #Print result was None
       main = self.env['account.main'].search(domain)
       sub = self.env['account.sub'].search([])
       docs = {
          'docs1': main,
          'docs2': sub,
       }
       return self.env['report'].render('erp.report', docs)

QWeb

<report
    id="report_id"
    string="Report"
    model="erp.report"
    report_type="qweb-pdf"
    file="erp.report"
    name="erp.report"
/>

<template id="payment_slip">
    <t t-call="nationalerp_sales.erp_external_layout">
        <t t-call="report.html_container">
            <div class="page">
                <div>
                    <t t-foreach="docs1" t-as="main">
                        <t t-esc="main.name"/>
                    </t>
                    <t t-foreach="docs2" t-as="sub">
                        <t t-esc="sub.name"/>
                    </t>
                </div>
            </div>
        </t>
    </t>
</template>

Passing data through context is not working. i tried to print the domain in abstract class it return none. but in my wizard it's okay


Solution

  • If you want to run specific code before your report prints or pass custom data to your template for rendering you can create an Abstract model which defines a render_html function so that your function will run when printing the report rather than the generic odoo function. This is referenced in the documentation HERE

    Take a look at this example.

    from openerp import models, fields, api, exceptions
    
    class YourReport(models.AbstractModel):
        _name = 'report.your_addon.report_template_id'
    
        @api.multi
        def render_html(self, data=None):
            report_obj = self.env['report']
            report = report_obj._get_report_from_name('your_addon.report_template_id')
            model1_docs = self.env['your_addon.your_model1'].search([('something','=','something')])
            model2_docs = self.env['your_addon.your_model2'].search([('something','=','something')])   
            docargs = {
                'doc_model': report.model,
                'model1_docs': model1_docs,
                'model2_docs': model2_docs,
            }
            return report_obj.render('your_addon.report_template_id', docargs)
    

    UPDATE WITH MODIFIED CONTEXT:

    To call your report with a modified context try the following (untested). I could not find any examples of calling reports with modified context however did not look extensively.

    ctx = self.env.context.copy()
    ctx.update({'domain':[('something','=','something')]})
    self.with_context(ctx)
    return {
        'name':'Report',
        'type':'ir.actions.report.xml,
        'report_name':'your_addon.report_template_id',
        'report_type':'qweb-pdf'
    }
    

    Then from within your report function we defined earlier you should be able to access context through your environment.

    domain = self.env.context.get('domain')
    

    You will need to create a function in your wizard which calls the report passing the context.