diff --git a/report_async/README.rst b/report_async/README.rst index 8b2719208..28d0fffd4 100644 --- a/report_async/README.rst +++ b/report_async/README.rst @@ -70,6 +70,15 @@ As normal user, you can run your reports from Report Center - **Files:** show all files being produced by the job as run by the user. - **Jobs:** show all jobs triggered by this report as run by the user. Only job queue manager have access to this button. +As additional improvement, you can now generate reports async directly from the form view itself, +and not have to go into the "Report Center" specifically to do it. This can be done by pressing +*Print*, you will get a popup asking you if you want to run it Async, and then to verify the email +address that it should be sent to. See below sample: + +.. image:: https://raw.githubusercontent.com/OCA/reporting-engine/14.0/report_async/static/description/sample.gif + :width: 800 + :alt: How It Works + Bug Tracker =========== @@ -97,6 +106,11 @@ Contributors * Saran Lim. * Tharathip Chaweewongphan +* `Sunflower IT `__: + + * Tom Blauwendraat + * Kevin Kamau + Maintainers ~~~~~~~~~~~ diff --git a/report_async/__manifest__.py b/report_async/__manifest__.py index 88a720170..4a0a24865 100644 --- a/report_async/__manifest__.py +++ b/report_async/__manifest__.py @@ -12,11 +12,14 @@ "data": [ "security/ir.model.access.csv", "security/ir_rule.xml", + "views/assets.xml", "data/mail_template.xml", "data/queue_job_function_data.xml", "views/report_async.xml", "wizard/print_report_wizard.xml", + "views/ir_actions_report.xml", ], + "qweb": ["static/src/xml/report_async.xml"], "demo": ["demo/report_async_demo.xml"], "installable": True, "maintainers": ["kittiu"], diff --git a/report_async/data/mail_template.xml b/report_async/data/mail_template.xml index bf1d29aa0..01ea4b9d5 100644 --- a/report_async/data/mail_template.xml +++ b/report_async/data/mail_template.xml @@ -40,7 +40,8 @@ valign="top" style="font-size: 13px;" > - % set base_url = object.env['ir.config_parameter'].sudo().get_param('web.base.url') + % set base_url_async = object.env['ir.config_parameter'].sudo().get_param('web.base.url.async_reports') + % set base_url = base_url_async or object.env['ir.config_parameter'].sudo().get_param('web.base.url') % set download_url = '%s/web/content/ir.attachment/%s/datas/%s?download=true' % (base_url, object.id, object.name, )
Dear ${object.create_uid.partner_id.name or ''}, diff --git a/report_async/models/__init__.py b/report_async/models/__init__.py index d0e92de8d..5c58434bb 100644 --- a/report_async/models/__init__.py +++ b/report_async/models/__init__.py @@ -4,3 +4,4 @@ from . import report_async from . import ir_report from . import ir_actions +from . import queue_job diff --git a/report_async/models/ir_report.py b/report_async/models/ir_report.py index 03a122cda..0b0f87fc5 100644 --- a/report_async/models/ir_report.py +++ b/report_async/models/ir_report.py @@ -1,7 +1,7 @@ # Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) -from odoo import models +from odoo import fields, models # Define all supported report_type REPORT_TYPES = ["qweb-pdf", "qweb-text", "qweb-xml", "csv", "excel", "xlsx"] @@ -10,6 +10,18 @@ REPORT_TYPES = ["qweb-pdf", "qweb-text", "qweb-xml", "csv", "excel", "xlsx"] class Report(models.Model): _inherit = "ir.actions.report" + async_report = fields.Boolean(default=False) + async_no_records = fields.Integer( + string="Min of Records", + default=100, + help="Min no of records to use async report functionality; e.g 100+", + ) + async_mail_recipient = fields.Char( + string="Mail Recipient", + help="The email that will receive the async report", + default=lambda self: self.env.user.email, + ) + def report_action(self, docids, data=None, config=True): res = super(Report, self).report_action(docids, data=data, config=config) if res["context"].get("async_process", False): diff --git a/report_async/models/queue_job.py b/report_async/models/queue_job.py new file mode 100644 index 000000000..2c5bd6b95 --- /dev/null +++ b/report_async/models/queue_job.py @@ -0,0 +1,30 @@ +# Copyright 2022 Sunflower IT (https://sunflowerweb.nl/) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from odoo import api, models + + +class QueueJob(models.Model): + _inherit = "queue.job" + + @api.model + def create(self, values): + res = super(QueueJob, self).create(values) + if ( + "model_name" in values + and values["model_name"] == "report.async" + and "kwargs" in values + and "to_email" in values["kwargs"] + ): + followers = self._find_partner(res, values["kwargs"]["to_email"]) + if followers: + res.message_subscribe(partner_ids=followers) + return res + + def _find_partner(self, record, email): + partner = self.env["res.partner"].search([("email", "=", email)], limit=1) + followers = record.message_follower_ids.mapped("partner_id") + ids = [x for x in partner.ids if x not in followers.ids] + if partner and ids: + return ids + return None diff --git a/report_async/models/report_async.py b/report_async/models/report_async.py index 7b43bb8f9..0d58cab92 100644 --- a/report_async/models/report_async.py +++ b/report_async/models/report_async.py @@ -2,11 +2,17 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) import base64 +import logging + +import mock from odoo import _, api, fields, models from odoo.exceptions import UserError +from odoo.http import request from odoo.tools.safe_eval import safe_eval +_logger = logging.getLogger(__name__) + # Define all supported report_type REPORT_TYPES_FUNC = { "qweb-pdf": "_render_qweb_pdf", @@ -137,13 +143,56 @@ class ReportAsync(models.Model): return result @api.model - def run_report(self, docids, data, report_id, user_id): + def print_document_async( + self, + record_ids, + report_name, + html=None, + data=None, + to_email="", + save_attachment_to_records=False, + ): + """Generate a document async, do not return the document file""" + user_email = to_email or self.env.user.email + report = self.env["ir.actions.report"]._get_report_from_name(report_name) + self.with_delay().run_report( + record_ids, + data or {}, + report.id, + self._uid, + email_notify=True, + to_email=user_email, + session_id=request.session.sid, + save_attachment_to_records=save_attachment_to_records, + ) + + @api.model + def run_report( + self, + docids, + data, + report_id, + user_id, + email_notify=False, + to_email=None, + session_id=None, + save_attachment_to_records=False, + ): report = self.env["ir.actions.report"].browse(report_id) func = REPORT_TYPES_FUNC[report.report_type] + if user_id: + report = report.with_user(user_id) + if session_id: + # necessary for correct CSS headers + with mock.patch("odoo.http.request.session") as session: + session.sid = session_id + out_file, file_ext = getattr(report, func)(docids, data) + else: + out_file, file_ext = getattr(report, func)(docids, data) # Run report - out_file, file_ext = getattr(report, func)(docids, data) out_file = base64.b64encode(out_file) out_name = "{}.{}".format(report.name, file_ext) + _logger.info("ASYNC GENERATION OF REPORT %s", (out_name,)) # Save report to attachment attachment = ( self.env["ir.attachment"] @@ -158,6 +207,26 @@ class ReportAsync(models.Model): } ) ) + # save attachment to records + if save_attachment_to_records: + model = report.model + records = self.env[model].sudo().browse(docids) + for record in records: + attachment = ( + self.env["ir.attachment"] + .sudo() + .create( + { + "name": out_name, + "datas": out_file, + "type": "binary", + "res_model": model, + "res_id": record.id, + } + ) + ) + if hasattr(record, "message_post"): + record.message_post(attachment_ids=[attachment.id]) self._cr.execute( """ UPDATE ir_attachment SET create_uid = %s, write_uid = %s @@ -165,11 +234,20 @@ class ReportAsync(models.Model): (self._uid, self._uid, attachment.id), ) # Send email - if self.email_notify: - self._send_email(attachment) + if email_notify or self.email_notify: + self._send_email(attachment, to_email=to_email) - def _send_email(self, attachment): + def _send_email(self, attachment, to_email=None): template = self.env.ref("report_async.async_report_delivery") + email_values = {} + if to_email: + email_values = { + "recipient_ids": [], + "email_to": to_email, + } template.send_mail( - attachment.id, notif_layout="mail.mail_notification_light", force_send=False + attachment.id, + notif_layout="mail.mail_notification_light", + force_send=False, + email_values=email_values, ) diff --git a/report_async/readme/CONTRIBUTORS.rst b/report_async/readme/CONTRIBUTORS.rst index d391cb73d..0f91c6253 100644 --- a/report_async/readme/CONTRIBUTORS.rst +++ b/report_async/readme/CONTRIBUTORS.rst @@ -3,3 +3,8 @@ * Kitti U. * Saran Lim. * Tharathip Chaweewongphan + +* `Sunflower IT `__: + + * Tom Blauwendraat + * Kevin Kamau diff --git a/report_async/readme/USAGE.rst b/report_async/readme/USAGE.rst index 9668d579d..43a2d6fc3 100644 --- a/report_async/readme/USAGE.rst +++ b/report_async/readme/USAGE.rst @@ -17,3 +17,12 @@ As normal user, you can run your reports from Report Center - **Job Status:** show status of the latest run job. If job fail, exception error will also shown - **Files:** show all files being produced by the job as run by the user. - **Jobs:** show all jobs triggered by this report as run by the user. Only job queue manager have access to this button. + +As additional improvement, you can now generate reports async directly from the form view itself, +and not have to go into the "Report Center" specifically to do it. This can be done by pressing +*Print*, you will get a popup asking you if you want to run it Async, and then to verify the email +address that it should be sent to. See below sample: + +.. image:: ../static/description/sample.gif + :width: 800 + :alt: How It Works diff --git a/report_async/static/description/index.html b/report_async/static/description/index.html index 7f653892b..9b31c5f08 100644 --- a/report_async/static/description/index.html +++ b/report_async/static/description/index.html @@ -3,7 +3,7 @@ - + Report Async