-->

custom report through python odoo 9

2020-03-26 06:53发布

问题:

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

回答1:

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.



回答2:

Below is the code to create a custom Model report which is wrapped on v9 API. Creating custom object report is three step process

  1. Create RML Prase Custom Report Object
  2. Wrap RML Report to AbstractModel Report for qweb engine.
  3. Design template for the custom object.
  4. Register your under report registry.

All Four Part listed here with possible sample code.

RML Prase Custom Report Object

import time
from openerp.osv import osv
from openerp.report import report_sxw


class CustomReportPrint(report_sxw.rml_parse):

    def __init__(self, cr, uid, name, context):
        super(CustomReportPrint, self).__init__(cr, uid, name, context=context)
        self.localcontext.update({
            'time': time,
            'lst': self._lst,
            'total': self._some_total,
            'get_records':self._get_records,
        })

    def _get_records(self, res_ids):
        records = self.pool.get('res.partner').browse(self.cr, self.uid, res_ids)
        return records

    def _lst(self, employee_id, dt_from, dt_to, max, *args):
        #Your code goes here
        return res

    def _some_total(self, employee_id, dt_from, dt_to, max, *args):
        #Your code goes here
        return [result_dict]

Wrapping RML Prase Object tot he QWeb Engine.

class report_custom_print(osv.AbstractModel):
    _name = 'report.<module_name>.report_custom_print'
    _inherit = 'report.abstract_report'
    _template = '<module_name>.report_custom_print'
    _wrapped_report_class = CustomReportPrint

Report XML look as below as you can see I am calling get_records from custom report model.

<?xml version="1.0" encoding="utf-8"?>
<openerp>
    <data>
        <template id="report_custom_print">
            <t t-call="report.html_container">
                <t t-foreach="get_records(data['form']['res_ids'])" t-as="employee">
                    <t t-call="report.internal_layout">
                        <div class="page">
                            <div class="oe_structure" />
                        </div>
                    </t>
                </t>
            </t>
        </template>
    </data>
</openerp>

Registering Report

    <record id="action_report_custom_print" model="ir.actions.report.xml">
        <field name="name">Custom Print Report</field>
        <field name="report_type">qweb-pdf</field>
        <field name="model">res.partner</field>
        <field name="report_name"><module_name>.report_custom_print</field>
        <field name="report_file"><module_name>.report_custom_print</field>
    </record>

In custom Rml report Object you can define as many functions as you like and register them under __int__ and you can call those function directly on yor rpeort and mutpllate data as you need.

PS: replace with your module to make wit works correct.

Hope this will help.