I want to make changes to the purchase order report in OpenERP 6.1. Do I have to go in and make changes to the purchase module, or can I create a new module that will inherit the standard report and override some details.
问题:
回答1:
You can't exactly inherit another report and just override some details, but you can replace a standard report and make all existing links to it launch your new report instead.
Our zaber_purchase module contains some changes to the purchase order report that our users wanted. Here's the purchase_report.xml file that replaces the standard report with ours.
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<report
auto="False"
id="purchase.report_purchase_order"
model="purchase.order"
name="purchase.order.zaber"
rml="zaber_purchase/report/order.rml"
string="Purchase Order"
usage="default"/>
</data>
</openerp>
Since it's not inheriting but replacing the report, you have to duplicate the whole report in your version. Your report's id has to match the original report's id, including the module name. In the example above, the original report has an id of report_purchase_order
, and it's part of the purchase
module, so your report id must be purchase.report_purchase_order
to replace it. The name has to match the name in your version's parser file, and the rml attribute has to point to your version's RML file.
Thanks to mihai for explaining most of this in the OpenERP forum.
回答2:
Don Kirkby has a good answer, and after banging my head on a wall for an hour, I'd like to expand it. But stackoverflow, in all its wisdom, won't let me comment on it because I don't have enough rep points, so instead, I'll spam the question with an unanswer.
By "The id has to match the original report's id, including the module name," Don means that if foomodule has <report id="fooreport" ...>
, then in your module you will need to say <report id="foomodule.fooreport" ...>
. This is because the ids declared by each module live in a namespace scoped to that module. If you don't reference the other (the one you are overriding) module's namespace, then you just end up creating a new report with the same name which is Bad.
For kicks, check out the database tables ir_act_report_xml
, which has all the reports, and ir_model_data
, which associates reports (and everything else) with the id
attribute from the XML that defined the thing.
回答3:
RML parser classes are registered globally as Services. For example the Sale Order parser class is registered in addons/sale/report/sale_order.py with
report_sxw.report_sxw('report.sale.order', 'sale.order', 'addons/sale/report/sale_order.rml', parser=order, header="external")
If you try to create another parser with the same name, you get an error : The report "sale.order" already exists!
A simple way to replace the sale.order parser and use a custom parser class is to remove it from the global service registry with :
from netsvc import Service
del Service._services['report.sale.order']
Here is a full example we used to conditionally hide the Discount column in the sale order report if there is no discount
from sale.report import sale_order
from report import report_sxw
# create a custom parser inherited from sale order parser:
class new_order_parser(sale_order.order):
'''Custom parser with an additional method
'''
def __init__(self, cr, uid, name, context):
super(new_order_parser, self).__init__(cr, uid, name, context=context)
self.localcontext.update({
'has_line_discount': self._has_line_discount,
})
def _has_line_discount(self, order):
return any([l.discount for l in order.order_line])
# remove previous sale.report service :
from netsvc import Service
del Service._services['report.sale.order']
# register the new report service :
report_sxw.report_sxw(
'report.sale.order',
'sale.order',
'addons/path/to/the/sale_order.rml',
parser=new_order_parser
)