mirror of
https://github.com/OCA/reporting-engine.git
synced 2025-02-16 16:30:38 +02:00
[IMP] report_async 14.0
This commit is contained in:
@@ -1,123 +0,0 @@
|
|||||||
============
|
|
||||||
Report Async
|
|
||||||
============
|
|
||||||
|
|
||||||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
!! This file is generated by oca-gen-addon-readme !!
|
|
||||||
!! changes will be overwritten. !!
|
|
||||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
|
|
||||||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
|
|
||||||
:target: https://odoo-community.org/page/development-status
|
|
||||||
:alt: Beta
|
|
||||||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
|
|
||||||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
|
|
||||||
:alt: License: AGPL-3
|
|
||||||
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github
|
|
||||||
:target: https://github.com/OCA/reporting-engine/tree/14.0/report_async
|
|
||||||
:alt: OCA/reporting-engine
|
|
||||||
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
|
|
||||||
:target: https://translation.odoo-community.org/projects/reporting-engine-14-0/reporting-engine-14-0-report_async
|
|
||||||
:alt: Translate me on Weblate
|
|
||||||
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
|
|
||||||
:target: https://runbot.odoo-community.org/runbot/143/14.0
|
|
||||||
:alt: Try me on Runbot
|
|
||||||
|
|
||||||
|badge1| |badge2| |badge3| |badge4| |badge5|
|
|
||||||
|
|
||||||
The new menu "Report Center" is the central place to host your reports in one place.
|
|
||||||
From here, there are 2 ways to launch the report,
|
|
||||||
|
|
||||||
1. Run Now - run report immediately as per normal.
|
|
||||||
2. Run Background - put the report execution to queue job.
|
|
||||||
|
|
||||||
By using the queue job, option 2 is great for long running report.
|
|
||||||
The report file will be saved for later use, with the option to send report
|
|
||||||
by email as soon as it is ready.
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
|
|
||||||
* Only user with Technical Feature rights can manage the report.
|
|
||||||
* Every internal user will have right to execute the report allowed for his/her groups.
|
|
||||||
* The files created are owned and viewable only by the person who run the report.
|
|
||||||
* Job queue manager can also see all jobs for each reports.
|
|
||||||
|
|
||||||
**Table of contents**
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
:local:
|
|
||||||
|
|
||||||
Usage
|
|
||||||
=====
|
|
||||||
|
|
||||||
Menu: Dashboard > Report Center
|
|
||||||
|
|
||||||
As Technical Feature users, you can manage reports for Report Center.
|
|
||||||
|
|
||||||
- **Report:** choose the report (a window action). Although the option show all window actions
|
|
||||||
it only make sense for window actions that launch reports.
|
|
||||||
- **Allow Async:** check this, if you want the report to run in background too, suitable for
|
|
||||||
report that return file as result, i.e., pdf/xlsx/csv/txt.
|
|
||||||
- **Email Notification:** if checked, once the background process is completed, email with link to download
|
|
||||||
report will be sent.
|
|
||||||
- **Groups:** select user groups allowed to use this report. If left blank, all user can use.
|
|
||||||
|
|
||||||
As normal user, you can run your reports from Report Center
|
|
||||||
|
|
||||||
- **Run Now button:** to run report immediately as per normal.
|
|
||||||
- **Run Background button:** to run report asynchronously. Fall back to run now, if not report that produce file.
|
|
||||||
- **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.
|
|
||||||
|
|
||||||
Bug Tracker
|
|
||||||
===========
|
|
||||||
|
|
||||||
Bugs are tracked on `GitHub Issues <https://github.com/OCA/reporting-engine/issues>`_.
|
|
||||||
In case of trouble, please check there if your issue has already been reported.
|
|
||||||
If you spotted it first, help us smashing it by providing a detailed and welcomed
|
|
||||||
`feedback <https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_async%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
|
|
||||||
|
|
||||||
Do not contact contributors directly about support or help with technical issues.
|
|
||||||
|
|
||||||
Credits
|
|
||||||
=======
|
|
||||||
|
|
||||||
Authors
|
|
||||||
~~~~~~~
|
|
||||||
|
|
||||||
* Ecosoft
|
|
||||||
|
|
||||||
Contributors
|
|
||||||
~~~~~~~~~~~~
|
|
||||||
|
|
||||||
* `Ecosoft <http://ecosoft.co.th>`__:
|
|
||||||
|
|
||||||
* Kitti U. <kittiu@ecosoft.co.th>
|
|
||||||
* Saran Lim. <saranl@ecosoft.co.th>
|
|
||||||
* Tharathip Chaweewongphan <tharathipc@ecosoft.co.th>
|
|
||||||
|
|
||||||
Maintainers
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
This module is maintained by the OCA.
|
|
||||||
|
|
||||||
.. image:: https://odoo-community.org/logo.png
|
|
||||||
:alt: Odoo Community Association
|
|
||||||
:target: https://odoo-community.org
|
|
||||||
|
|
||||||
OCA, or the Odoo Community Association, is a nonprofit organization whose
|
|
||||||
mission is to support the collaborative development of Odoo features and
|
|
||||||
promote its widespread use.
|
|
||||||
|
|
||||||
.. |maintainer-kittiu| image:: https://github.com/kittiu.png?size=40px
|
|
||||||
:target: https://github.com/kittiu
|
|
||||||
:alt: kittiu
|
|
||||||
|
|
||||||
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:
|
|
||||||
|
|
||||||
|maintainer-kittiu|
|
|
||||||
|
|
||||||
This module is part of the `OCA/reporting-engine <https://github.com/OCA/reporting-engine/tree/14.0/report_async>`_ project on GitHub.
|
|
||||||
|
|
||||||
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
|
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
"data": [
|
"data": [
|
||||||
"security/ir.model.access.csv",
|
"security/ir.model.access.csv",
|
||||||
"security/ir_rule.xml",
|
"security/ir_rule.xml",
|
||||||
|
"views/assets.xml",
|
||||||
"data/mail_template.xml",
|
"data/mail_template.xml",
|
||||||
"data/queue_job_function_data.xml",
|
"data/queue_job_function_data.xml",
|
||||||
"views/report_async.xml",
|
"views/report_async.xml",
|
||||||
"wizard/print_report_wizard.xml",
|
"wizard/print_report_wizard.xml",
|
||||||
|
"views/ir_actions_report.xml",
|
||||||
],
|
],
|
||||||
|
"qweb": ["static/src/xml/report_async.xml"],
|
||||||
"demo": ["demo/report_async_demo.xml"],
|
"demo": ["demo/report_async_demo.xml"],
|
||||||
"installable": True,
|
"installable": True,
|
||||||
"maintainers": ["kittiu"],
|
"maintainers": ["kittiu"],
|
||||||
|
|||||||
@@ -40,7 +40,8 @@
|
|||||||
valign="top"
|
valign="top"
|
||||||
style="font-size: 13px;"
|
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, )
|
% set download_url = '%s/web/content/ir.attachment/%s/datas/%s?download=true' % (base_url, object.id, object.name, )
|
||||||
<div>
|
<div>
|
||||||
Dear ${object.create_uid.partner_id.name or ''},
|
Dear ${object.create_uid.partner_id.name or ''},
|
||||||
|
|||||||
@@ -4,3 +4,4 @@
|
|||||||
from . import report_async
|
from . import report_async
|
||||||
from . import ir_report
|
from . import ir_report
|
||||||
from . import ir_actions
|
from . import ir_actions
|
||||||
|
from . import queue_job
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
|
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
|
||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
# 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
|
# Define all supported report_type
|
||||||
REPORT_TYPES = ["qweb-pdf", "qweb-text", "qweb-xml", "csv", "excel", "xlsx"]
|
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):
|
class Report(models.Model):
|
||||||
_inherit = "ir.actions.report"
|
_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):
|
def report_action(self, docids, data=None, config=True):
|
||||||
res = super(Report, self).report_action(docids, data=data, config=config)
|
res = super(Report, self).report_action(docids, data=data, config=config)
|
||||||
if res["context"].get("async_process", False):
|
if res["context"].get("async_process", False):
|
||||||
|
|||||||
30
report_async/models/queue_job.py
Normal file
30
report_async/models/queue_job.py
Normal file
@@ -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
|
||||||
@@ -2,11 +2,17 @@
|
|||||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
|
import logging
|
||||||
|
|
||||||
|
import mock
|
||||||
|
|
||||||
from odoo import _, api, fields, models
|
from odoo import _, api, fields, models
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
from odoo.http import request
|
||||||
from odoo.tools.safe_eval import safe_eval
|
from odoo.tools.safe_eval import safe_eval
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# Define all supported report_type
|
# Define all supported report_type
|
||||||
REPORT_TYPES_FUNC = {
|
REPORT_TYPES_FUNC = {
|
||||||
"qweb-pdf": "_render_qweb_pdf",
|
"qweb-pdf": "_render_qweb_pdf",
|
||||||
@@ -137,13 +143,48 @@ class ReportAsync(models.Model):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
@api.model
|
@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=""
|
||||||
|
):
|
||||||
|
"""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,
|
||||||
|
)
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def run_report(
|
||||||
|
self,
|
||||||
|
docids,
|
||||||
|
data,
|
||||||
|
report_id,
|
||||||
|
user_id,
|
||||||
|
email_notify=False,
|
||||||
|
to_email=None,
|
||||||
|
session_id=None,
|
||||||
|
):
|
||||||
report = self.env["ir.actions.report"].browse(report_id)
|
report = self.env["ir.actions.report"].browse(report_id)
|
||||||
func = REPORT_TYPES_FUNC[report.report_type]
|
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
|
# Run report
|
||||||
out_file, file_ext = getattr(report, func)(docids, data)
|
|
||||||
out_file = base64.b64encode(out_file)
|
out_file = base64.b64encode(out_file)
|
||||||
out_name = "{}.{}".format(report.name, file_ext)
|
out_name = "{}.{}".format(report.name, file_ext)
|
||||||
|
_logger.info("ASYNC GENERATION OF REPORT %s", (out_name,))
|
||||||
# Save report to attachment
|
# Save report to attachment
|
||||||
attachment = (
|
attachment = (
|
||||||
self.env["ir.attachment"]
|
self.env["ir.attachment"]
|
||||||
@@ -165,11 +206,20 @@ class ReportAsync(models.Model):
|
|||||||
(self._uid, self._uid, attachment.id),
|
(self._uid, self._uid, attachment.id),
|
||||||
)
|
)
|
||||||
# Send email
|
# Send email
|
||||||
if self.email_notify:
|
if email_notify or self.email_notify:
|
||||||
self._send_email(attachment)
|
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")
|
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(
|
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,
|
||||||
)
|
)
|
||||||
|
|||||||
124
report_async/static/src/js/components/action_menus.js
Normal file
124
report_async/static/src/js/components/action_menus.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
odoo.define("report_async.ActionMenus", function (require) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const {patch} = require("web.utils");
|
||||||
|
const ActionMenus = require("web.ActionMenus");
|
||||||
|
const Dialog = require("web.Dialog");
|
||||||
|
const Core = require("web.core");
|
||||||
|
const Framework = require("web.framework");
|
||||||
|
|
||||||
|
const _t = Core._t;
|
||||||
|
const QWeb = Core.qweb;
|
||||||
|
|
||||||
|
function validate_email(email) {
|
||||||
|
const res = email.match(
|
||||||
|
/^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||||
|
);
|
||||||
|
if (!res) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch _executeAction to use Dialog
|
||||||
|
patch(ActionMenus, "async _super report_async.ActionMenus", {
|
||||||
|
async _executeAction(action) {
|
||||||
|
const self = this;
|
||||||
|
const _super = this._super;
|
||||||
|
const args = arguments; // Dict action
|
||||||
|
const records = this.props.activeIds;
|
||||||
|
var $content = $(QWeb.render("ReportAsyncConfiguration", {}));
|
||||||
|
|
||||||
|
if (action.async_report && records.length >= action.async_no_records) {
|
||||||
|
const asyncDialog = new Dialog(self, {
|
||||||
|
title:
|
||||||
|
_t("Async Report Configuration ") +
|
||||||
|
"(" +
|
||||||
|
action.display_name +
|
||||||
|
")",
|
||||||
|
size: "medium",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: _t("Print"),
|
||||||
|
classes: "btn-primary",
|
||||||
|
close: true,
|
||||||
|
click: function () {
|
||||||
|
const is_report_async = this.$(
|
||||||
|
"#async_report_checker"
|
||||||
|
).prop("checked");
|
||||||
|
const user_email = this.$("#async-user-email").val();
|
||||||
|
if (user_email !== "" && is_report_async) {
|
||||||
|
// Try basic email validation
|
||||||
|
if (validate_email(user_email)) {
|
||||||
|
if (
|
||||||
|
"report_type" in action &&
|
||||||
|
action.report_type === "qweb-pdf"
|
||||||
|
) {
|
||||||
|
Framework.unblockUI();
|
||||||
|
// Generate report async
|
||||||
|
self.rpc({
|
||||||
|
model: "report.async",
|
||||||
|
method: "print_document_async",
|
||||||
|
args: [records, action.report_name],
|
||||||
|
kwargs: {
|
||||||
|
to_email: user_email,
|
||||||
|
data: action.data || {},
|
||||||
|
context: action.context || {},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
const msg =
|
||||||
|
_t(
|
||||||
|
"Job started to generate report. Upon " +
|
||||||
|
"completion, mail sent to:"
|
||||||
|
) + user_email;
|
||||||
|
Dialog.alert(self, msg, {
|
||||||
|
title: _t("Report"),
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
const error = _t(
|
||||||
|
"Failed, error on job creation."
|
||||||
|
);
|
||||||
|
const title = _t("Report");
|
||||||
|
Dialog.alert(self, error, {
|
||||||
|
title: title,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Default to normal approach to generate report
|
||||||
|
return _super.apply(self, args);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const msg = _t(
|
||||||
|
"Please check your email syntax and try again"
|
||||||
|
);
|
||||||
|
const title = _t("Email Validation Error");
|
||||||
|
Dialog.alert(self, msg, {title: title});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Default to normal approach to generate report
|
||||||
|
return _super.apply(self, args);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: _t("Discard"),
|
||||||
|
close: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
$content: $content,
|
||||||
|
});
|
||||||
|
// Default current user mail
|
||||||
|
asyncDialog.open().opened(function () {
|
||||||
|
asyncDialog.$el
|
||||||
|
.find("#async-user-email")
|
||||||
|
.val(action.async_mail_recipient);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Default to normal approach to generate report
|
||||||
|
return _super.apply(this, arguments);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
138
report_async/static/src/tests/report_async_tests.js
Normal file
138
report_async/static/src/tests/report_async_tests.js
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
odoo.define("report_async.action_menus_tests", function (require) {
|
||||||
|
"use strict";
|
||||||
|
/* global QUnit*/
|
||||||
|
|
||||||
|
const ActionMenus = require("web.ActionMenus");
|
||||||
|
const Registry = require("web.Registry");
|
||||||
|
const testUtils = require("web.test_utils");
|
||||||
|
const cpHelpers = testUtils.controlPanel;
|
||||||
|
|
||||||
|
const {createComponent} = testUtils;
|
||||||
|
|
||||||
|
QUnit.module(
|
||||||
|
"report_async",
|
||||||
|
{
|
||||||
|
beforeEach() {
|
||||||
|
this.action = {
|
||||||
|
res_model: "res.users",
|
||||||
|
};
|
||||||
|
this.view = {
|
||||||
|
type: "form",
|
||||||
|
};
|
||||||
|
this.props = {
|
||||||
|
activeIds: [1, 2],
|
||||||
|
context: {},
|
||||||
|
items: {
|
||||||
|
print: [
|
||||||
|
{
|
||||||
|
type: "ir.actions.report",
|
||||||
|
async_report: true,
|
||||||
|
data: null,
|
||||||
|
async_no_records: 1,
|
||||||
|
async_mail_recipient: "admin@example.com",
|
||||||
|
report_type: "qweb-pdf",
|
||||||
|
report_name: "report_async.async_demo_report_view",
|
||||||
|
report_file: "report_async.async_demo_report_view",
|
||||||
|
name: "Async Report",
|
||||||
|
id: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// Patch the registry of the action menus
|
||||||
|
this.actionMenusRegistry = ActionMenus.registry;
|
||||||
|
ActionMenus.registry = new Registry();
|
||||||
|
},
|
||||||
|
afterEach() {
|
||||||
|
ActionMenus.registry = this.actionMenusRegistry;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
function () {
|
||||||
|
QUnit.test("execute print action", async function (assert) {
|
||||||
|
// No of assertion expected.
|
||||||
|
assert.expect(7);
|
||||||
|
const actionMenus = await createComponent(ActionMenus, {
|
||||||
|
env: {
|
||||||
|
action: this.action,
|
||||||
|
view: this.view,
|
||||||
|
},
|
||||||
|
intercepts: {
|
||||||
|
"do-action": () => assert.step("do-action"),
|
||||||
|
},
|
||||||
|
props: this.props,
|
||||||
|
async mockRPC(route, args) {
|
||||||
|
switch (route) {
|
||||||
|
case "/web/action/load": {
|
||||||
|
const expectedContext = {
|
||||||
|
active_id: 1,
|
||||||
|
active_ids: [1, 2],
|
||||||
|
active_model: "res.users",
|
||||||
|
};
|
||||||
|
assert.deepEqual(args.context, expectedContext);
|
||||||
|
assert.step("load-action");
|
||||||
|
return {context: {}, flags: {}};
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return this._super(...arguments);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await testUtils.nextTick();
|
||||||
|
await cpHelpers.toggleActionMenu(actionMenus, "Print");
|
||||||
|
await cpHelpers.toggleMenuItem(actionMenus, "Async Report");
|
||||||
|
|
||||||
|
// We should have dialog created and opened
|
||||||
|
assert.containsOnce(
|
||||||
|
$,
|
||||||
|
".form",
|
||||||
|
"Error dialog should be opened and showing async options"
|
||||||
|
);
|
||||||
|
// We should have checkbox checked
|
||||||
|
assert.ok(
|
||||||
|
$("#async_report_checker").prop("checked"),
|
||||||
|
"Checkbox should be checked auto"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Email should be set as default
|
||||||
|
assert.equal(
|
||||||
|
$("#async-user-email").val(),
|
||||||
|
"admin@example.com",
|
||||||
|
"Email should be set and equal to default"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Try to process async report to a queue and send mail
|
||||||
|
await testUtils.dom.click($("button.btn-primary"), {
|
||||||
|
allowInvisible: true,
|
||||||
|
});
|
||||||
|
await testUtils.nextTick();
|
||||||
|
|
||||||
|
// This should fail through error/alert dialog because we haven't
|
||||||
|
// defined the report well queue job, qweb etc. For a successful
|
||||||
|
// test see possible python tests.
|
||||||
|
assert.containsNone(
|
||||||
|
$,
|
||||||
|
$(".modal-content"),
|
||||||
|
"Error Dialog should have popup"
|
||||||
|
);
|
||||||
|
assert.ok(
|
||||||
|
$(".modal-title").text(),
|
||||||
|
"Report",
|
||||||
|
'Should have title "Report"'
|
||||||
|
);
|
||||||
|
assert.ok($(".modal-content").text().search("Failed"));
|
||||||
|
|
||||||
|
// Close error dialog
|
||||||
|
await testUtils.dom.click($(".modal-footer button.btn-primary"), {
|
||||||
|
allowInvisible: true,
|
||||||
|
});
|
||||||
|
await testUtils.nextTick();
|
||||||
|
|
||||||
|
// All dialogs should be closed
|
||||||
|
assert.containsNone($, $(".modal-dialog"), "Dialogs should be closed");
|
||||||
|
|
||||||
|
// Destroy the action menus
|
||||||
|
actionMenus.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
40
report_async/static/src/xml/report_async.xml
Normal file
40
report_async/static/src/xml/report_async.xml
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<templates>
|
||||||
|
<t t-name='ReportAsyncConfiguration'>
|
||||||
|
<div class="form">
|
||||||
|
<!-- Async Checkbox -->
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
class="form-check-input"
|
||||||
|
checked="checked"
|
||||||
|
id="async_report_checker"
|
||||||
|
/>
|
||||||
|
<label class="form-check-label" for="async_report_checker">
|
||||||
|
Async Report
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<small id="async-report-checker-help" class="form-text text-muted">
|
||||||
|
Checker enables async report to be created on the background
|
||||||
|
via queue job and sent to a below email address.
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<!-- Email Input -->
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="async-user-email">Email Address</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
class="form-control"
|
||||||
|
id="async-user-email"
|
||||||
|
aria-describedby="emailHelp"
|
||||||
|
placeholder="admin@example.com"
|
||||||
|
/>
|
||||||
|
<small id="async-user-email-help" class="form-text text-muted">
|
||||||
|
Email will be used to send the async report after queue job
|
||||||
|
is done on the background
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
||||||
28
report_async/views/assets.xml
Normal file
28
report_async/views/assets.xml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<template
|
||||||
|
id="report_async_assets_backend"
|
||||||
|
inherit_id="web.assets_backend"
|
||||||
|
name="Report Async Assets"
|
||||||
|
>
|
||||||
|
<xpath expr="//script[last()]" position="after">
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/report_async/static/src/js/components/action_menus.js"
|
||||||
|
/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template
|
||||||
|
id="report_async_tests"
|
||||||
|
name="Report Async Tests"
|
||||||
|
inherit_id="web.qunit_suite_tests"
|
||||||
|
>
|
||||||
|
<xpath expr="//script[last()]" position="after">
|
||||||
|
<script
|
||||||
|
type="text/javascript"
|
||||||
|
src="/report_async/static/src/tests/report_async_tests.js"
|
||||||
|
/>
|
||||||
|
</xpath>
|
||||||
|
</template>
|
||||||
|
</odoo>
|
||||||
17
report_async/views/ir_actions_report.xml
Normal file
17
report_async/views/ir_actions_report.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<odoo>
|
||||||
|
<record id="async_act_report_xml_view" model="ir.ui.view">
|
||||||
|
<field name="name">async_report_view</field>
|
||||||
|
<field name="model">ir.actions.report</field>
|
||||||
|
<field name="inherit_id" ref="base.act_report_xml_view" />
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<xpath expr="//page[@name='advanced']/group" position="after">
|
||||||
|
<group name="async_opts" string="Async Options">
|
||||||
|
<field name="async_report" />
|
||||||
|
<field name="async_no_records" />
|
||||||
|
<field name="async_mail_recipient" />
|
||||||
|
</group>
|
||||||
|
</xpath>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
Reference in New Issue
Block a user