diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 35bf08d1542..47d0032751f 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -434,7 +434,7 @@ class AccountBankStatement(models.Model): # Bank statement report. if statement.journal_id.type == 'bank': - content, content_type = self.env.ref('account.action_report_account_statement')._render(statement.id) + content = self.env["ir.actions.report"]._render_qweb_pdf('account.action_report_account_statement', statement.id)[0] self.env['ir.attachment'].create({ 'name': statement.name and _("Bank Statement %s.pdf", statement.name) or _("Bank Statement.pdf"), 'type': 'binary', diff --git a/addons/account/models/ir_actions_report.py b/addons/account/models/ir_actions_report.py index 19701e6347e..42525221ea2 100644 --- a/addons/account/models/ir_actions_report.py +++ b/addons/account/models/ir_actions_report.py @@ -11,10 +11,10 @@ from odoo.tools import pdf class IrActionsReport(models.Model): _inherit = 'ir.actions.report' - def _render_qweb_pdf_prepare_streams(self, data, res_ids=None): + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): # Custom behavior for 'account.report_original_vendor_bill'. - if self.report_name != 'account.report_original_vendor_bill': - return super()._render_qweb_pdf_prepare_streams(data, res_ids=res_ids) + if self._get_report(report_ref).report_name != 'account.report_original_vendor_bill': + return super()._render_qweb_pdf_prepare_streams(report_ref, data, res_ids=res_ids) invoices = self.env['account.move'].browse(res_ids) if any(x.move_type not in ('in_invoice', 'in_receipt') for x in invoices): @@ -44,11 +44,11 @@ class IrActionsReport(models.Model): } return collected_streams - def _render_qweb_pdf(self, res_ids=None, data=None): + def _render_qweb_pdf(self, report_ref, res_ids=None, data=None): # Check for reports only available for invoices. - if self.report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): + if self._get_report(report_ref).report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): invoices = self.env['account.move'].browse(res_ids) if any(x.move_type == 'entry' for x in invoices): raise UserError(_("Only invoices could be printed.")) - return super()._render_qweb_pdf(res_ids=res_ids, data=data) + return super()._render_qweb_pdf(report_ref, res_ids=res_ids, data=data) diff --git a/addons/account_edi/models/ir_actions_report.py b/addons/account_edi/models/ir_actions_report.py index 611849d34e9..4feeff1674e 100644 --- a/addons/account_edi/models/ir_actions_report.py +++ b/addons/account_edi/models/ir_actions_report.py @@ -9,14 +9,14 @@ from odoo.tools.pdf import OdooPdfFileReader, OdooPdfFileWriter class IrActionsReport(models.Model): _inherit = 'ir.actions.report' - def _render_qweb_pdf_prepare_streams(self, data, res_ids=None): + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): # EXTENDS base - collected_streams = super()._render_qweb_pdf_prepare_streams(data, res_ids=res_ids) + collected_streams = super()._render_qweb_pdf_prepare_streams(report_ref, data, res_ids=res_ids) if collected_streams \ and res_ids \ and len(res_ids) == 1 \ - and self.report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): + and self._get_report(report_ref).report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): invoice = self.env['account.move'].browse(res_ids) if invoice.is_sale_document() and invoice.state != 'draft': to_embed = invoice.edi_document_ids diff --git a/addons/account_edi_ubl_cii/models/ir_actions_report.py b/addons/account_edi_ubl_cii/models/ir_actions_report.py index 71328c46a9b..7b3529f8d1a 100644 --- a/addons/account_edi_ubl_cii/models/ir_actions_report.py +++ b/addons/account_edi_ubl_cii/models/ir_actions_report.py @@ -50,14 +50,14 @@ class IrActionsReport(models.Model): 'mimetype': 'application/xml', }) - def _render_qweb_pdf_prepare_streams(self, data, res_ids=None): + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): # EXTENDS base # Add the pdf report in the XML as base64 string. - collected_streams = super()._render_qweb_pdf_prepare_streams(data, res_ids=res_ids) + collected_streams = super()._render_qweb_pdf_prepare_streams(report_ref, data, res_ids=res_ids) if collected_streams \ and res_ids \ - and self.report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): + and self._get_report(report_ref).report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): for res_id, stream_data in collected_streams.items(): invoice = self.env['account.move'].browse(res_id) self._add_pdf_into_invoice_xml(invoice, stream_data) diff --git a/addons/hr/tests/test_multi_company.py b/addons/hr/tests/test_multi_company.py index 13e181aad72..5fa51f17f50 100644 --- a/addons/hr/tests/test_multi_company.py +++ b/addons/hr/tests/test_multi_company.py @@ -28,14 +28,14 @@ class TestMultiCompany(TestHrCommon): cls.env.invalidate_all() def test_multi_company_report(self): - content, content_type = self.env.ref('hr.hr_employee_print_badge').with_user(self.res_users_hr_officer).with_context( + content, _ = self.env['ir.actions.report'].with_user(self.res_users_hr_officer).with_context( allowed_company_ids=[self.company_1.id, self.company_2.id] - )._render_qweb_pdf(res_ids=self.employees.ids) + )._render_qweb_pdf('hr.hr_employee_print_badge', res_ids=self.employees.ids) self.assertIn(b'Bidule', content) self.assertIn(b'Machin', content) def test_single_company_report(self): with self.assertRaises(QWebException): # CacheMiss followed by AccessError - content, content_type = self.env.ref('hr.hr_employee_print_badge').with_user(self.res_users_hr_officer).with_company( + self.env['ir.actions.report'].with_user(self.res_users_hr_officer).with_company( self.company_1 - )._render_qweb_pdf(res_ids=self.employees.ids) + )._render_qweb_pdf('hr.hr_employee_print_badge', res_ids=self.employees.ids) diff --git a/addons/l10n_ch/models/ir_actions_report.py b/addons/l10n_ch/models/ir_actions_report.py index 469b93e7d61..dcc1dd4b74e 100644 --- a/addons/l10n_ch/models/ir_actions_report.py +++ b/addons/l10n_ch/models/ir_actions_report.py @@ -27,11 +27,14 @@ class IrActionsReport(models.Model): qr_cross = ReportLabImage((width/2 - cross_width/2) / mm, (height/2 - cross_height/2) / mm, cross_width / mm, cross_height / mm, cross_path.as_posix()) barcode_drawing.add(qr_cross) - def _render_qweb_pdf_prepare_streams(self, data, res_ids=None): + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): # OVERRIDE - res = super()._render_qweb_pdf_prepare_streams(data, res_ids) - if res_ids and self.report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): - invoices = self.env[self.model].browse(res_ids) + res = super()._render_qweb_pdf_prepare_streams(report_ref, data, res_ids) + if not res_ids: + return res + report = self._get_report(report_ref) + if report.report_name in ('account.report_invoice_with_payments', 'account.report_invoice'): + invoices = self.env[report.model].browse(res_ids) # Determine which invoices need a QR/ISR. qr_inv_ids = [] isr_inv_ids = [] @@ -45,11 +48,11 @@ class IrActionsReport(models.Model): # Render the additional reports. streams_to_append = {} if qr_inv_ids: - qr_res = self.env.ref('l10n_ch.l10n_ch_qr_report')._render_qweb_pdf_prepare_streams(data, res_ids=qr_inv_ids) + qr_res = self._render_qweb_pdf_prepare_streams('l10n_ch.l10n_ch_qr_report', data, res_ids=qr_inv_ids) for invoice_id, stream in qr_res.items(): streams_to_append[invoice_id] = stream if isr_inv_ids: - isr_res = self.env.ref('l10n_ch.l10n_ch_isr_report')._render_qweb_pdf_prepare_streams(data, res_ids=isr_inv_ids) + isr_res = self._render_qweb_pdf_prepare_streams('l10n_ch.l10n_ch_isr_report', data, res_ids=isr_inv_ids) for invoice_id, stream in isr_res.items(): streams_to_append[invoice_id] = stream # Add to results diff --git a/addons/l10n_de/models/ir_actions_report.py b/addons/l10n_de/models/ir_actions_report.py index bc3c499b68c..2590b75a98f 100644 --- a/addons/l10n_de/models/ir_actions_report.py +++ b/addons/l10n_de/models/ir_actions_report.py @@ -4,7 +4,7 @@ from odoo import models class IrActionsReport(models.Model): _inherit = 'ir.actions.report' - def _get_rendering_context(self, docids, data): - data = super()._get_rendering_context(docids, data) - data['din_header_spacing'] = self.get_paperformat().header_spacing + def _get_rendering_context(self, report, docids, data): + data = super()._get_rendering_context(report, docids, data) + data['din_header_spacing'] = report.get_paperformat().header_spacing return data diff --git a/addons/l10n_it_edi/models/account_invoice.py b/addons/l10n_it_edi/models/account_invoice.py index 94493f03639..5224cdee825 100644 --- a/addons/l10n_it_edi/models/account_invoice.py +++ b/addons/l10n_it_edi/models/account_invoice.py @@ -148,7 +148,7 @@ class AccountMove(models.Model): # b64encode returns a bytestring, the template tries to turn it to string, # but only gets the repr(pdf) --> "b''" - pdf = self.env.ref('account.account_invoices')._render_qweb_pdf(self.id)[0] + pdf = self.env['ir.actions.report']._render_qweb_pdf("account.account_invoices", self.id)[0] pdf = base64.b64encode(pdf).decode() pdf_name = re.sub(r'\W+', '', self.name) + '.pdf' diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index fd218432266..a649235c51a 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -223,18 +223,18 @@ class MailTemplate(models.Model): report_service = report.report_name if report.report_type in ['qweb-html', 'qweb-pdf']: - result, format = report._render_qweb_pdf([res_id]) + result, report_format = self.env['ir.actions.report']._render_qweb_pdf(report, [res_id]) else: - res = report._render([res_id]) + res = self.env['ir.actions.report']._render(report, [res_id]) if not res: raise UserError(_('Unsupported report type %s found.', report.report_type)) - result, format = res + result, report_format = res # TODO in trunk, change return format to binary to match message_post expected format result = base64.b64encode(result) if not report_name: report_name = 'report.' + report_service - ext = "." + format + ext = "." + report_format if not report_name.endswith(ext): report_name += ext attachments.append((report_name, result)) diff --git a/addons/mrp/tests/test_stock_report.py b/addons/mrp/tests/test_stock_report.py index 6a9fda5749e..6751a6d02c2 100644 --- a/addons/mrp/tests/test_stock_report.py +++ b/addons/mrp/tests/test_stock_report.py @@ -241,8 +241,8 @@ class TestMrpStockReports(TestReportsCommon): move.move_line_ids.result_package_id = self.env['stock.quant.package'].create({'name': 'Package0001'}) picking.button_validate() - report = self.env['ir.actions.report']._get_report_from_name('stock.report_deliveryslip') - html_report = report._render_qweb_html(picking.ids)[0].decode('utf-8').split('\n') + html_report = self.env['ir.actions.report']._render_qweb_html( + 'stock.report_deliveryslip', picking.ids)[0].decode('utf-8').split('\n') keys = [ "Package0001", "Compo 03", "Products with no package assigned", "Compo 01", "Compo 02", diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py index 4341b597f01..35a29c8a20c 100644 --- a/addons/point_of_sale/controllers/main.py +++ b/addons/point_of_sale/controllers/main.py @@ -82,7 +82,7 @@ class PosController(http.Controller): @http.route('/pos/sale_details_report', type='http', auth='user') def print_sale_details(self, date_start=False, date_stop=False, **kw): r = request.env['report.point_of_sale.report_saledetails'] - pdf, _ = request.env.ref('point_of_sale.sale_details_report').with_context(date_start=date_start, date_stop=date_stop)._render_qweb_pdf(r) + pdf, _ = request.env['ir.actions.report'].with_context(date_start=date_start, date_stop=date_stop)._render_qweb_pdf('point_of_sale.sale_details_report', r) pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))] return request.make_response(pdf, headers=pdfhttpheaders) diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 5a1f6bad543..2660bb65306 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -786,7 +786,7 @@ class PosOrder(models.Model): attachment = [(4, receipt.id)] if self.mapped('account_move'): - report = self.env.ref('account.account_invoices')._render_qweb_pdf(self.account_move.ids[0]) + report = self.env['ir.actions.report']._render_qweb_pdf("account.account_invoices", self.account_move.ids[0]) filename = name + '.pdf' invoice = self.env['ir.attachment'].create({ 'name': filename, diff --git a/addons/portal/controllers/portal.py b/addons/portal/controllers/portal.py index ca64e36dec5..7f1a47e4988 100644 --- a/addons/portal/controllers/portal.py +++ b/addons/portal/controllers/portal.py @@ -473,18 +473,15 @@ class CustomerPortal(Controller): if report_type not in ('html', 'pdf', 'text'): raise UserError(_("Invalid report type: %s", report_type)) - report_sudo = request.env.ref(report_ref).with_user(SUPERUSER_ID) - - if not isinstance(report_sudo, type(request.env['ir.actions.report'])): - raise UserError(_("%s is not the reference of a report", report_ref)) + ReportAction = request.env['ir.actions.report'].sudo() if hasattr(model, 'company_id'): if len(model.company_id) > 1: raise UserError(_('Multi company reports are not supported.')) - report_sudo = report_sudo.with_company(model.company_id) + ReportAction = ReportAction.with_company(model.company_id) method_name = '_render_qweb_%s' % (report_type) - report = getattr(report_sudo, method_name)(list(model.ids), data={'report_type': report_type})[0] + report = getattr(ReportAction, method_name)(report_ref, list(model.ids), data={'report_type': report_type})[0] reporthttpheaders = [ ('Content-Type', 'application/pdf' if report_type == 'pdf' else 'text/html'), ('Content-Length', len(report)), diff --git a/addons/sale/controllers/portal.py b/addons/sale/controllers/portal.py index 89dfd794767..75dcfa41008 100644 --- a/addons/sale/controllers/portal.py +++ b/addons/sale/controllers/portal.py @@ -234,7 +234,7 @@ class CustomerPortal(portal.CustomerPortal): order_sudo.action_confirm() order_sudo._send_order_confirmation_mail() - pdf = request.env.ref('sale.action_report_saleorder').with_user(SUPERUSER_ID)._render_qweb_pdf([order_sudo.id])[0] + pdf = request.env['ir.actions.report'].sudo()._render_qweb_pdf('sale.action_report_saleorder', [order_sudo.id])[0] _message_post_helper( 'sale.order', diff --git a/addons/sale_mrp/tests/test_sale_mrp_report.py b/addons/sale_mrp/tests/test_sale_mrp_report.py index c6d67de270d..3013d92f481 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_report.py +++ b/addons/sale_mrp/tests/test_sale_mrp_report.py @@ -64,7 +64,7 @@ class TestSaleMrpInvoices(common.TransactionCase): invoice = so._create_invoices() invoice.action_post() - report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments') - html = report._render_qweb_html(invoice.ids)[0] + html = self.env['ir.actions.report']._render_qweb_html( + 'account.report_invoice_with_payments', invoice.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By Lot\n1.00Units\nLOT0001', "There should be a line that specifies 1 x LOT0001") diff --git a/addons/sale_stock/controllers/portal.py b/addons/sale_stock/controllers/portal.py index 9cb1ee756b8..4bf4240f37f 100644 --- a/addons/sale_stock/controllers/portal.py +++ b/addons/sale_stock/controllers/portal.py @@ -29,8 +29,8 @@ class SaleStockPortal(CustomerPortal): except exceptions.AccessError: return request.redirect('/my') - # print report as SUPERUSER, since it require access to product, taxes, payment term etc.. and portal does not have those access rights. - pdf = request.env.ref('stock.action_report_delivery').with_user(SUPERUSER_ID)._render_qweb_pdf([picking_sudo.id])[0] + # print report with sudo, since it require access to product, taxes, payment term etc.. and portal does not have those access rights. + pdf = request.env['ir.actions.report'].sudo()._render_qweb_pdf('stock.action_report_delivery', [picking_sudo.id])[0] pdfhttpheaders = [ ('Content-Type', 'application/pdf'), ('Content-Length', len(pdf)), diff --git a/addons/sale_stock/tests/test_sale_stock_report.py b/addons/sale_stock/tests/test_sale_stock_report.py index 8cbe4afd471..a4d5b2211e3 100644 --- a/addons/sale_stock/tests/test_sale_stock_report.py +++ b/addons/sale_stock/tests/test_sale_stock_report.py @@ -151,8 +151,8 @@ class TestSaleStockInvoices(TestSaleCommon): line.quantity = 2 invoice.action_post() - report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments') - html = report._render_qweb_html(invoice.ids)[0] + html = self.env['ir.actions.report']._render_qweb_html( + 'account.report_invoice_with_payments', invoice.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By Lot\n2.00Units\nLOT0001', "There should be a line that specifies 2 x LOT0001") @@ -184,8 +184,8 @@ class TestSaleStockInvoices(TestSaleCommon): picking.move_ids.quantity_done = 4 picking.button_validate() - report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments') - html = report._render_qweb_html(invoice.ids)[0] + html = self.env['ir.actions.report']._render_qweb_html( + 'account.report_invoice_with_payments', invoice.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By Lot\n4.00Units\nLOT0001', "There should be a line that specifies 4 x LOT0001") @@ -196,7 +196,6 @@ class TestSaleStockInvoices(TestSaleCommon): Then, he delivers the other one and invoices it too. Each invoice should have the correct USN """ - report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments') display_lots = self.env.ref('stock_account.group_lot_on_invoice') display_uom = self.env.ref('uom.group_uom') self.env.user.write({'groups_id': [(4, display_lots.id), (4, display_uom.id)]}) @@ -226,20 +225,21 @@ class TestSaleStockInvoices(TestSaleCommon): backorder.move_ids.move_line_ids.qty_done = 1 backorder.button_validate() - html = report._render_qweb_html(invoice01.ids)[0] + IrActionsReport = self.env['ir.actions.report'] + html = IrActionsReport._render_qweb_html('account.report_invoice_with_payments', invoice01.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By USN\n1.00Units\nUSN0001', "There should be a line that specifies 1 x USN0001") self.assertNotIn('USN0002', text) invoice02 = so._create_invoices() invoice02.action_post() - html = report._render_qweb_html(invoice02.ids)[0] + html = IrActionsReport._render_qweb_html('account.report_invoice_with_payments', invoice02.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By USN\n1.00Units\nUSN0002', "There should be a line that specifies 1 x USN0002") self.assertNotIn('USN0001', text) # Posting the second invoice shouldn't change the result of the first one - html = report._render_qweb_html(invoice01.ids)[0] + html = IrActionsReport._render_qweb_html('account.report_invoice_with_payments', invoice01.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By USN\n1.00Units\nUSN0001', "There should still be a line that specifies 1 x USN0001") self.assertNotIn('USN0002', text) @@ -247,11 +247,11 @@ class TestSaleStockInvoices(TestSaleCommon): # Resetting and posting again the first invoice shouldn't change the results invoice01.button_draft() invoice01.action_post() - html = report._render_qweb_html(invoice01.ids)[0] + html = IrActionsReport._render_qweb_html('account.report_invoice_with_payments', invoice01.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By USN\n1.00Units\nUSN0001', "There should still be a line that specifies 1 x USN0001") self.assertNotIn('USN0002', text) - html = report._render_qweb_html(invoice02.ids)[0] + html = IrActionsReport._render_qweb_html('account.report_invoice_with_payments', invoice02.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By USN\n1.00Units\nUSN0002', "There should be a line that specifies 1 x USN0002") self.assertNotIn('USN0001', text) @@ -268,7 +268,6 @@ class TestSaleStockInvoices(TestSaleCommon): - Deliver 05 x Lot02 + 02 x Lot03 - Invoice 08 x P """ - report = self.env['ir.actions.report']._get_report_from_name('account.report_invoice_with_payments') display_lots = self.env.ref('stock_account.group_lot_on_invoice') display_uom = self.env.ref('uom.group_uom') self.env.user.write({'groups_id': [(4, display_lots.id), (4, display_uom.id)]}) @@ -333,7 +332,8 @@ class TestSaleStockInvoices(TestSaleCommon): line.quantity = 2 invoice01.action_post() - html = report._render_qweb_html(invoice01.ids)[0] + html = self.env['ir.actions.report']._render_qweb_html( + 'account.report_invoice_with_payments', invoice01.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By Lot\n2.00Units\nLOT0002', "There should be a line that specifies 2 x LOT0002") self.assertNotIn('LOT0001', text) @@ -355,7 +355,8 @@ class TestSaleStockInvoices(TestSaleCommon): invoice02 = so._create_invoices() invoice02.action_post() - html = report._render_qweb_html(invoice02.ids)[0] + html = self.env['ir.actions.report']._render_qweb_html( + 'account.report_invoice_with_payments', invoice02.ids)[0] text = html2plaintext(html) self.assertRegex(text, r'Product By Lot\n6.00Units\nLOT0002', "There should be a line that specifies 6 x LOT0002") self.assertRegex(text, r'Product By Lot\n2.00Units\nLOT0003', "There should be a line that specifies 2 x LOT0003") diff --git a/addons/snailmail/models/snailmail_letter.py b/addons/snailmail/models/snailmail_letter.py index 7c261a8787d..e6bc01809a4 100644 --- a/addons/snailmail/models/snailmail_letter.py +++ b/addons/snailmail/models/snailmail_letter.py @@ -138,7 +138,7 @@ class SnailmailLetter(models.Model): else: report_name = 'Document' filename = "%s.%s" % (report_name, "pdf") - pdf_bin, _ = report.with_context(snailmail_layout=not self.cover)._render_qweb_pdf(self.res_id) + pdf_bin, _ = self.env['ir.actions.report'].with_context(snailmail_layout=not self.cover)._render_qweb_pdf(report, self.res_id) attachment = self.env['ir.attachment'].create({ 'name': filename, 'datas': base64.b64encode(pdf_bin), diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 1ddd7e1de83..fe0d182ffeb 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -1544,7 +1544,7 @@ class Picking(models.Model): def _attach_sign(self): """ Render the delivery report in pdf and attach it to the picking in `self`. """ self.ensure_one() - report = self.env.ref('stock.action_report_delivery')._render_qweb_pdf(self.id) + report = self.env['ir.actions.report']._render_qweb_pdf("stock.action_report_delivery", self.id) filename = "%s_signed_delivery_slip" % self.name if self.partner_id: message = _('Order signed by %s') % (self.partner_id.name) diff --git a/addons/stock/tests/test_report.py b/addons/stock/tests/test_report.py index 286d8d893d4..b7aeefb98fe 100644 --- a/addons/stock/tests/test_report.py +++ b/addons/stock/tests/test_report.py @@ -53,10 +53,9 @@ class TestReports(TestReportsCommon): 'product_id': product1.id, 'company_id': self.env.company.id, }) - report = self.env.ref('stock.label_lot_template') target = b'\n\n^XA\n^FO100,50\n^A0N,44,33^FD[C418]Mellohi^FS\n^FO100,100\n^A0N,44,33^FDLN/SN:Volume-Beta^FS\n^FO100,150^BY3\n^BCN,100,Y,N,N\n^FDVolume-Beta^FS\n^XZ\n' - rendering, qweb_type = report._render_qweb_text(lot1.id) + rendering, qweb_type = self.env['ir.actions.report']._render_qweb_text('stock.label_lot_template', lot1.id) self.assertEqual(target, rendering.replace(b' ', b''), 'The rendering is not good') self.assertEqual(qweb_type, 'text', 'the report type is not good') diff --git a/addons/survey/controllers/main.py b/addons/survey/controllers/main.py index 908b6d29a3e..c3a92449680 100644 --- a/addons/survey/controllers/main.py +++ b/addons/survey/controllers/main.py @@ -696,7 +696,7 @@ class Survey(http.Controller): return request.render('survey.survey_page_statistics', template_values) def _generate_report(self, user_input, download=True): - report = request.env.ref('survey.certification_report').with_user(SUPERUSER_ID)._render_qweb_pdf([user_input.id], data={'report_type': 'pdf'})[0] + report = request.env["ir.actions.report"].sudo()._render_qweb_pdf('survey.certification_report', [user_input.id], data={'report_type': 'pdf'})[0] report_content_disposition = content_disposition('Certification.pdf') if not download: diff --git a/addons/test_event_full/tests/test_performance.py b/addons/test_event_full/tests/test_performance.py index 9daa296df0c..0452300254b 100644 --- a/addons/test_event_full/tests/test_performance.py +++ b/addons/test_event_full/tests/test_performance.py @@ -280,7 +280,7 @@ class TestRegistrationPerformance(EventPerformanceCase): form like) """ event = self.env['event.event'].browse(self.test_event.ids) - with freeze_time(self.reference_now), self.assertQueryCount(event_user=695): # tef only: 650 - com runbot 692 + with freeze_time(self.reference_now), self.assertQueryCount(event_user=697): # tef only: 650 - com runbot 692 self.env.cr._now = self.reference_now # force create_date to check schedulers registration_values = [ dict(reg_data, @@ -317,7 +317,7 @@ class TestRegistrationPerformance(EventPerformanceCase): """ Test a single registration creation using Form """ event = self.env['event.event'].browse(self.test_event.ids) - with freeze_time(self.reference_now), self.assertQueryCount(event_user=206): # tef only: 188 - com runbot: 193 + with freeze_time(self.reference_now), self.assertQueryCount(event_user=208): # tef only: 188 - com runbot: 193 self.env.cr._now = self.reference_now # force create_date to check schedulers with Form(self.env['event.registration']) as reg_form: reg_form.event_id = event @@ -330,7 +330,7 @@ class TestRegistrationPerformance(EventPerformanceCase): """ Test a single registration creation using Form """ event = self.env['event.event'].browse(self.test_event.ids) - with freeze_time(self.reference_now), self.assertQueryCount(event_user=123): # tef only: 120? - com runbot 108 - ent runbot 122 + with freeze_time(self.reference_now), self.assertQueryCount(event_user=124): # tef only: 120? - com runbot 108 - ent runbot 122 self.env.cr._now = self.reference_now # force create_date to check schedulers with Form(self.env['event.registration'].with_context(event_lead_rule_skip=True)) as reg_form: reg_form.event_id = event @@ -358,7 +358,7 @@ class TestRegistrationPerformance(EventPerformanceCase): event = self.env['event.event'].browse(self.test_event.ids) # partner-based customer - with freeze_time(self.reference_now), self.assertQueryCount(event_user=126): # tef only: 118 - com runbot: 125 + with freeze_time(self.reference_now), self.assertQueryCount(event_user=128): # tef only: 118 - com runbot: 125 self.env.cr._now = self.reference_now # force create_date to check schedulers registration_values = { 'event_id': event.id, @@ -373,7 +373,7 @@ class TestRegistrationPerformance(EventPerformanceCase): event = self.env['event.event'].browse(self.test_event.ids) # partner-based customer - with freeze_time(self.reference_now), self.assertQueryCount(event_user=44): # tef only: 40 - com runbot: 42 + with freeze_time(self.reference_now), self.assertQueryCount(event_user=46): # tef only: 40 - com runbot: 42 self.env.cr._now = self.reference_now # force create_date to check schedulers registration_values = { 'event_id': event.id, @@ -388,7 +388,7 @@ class TestRegistrationPerformance(EventPerformanceCase): event = self.env['event.event'].browse(self.test_event.ids) # website customer data - with freeze_time(self.reference_now), self.assertQueryCount(event_user=132): # tef only: 124 - com runbot: 128 + with freeze_time(self.reference_now), self.assertQueryCount(event_user=134): # tef only: 124 - com runbot: 128 self.env.cr._now = self.reference_now # force create_date to check schedulers registration_values = dict( self.website_customer_data[0], diff --git a/addons/test_mail/tests/test_mail_composer.py b/addons/test_mail/tests/test_mail_composer.py index ead685ad71e..aa075cf4a34 100644 --- a/addons/test_mail/tests/test_mail_composer.py +++ b/addons/test_mail/tests/test_mail_composer.py @@ -58,7 +58,7 @@ class TestMailComposer(TestMailCommon, TestRecipients): 'report_type': 'qweb-pdf', 'report_name': 'test_mail.mail_test_ticket_test_template', }) - cls.test_record_report = cls.test_report._render_qweb_pdf(cls.test_report.ids) + cls.test_record_report = cls.env['ir.actions.report']._render_qweb_pdf(cls.test_report, cls.test_record.ids) cls.test_from = '"John Doe" ' diff --git a/addons/web/controllers/report.py b/addons/web/controllers/report.py index 1da64f6223d..8ba955f378d 100644 --- a/addons/web/controllers/report.py +++ b/addons/web/controllers/report.py @@ -29,7 +29,7 @@ class ReportController(http.Controller): '/report///', ], type='http', auth='user', website=True) def report_routes(self, reportname, docids=None, converter=None, **data): - report = request.env['ir.actions.report']._get_report_from_name(reportname) + report = request.env['ir.actions.report'] context = dict(request.env.context) if docids: @@ -40,14 +40,14 @@ class ReportController(http.Controller): data['context'] = json.loads(data['context']) context.update(data['context']) if converter == 'html': - html = report.with_context(context)._render_qweb_html(docids, data=data)[0] + html = report.with_context(context)._render_qweb_html(reportname, docids, data=data)[0] return request.make_response(html) elif converter == 'pdf': - pdf = report.with_context(context)._render_qweb_pdf(docids, data=data)[0] + pdf = report.with_context(context)._render_qweb_pdf(reportname, docids, data=data)[0] pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))] return request.make_response(pdf, headers=pdfhttpheaders) elif converter == 'text': - text = report.with_context(context)._render_qweb_text(docids, data=data)[0] + text = report.with_context(context)._render_qweb_text(reportname, docids, data=data)[0] texthttpheaders = [('Content-Type', 'text/plain'), ('Content-Length', len(text))] return request.make_response(text, headers=texthttpheaders) else: diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index a9d21515607..da404115db8 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -1348,7 +1348,7 @@ class WebsiteSale(http.Controller): def print_saleorder(self, **kwargs): sale_order_id = request.session.get('sale_last_order_id') if sale_order_id: - pdf, _ = request.env.ref('sale.action_report_saleorder').with_user(SUPERUSER_ID)._render_qweb_pdf([sale_order_id]) + pdf, _ = request.env['ir.actions.report'].sudo()._render_qweb_pdf('sale.action_report_saleorder', [sale_order_id]) pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', u'%s' % len(pdf))] return request.make_response(pdf, headers=pdfhttpheaders) else: diff --git a/odoo/addons/base/models/ir_actions_report.py b/odoo/addons/base/models/ir_actions_report.py index 594af972ff0..054a20ebf56 100644 --- a/odoo/addons/base/models/ir_actions_report.py +++ b/odoo/addons/base/models/ir_actions_report.py @@ -490,15 +490,20 @@ class IrActionsReport(models.Model): @api.model def _get_report(self, report_ref): - """Get the report (with sudo) from an id or xmlid + """Get the report (with sudo) from a reference report_ref: can be one of - ir.actions.report id + - ir.actions.report record + - ir.model.data reference to ir.actions.report - ir.actions.report report_name - - ir.model.data reference """ ReportSudo = self.env['ir.actions.report'].sudo() if isinstance(report_ref, int): return ReportSudo.browse(report_ref) + if isinstance(report_ref, models.Model): + if report_ref._name != self._name: + raise ValueError("Expected report of type %s, got %s" % (self._name, report_ref._name)) + return report_ref.sudo() report = ReportSudo.search([('report_name', '=', report_ref)], limit=1) if report: return report @@ -614,29 +619,28 @@ class IrActionsReport(models.Model): writer.write(result_stream) return result_stream - def _render_qweb_pdf_prepare_streams(self, data, res_ids=None): - self.ensure_one() + def _render_qweb_pdf_prepare_streams(self, report_ref, data, res_ids=None): if not data: data = {} data.setdefault('report_type', 'pdf') - # access the report details with sudo() but evaluation context as sudo(False) - self_sudo = self.sudo() + # access the report details with sudo() but evaluation context as current user + report_sudo = self._get_report(report_ref) collected_streams = OrderedDict() # Fetch the existing attachments from the database for later use. # Reload the stream from the attachment in case of 'attachment_use'. if res_ids: - records = self.env[self_sudo.model].browse(res_ids) + records = self.env[report_sudo.model].browse(res_ids) for record in records: stream = None attachment = None - if self_sudo.attachment: - attachment = self_sudo.retrieve_attachment(record) + if report_sudo.attachment: + attachment = report_sudo.retrieve_attachment(record) # Extract the stream from the attachment. - if attachment and self_sudo.attachment_use: + if attachment and report_sudo.attachment_use: stream = io.BytesIO(attachment.raw) # Ensure the stream can be saved in Image. @@ -684,11 +688,11 @@ class IrActionsReport(models.Model): if not config['test_enable']: additional_context['commit_assetsbundle'] = True - html = self_sudo.with_context(**additional_context)._render_qweb_html(res_ids_wo_stream, data=data)[0] + html = self.with_context(**additional_context)._render_qweb_html(report_ref, res_ids_wo_stream, data=data)[0] - bodies, html_ids, header, footer, specific_paperformat_args = self._prepare_html(html, report_model=self_sudo.model) + bodies, html_ids, header, footer, specific_paperformat_args = self._prepare_html(html, report_model=report_sudo.model) - if self_sudo.attachment and set(res_ids_wo_stream) != set(html_ids): + if report_sudo.attachment and set(res_ids_wo_stream) != set(html_ids): raise UserError(_( "The report's template %r is wrong, please contact your administrator. \n\n" "Can not separate file to save as attachment because the report's template does not contains the" @@ -771,21 +775,21 @@ class IrActionsReport(models.Model): return collected_streams - def _render_qweb_pdf(self, res_ids=None, data=None): - self.ensure_one() + def _render_qweb_pdf(self, report_ref, res_ids=None, data=None): if not data: data = {} if isinstance(res_ids, int): res_ids = [res_ids] data.setdefault('report_type', 'pdf') - self_sudo = self.sudo() - # In case of test environment without enough workers to perform calls to wkhtmltopdf, # fallback to render_html. if (tools.config['test_enable'] or tools.config['test_file']) and not self.env.context.get('force_report_rendering'): - return self_sudo._render_qweb_html(res_ids, data=data) + return self._render_qweb_html(report_ref, res_ids, data=data) - collected_streams = self._render_qweb_pdf_prepare_streams(data, res_ids=res_ids) + collected_streams = self._render_qweb_pdf_prepare_streams(report_ref, data, res_ids=res_ids) + + # access the report details with sudo() but keep evaluation context as current user + report_sudo = self._get_report(report_ref) # Generate the ir.attachment if needed. if self.attachment: @@ -795,8 +799,8 @@ class IrActionsReport(models.Model): if stream_data['attachment']: continue - record = self.env[self_sudo.model].browse(res_id) - attachment_name = safe_eval(self.attachment, {'object': record, 'time': time}) + record = self.env[report_sudo.model].browse(res_id) + attachment_name = safe_eval(report_sudo.attachment, {'object': record, 'time': time}) # Unable to compute a name for the attachment. if not attachment_name: @@ -805,7 +809,7 @@ class IrActionsReport(models.Model): attachment_vals_list.append({ 'name': attachment_name, 'raw': stream_data['stream'].getvalue(), - 'res_model': self.model, + 'res_model': report_sudo.model, 'res_id': record.id, 'type': 'binary', }) @@ -831,65 +835,59 @@ class IrActionsReport(models.Model): stream.close() if res_ids: - _logger.info("The PDF report has been generated for model: %s, records %s.", self_sudo.model, str(res_ids)) + _logger.info("The PDF report has been generated for model: %s, records %s.", report_sudo.model, str(res_ids)) return pdf_content, 'pdf' @api.model - def _render_qweb_text(self, docids, data=None): - """ - :rtype: bytes - """ + def _render_qweb_text(self, report_ref, docids, data=None): if not data: data = {} data.setdefault('report_type', 'text') - data = self._get_rendering_context(docids, data) - return self._render_template(self.report_name, data), 'text' + report = self._get_report(report_ref) + data = self._get_rendering_context(report, docids, data) + return self._render_template(report.report_name, data), 'text' @api.model - def _render_qweb_html(self, docids, data=None): - """This method generates and returns html version of a report. - - :rtype: bytes - """ + def _render_qweb_html(self, report_ref, docids, data=None): if not data: data = {} data.setdefault('report_type', 'html') - data = self._get_rendering_context(docids, data) - return self._render_template(self.report_name, data), 'html' + report = self._get_report(report_ref) + data = self._get_rendering_context(report, docids, data) + return self._render_template(report.report_name, data), 'html' - def _get_rendering_context_model(self): - report_model_name = 'report.%s' % self.report_name + def _get_rendering_context_model(self, report): + report_model_name = 'report.%s' % report.report_name return self.env.get(report_model_name) - def _get_rendering_context(self, docids, data): + def _get_rendering_context(self, report, docids, data): # If the report is using a custom model to render its html, we must use it. # Otherwise, fallback on the generic html rendering. - report_model = self._get_rendering_context_model() + report_model = self._get_rendering_context_model(report) data = data and dict(data) or {} if report_model is not None: - # _render_ may be executed in sudo but evaluation context as real user - report_model = report_model.sudo(False) data.update(report_model._get_report_values(docids, data=data)) else: - # _render_ may be executed in sudo but evaluation context as real user - docs = self.env[self.model].sudo(False).browse(docids) + docs = self.env[report.model].browse(docids) data.update({ 'doc_ids': docids, - 'doc_model': self.model, + 'doc_model': report.model, 'docs': docs, }) data['is_html_empty'] = is_html_empty return data - def _render(self, res_ids, data=None): - report_type = self.report_type.lower().replace('-', '_') + @api.model + def _render(self, report_ref, res_ids, data): + report = self._get_report(report_ref) + report_type = report.report_type.lower().replace('-', '_') render_func = getattr(self, '_render_' + report_type, None) if not render_func: return None - return render_func(res_ids, data=data) + return render_func(report_ref, res_ids, data=data) def report_action(self, docids, data=None, config=True): """Return an action of type ir.actions.report. diff --git a/odoo/addons/base/tests/test_reports.py b/odoo/addons/base/tests/test_reports.py index 7a550554736..8a403d3480b 100644 --- a/odoo/addons/base/tests/test_reports.py +++ b/odoo/addons/base/tests/test_reports.py @@ -18,7 +18,8 @@ class TestReports(odoo.tests.TransactionCase): 'account.report_invoice_with_payments': invoice_domain, 'account.report_invoice': invoice_domain, } - for report in self.env['ir.actions.report'].search([('report_type', 'like', 'qweb')]): + Report = self.env['ir.actions.report'] + for report in Report.search([('report_type', 'like', 'qweb')]): report_model = 'report.%s' % report.report_name try: self.env[report_model] @@ -33,8 +34,8 @@ class TestReports(odoo.tests.TransactionCase): # Test report generation if not report.multi: for record in report_records: - report._render_qweb_html(record.ids) + Report._render_qweb_html(report.id, record.ids) else: - report._render_qweb_html(report_records.ids) + Report._render_qweb_html(report.id, report_records.ids) else: continue diff --git a/odoo/tools/test_reports.py b/odoo/tools/test_reports.py index 0938e666744..b66619418c1 100644 --- a/odoo/tools/test_reports.py +++ b/odoo/tools/test_reports.py @@ -32,11 +32,7 @@ def try_report(cr, uid, rname, ids, data=None, context=None, our_module=None, re env = api.Environment(cr, uid, context) - report_id = env['ir.actions.report'].search([('report_name', '=', rname)], limit=1) - if not report_id: - raise Exception("Required report does not exist: %s" % rname) - - res_data, res_format = report_id._render(ids, data=data) + res_data, res_format = env['ir.actions.report']._render(rname, ids, data=data) if not res_data: raise ValueError("Report %s produced an empty result!" % rname)