Merge pull request #1 from OCA/13.0

13.0
pull/561/head^2
haulogy.net 2022-04-28 18:34:53 +02:00 committed by GitHub
commit e075724400
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
62 changed files with 1827 additions and 118 deletions

View File

@ -1,11 +1,13 @@
# Do NOT update manually; changes here will be overwritten by Copier # Do NOT update manually; changes here will be overwritten by Copier
_commit: v1.3.6 _commit: v1.6.1
_src_path: git+https://github.com/OCA/oca-addons-repo-template _src_path: git+https://github.com/OCA/oca-addons-repo-template
ci: Travis ci: GitHub
dependency_installation_mode: PIP dependency_installation_mode: PIP
generate_requirements_txt: true generate_requirements_txt: true
include_wkhtmltopdf: true include_wkhtmltopdf: true
odoo_version: 13.0 odoo_version: 13.0
org_name: Odoo Community Association (OCA)
org_slug: OCA
rebel_module_groups: [] rebel_module_groups: []
repo_description: 'This repository hosts alternative reporting engines to the ones repo_description: 'This repository hosts alternative reporting engines to the ones
included on Odoo core (RML, QWeb and Webkit). included on Odoo core (RML, QWeb and Webkit).
@ -19,6 +21,7 @@ repo_description: 'This repository hosts alternative reporting engines to the on
utils, checkers, signing tools and so on).' utils, checkers, signing tools and so on).'
repo_name: OCA alternative reporting engines and reporting utilities for Odoo repo_name: OCA alternative reporting engines and reporting utilities for Odoo
repo_slug: reporting-engine repo_slug: reporting-engine
repo_website: https://github.com/OCA/reporting-engine
travis_apt_packages: travis_apt_packages:
- swig - swig
- libreoffice - libreoffice

View File

@ -4,7 +4,7 @@ env:
# See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449 # See https://github.com/OCA/odoo-community.org/issues/37#issuecomment-470686449
parserOptions: parserOptions:
ecmaVersion: 2017 ecmaVersion: 2019
overrides: overrides:
- files: - files:

View File

@ -2,7 +2,12 @@ name: pre-commit
on: on:
pull_request: pull_request:
branches:
- "13.0*"
push: push:
branches:
- "13.0"
- "13.0-ocabot-*"
jobs: jobs:
pre-commit: pre-commit:
@ -11,10 +16,22 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions/setup-python@v2 - uses: actions/setup-python@v2
with: with:
# The pylint-odoo version we use here does not support python 3.10 python-version: "3.8"
# https://github.com/OCA/oca-addons-repo-template/issues/80 - name: Get python version
# We also need to pin to an older version of python for older odoo versions run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
# where we are not using black > 21. Older black versions won't work with - uses: actions/cache@v1
# Python 3.9.8+, and we can't bump black without reformatting. with:
python-version: "3.9.7" path: ~/.cache/pre-commit
- uses: pre-commit/action@v2.0.0 key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit
run: pre-commit run --all-files --show-diff-on-failure --color=always
- name: Check that all files generated by pre-commit are in git
run: |
newfiles="$(git ls-files --others --exclude-from=.gitignore)"
if [ "$newfiles" != "" ] ; then
echo "Please check-in the following files:"
echo "$newfiles"
exit 1
fi

69
.github/workflows/test.yml vendored 100644
View File

@ -0,0 +1,69 @@
name: tests
on:
pull_request:
branches:
- "13.0*"
push:
branches:
- "13.0"
- "13.0-ocabot-*"
jobs:
unreleased-deps:
runs-on: ubuntu-latest
name: Detect unreleased dependencies
steps:
- uses: actions/checkout@v2
- run: |
for reqfile in requirements.txt test-requirements.txt ; do
if [ -f ${reqfile} ] ; then
result=0
# reject non-comment lines that contain a / (i.e. URLs, relative paths)
grep "^[^#].*/" ${reqfile} || result=$?
if [ $result -eq 0 ] ; then
echo "Unreleased dependencies found in ${reqfile}."
exit 1
fi
fi
done
test:
runs-on: ubuntu-latest
container: ${{ matrix.container }}
name: ${{ matrix.name }}
strategy:
fail-fast: false
matrix:
include:
- container: ghcr.io/oca/oca-ci/py3.6-odoo13.0:latest
makepot: "true"
name: test with Odoo
- container: ghcr.io/oca/oca-ci/py3.6-ocb13.0:latest
name: test with OCB
services:
postgres:
image: postgres:9.6
env:
POSTGRES_USER: odoo
POSTGRES_PASSWORD: odoo
POSTGRES_DB: odoo
ports:
- 5432:5432
steps:
- uses: actions/checkout@v2
with:
persist-credentials: false
- name: Install addons and dependencies
run: oca_install_addons
- name: Check licenses
run: manifestoo -d . check-licenses
- name: Check development status
run: manifestoo -d . check-dev-status --default-dev-status=Beta
- name: Initialize test db
run: oca_init_test_database
- name: Run tests
run: oca_run_tests
- uses: codecov/codecov-action@v1
- name: Update .pot files
run: oca_export_and_push_pot https://x-access-token:${{ secrets.GIT_PUSH_TOKEN }}@github.com/${{ github.repository }}
if: ${{ matrix.makepot == 'true' && github.event_name == 'push' && github.repository_owner == 'OCA' }}

View File

@ -5,7 +5,7 @@ exclude: |
# Files and folders generated by bots, to avoid loops # Files and folders generated by bots, to avoid loops
^setup/|/static/description/index\.html$| ^setup/|/static/description/index\.html$|
# We don't want to mess with tool-generated files # We don't want to mess with tool-generated files
.svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$| .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/|
# Maybe reactivate this when all README files include prettier ignore tags? # Maybe reactivate this when all README files include prettier ignore tags?
^README\.md$| ^README\.md$|
# Library files can have extraneous formatting (even minimized) # Library files can have extraneous formatting (even minimized)
@ -49,6 +49,7 @@ repos:
rev: 19.10b0 rev: 19.10b0
hooks: hooks:
- id: black - id: black
additional_dependencies: ["click<8.1.0"]
- repo: https://github.com/pre-commit/mirrors-prettier - repo: https://github.com/pre-commit/mirrors-prettier
rev: v1.19.1 rev: v1.19.1
hooks: hooks:

View File

@ -1,45 +0,0 @@
language: python
cache:
directories:
- $HOME/.cache/pip
- $HOME/.cache/pre-commit
python:
- "3.6"
addons:
postgresql: "9.6"
apt:
packages:
- expect-dev # provides unbuffer utility
- "swig"
- "libreoffice"
stages:
- test
jobs:
include:
- stage: test
env:
- TESTS=1 ODOO_REPO="odoo/odoo" MAKEPOT="1"
- stage: test
env:
- TESTS=1 ODOO_REPO="OCA/OCB"
env:
global:
- VERSION="13.0" TESTS="0" LINT_CHECK="0" MAKEPOT="0"
- WKHTMLTOPDF_VERSION="0.12.5"
- MQT_DEP=PIP
install:
- git clone --depth=1 https://github.com/OCA/maintainer-quality-tools.git
${HOME}/maintainer-quality-tools
- export PATH=${HOME}/maintainer-quality-tools/travis:${PATH}
- travis_install_nightly
script:
- travis_run_tests
after_success:
- travis_after_tests_success

View File

@ -1,5 +1,7 @@
[![Runbot Status](https://runbot.odoo-community.org/runbot/badge/flat/143/13.0.svg)](https://runbot.odoo-community.org/runbot/repo/github-com-oca-reporting-engine-143)
[![Build Status](https://travis-ci.com/OCA/reporting-engine.svg?branch=13.0)](https://travis-ci.com/OCA/reporting-engine) [![Runboat](https://img.shields.io/badge/runboat-Try%20me-875A7B.png)](https://runboat.odoo-community.org/builds?repo=OCA/reporting-engine&target_branch=13.0)
[![Pre-commit Status](https://github.com/OCA/reporting-engine/actions/workflows/pre-commit.yml/badge.svg?branch=13.0)](https://github.com/OCA/reporting-engine/actions/workflows/pre-commit.yml?query=branch%3A13.0)
[![Build Status](https://github.com/OCA/reporting-engine/actions/workflows/test.yml/badge.svg?branch=13.0)](https://github.com/OCA/reporting-engine/actions/workflows/test.yml?query=branch%3A13.0)
[![codecov](https://codecov.io/gh/OCA/reporting-engine/branch/13.0/graph/badge.svg)](https://codecov.io/gh/OCA/reporting-engine) [![codecov](https://codecov.io/gh/OCA/reporting-engine/branch/13.0/graph/badge.svg)](https://codecov.io/gh/OCA/reporting-engine)
[![Translation Status](https://translation.odoo-community.org/widgets/reporting-engine-13-0/-/svg-badge.svg)](https://translation.odoo-community.org/engage/reporting-engine-13-0/?utm_source=widget) [![Translation Status](https://translation.odoo-community.org/widgets/reporting-engine-13-0/-/svg-badge.svg)](https://translation.odoo-community.org/engage/reporting-engine-13-0/?utm_source=widget)
@ -26,7 +28,8 @@ addon | version | maintainers | summary
[base_comment_template](base_comment_template/) | 13.0.3.0.1 | | Add conditional mako template to any report on models that inherits comment.template. [base_comment_template](base_comment_template/) | 13.0.3.0.1 | | Add conditional mako template to any report on models that inherits comment.template.
[bi_sql_editor](bi_sql_editor/) | 13.0.1.0.1 | | BI Views builder, based on Materialized or Normal SQL Views [bi_sql_editor](bi_sql_editor/) | 13.0.1.0.1 | | BI Views builder, based on Materialized or Normal SQL Views
[kpi](kpi/) | 13.0.1.0.1 | | Key Performance Indicator [kpi](kpi/) | 13.0.1.0.1 | | Key Performance Indicator
[kpi_dashboard](kpi_dashboard/) | 13.0.1.0.0 | [![etobella](https://github.com/etobella.png?size=30px)](https://github.com/etobella) | Create Dashboards using kpis [kpi_dashboard](kpi_dashboard/) | 13.0.1.1.0 | [![etobella](https://github.com/etobella.png?size=30px)](https://github.com/etobella) | Create Dashboards using kpis
[report_async](report_async/) | 13.0.1.0.0 | [![kittiu](https://github.com/kittiu.png?size=30px)](https://github.com/kittiu) | Central place to run reports live or async
[report_batch](report_batch/) | 13.0.1.0.1 | [![bodedra](https://github.com/bodedra.png?size=30px)](https://github.com/bodedra) | Ability to print multiple QWeb reports in a single batch. [report_batch](report_batch/) | 13.0.1.0.1 | [![bodedra](https://github.com/bodedra.png?size=30px)](https://github.com/bodedra) | Ability to print multiple QWeb reports in a single batch.
[report_context](report_context/) | 13.0.1.0.0 | | Adding context to reports [report_context](report_context/) | 13.0.1.0.0 | | Adding context to reports
[report_csv](report_csv/) | 13.0.1.0.2 | | Base module to create csv report [report_csv](report_csv/) | 13.0.1.0.2 | | Base module to create csv report
@ -41,8 +44,8 @@ addon | version | maintainers | summary
[report_qweb_signer](report_qweb_signer/) | 13.0.2.1.0 | | Sign Qweb PDFs usign a PKCS#12 certificate [report_qweb_signer](report_qweb_signer/) | 13.0.2.1.0 | | Sign Qweb PDFs usign a PKCS#12 certificate
[report_wkhtmltopdf_param](report_wkhtmltopdf_param/) | 13.0.1.0.0 | | Add new parameters for a paper format to be used by wkhtmltopdf command as arguments. [report_wkhtmltopdf_param](report_wkhtmltopdf_param/) | 13.0.1.0.0 | | Add new parameters for a paper format to be used by wkhtmltopdf command as arguments.
[report_xlsx](report_xlsx/) | 13.0.1.0.6 | | Base module to create xlsx report [report_xlsx](report_xlsx/) | 13.0.1.0.6 | | Base module to create xlsx report
[report_xlsx_helper](report_xlsx_helper/) | 13.0.1.1.1 | | Report xlsx helpers [report_xlsx_helper](report_xlsx_helper/) | 13.0.1.1.3 | | Report xlsx helpers
[report_xml](report_xml/) | 13.0.1.0.1 | | Allow to generate XML reports [report_xml](report_xml/) | 13.0.1.1.0 | | Allow to generate XML reports
[//]: # (end addons) [//]: # (end addons)
@ -52,12 +55,11 @@ addon | version | maintainers | summary
This repository is licensed under [AGPL-3.0](LICENSE). This repository is licensed under [AGPL-3.0](LICENSE).
However, each module can have a totally different license, as long as they adhere to OCA However, each module can have a totally different license, as long as they adhere to Odoo Community Association (OCA)
policy. Consult each module's `__manifest__.py` file, which contains a `license` key policy. Consult each module's `__manifest__.py` file, which contains a `license` key
that explains its license. that explains its license.
---- ----
OCA, or the [Odoo Community Association](http://odoo-community.org/), is a nonprofit OCA, or the [Odoo Community Association](http://odoo-community.org/), is a nonprofit
organization whose mission is to support the collaborative development of Odoo features organization whose mission is to support the collaborative development of Odoo features
and promote its widespread use. and promote its widespread use.

View File

@ -5,7 +5,7 @@
"name": "Kpi Dashboard", "name": "Kpi Dashboard",
"summary": """ "summary": """
Create Dashboards using kpis""", Create Dashboards using kpis""",
"version": "13.0.1.0.0", "version": "13.0.1.1.0",
"license": "AGPL-3", "license": "AGPL-3",
"author": "Creu Blanca,Odoo Community Association (OCA)", "author": "Creu Blanca,Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",

View File

@ -99,6 +99,7 @@ msgid "Computation Method"
msgstr "" msgstr ""
#. module: kpi_dashboard #. module: kpi_dashboard
#: model:ir.model.fields,field_description:kpi_dashboard.field_kpi_dashboard_item__compute_on_fly
#: model:ir.model.fields,field_description:kpi_dashboard.field_kpi_kpi__compute_on_fly #: model:ir.model.fields,field_description:kpi_dashboard.field_kpi_kpi__compute_on_fly
msgid "Compute On Fly" msgid "Compute On Fly"
msgstr "" msgstr ""
@ -542,6 +543,11 @@ msgstr ""
msgid "Size Y of the widget cannot be bigger than 10" msgid "Size Y of the widget cannot be bigger than 10"
msgstr "" msgstr ""
#. module: kpi_dashboard
#: model:ir.model.fields,field_description:kpi_dashboard.field_kpi_dashboard_item__special_context
msgid "Special Context"
msgstr ""
#. module: kpi_dashboard #. module: kpi_dashboard
#: model:ir.model.fields,field_description:kpi_dashboard.field_kpi_kpi__store_history #: model:ir.model.fields,field_description:kpi_dashboard.field_kpi_kpi__store_history
msgid "Store History" msgid "Store History"

View File

@ -3,6 +3,7 @@
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.tools.safe_eval import safe_eval
class KpiDashboard(models.Model): class KpiDashboard(models.Model):
@ -113,9 +114,11 @@ class KpiDashboardItem(models.Model):
color = fields.Char() color = fields.Char()
font_color = fields.Char() font_color = fields.Char()
modify_context = fields.Boolean() modify_context = fields.Boolean()
compute_on_fly = fields.Boolean(related="kpi_id.compute_on_fly")
modify_context_expression = fields.Char() modify_context_expression = fields.Char()
modify_color = fields.Boolean() modify_color = fields.Boolean()
modify_color_expression = fields.Char() modify_color_expression = fields.Char()
special_context = fields.Char()
@api.depends("row", "size_y") @api.depends("row", "size_y")
def _compute_end_row(self): def _compute_end_row(self):
@ -189,9 +192,17 @@ class KpiDashboardItem(models.Model):
} }
) )
if self.kpi_id.compute_on_fly: if self.kpi_id.compute_on_fly:
kpi = self.kpi_id
if self.special_context:
try:
ctx = safe_eval(self.special_context)
if isinstance(ctx, dict):
kpi = kpi.with_context(**ctx)
except SyntaxError:
pass
vals.update( vals.update(
{ {
"value": self.kpi_id._compute_value(), "value": kpi._compute_value(),
"value_last_update": fields.Datetime.now(), "value_last_update": fields.Datetime.now(),
} }
) )

View File

@ -162,15 +162,16 @@
widget="ace" widget="ace"
options="{'mode': 'python'}" options="{'mode': 'python'}"
/> />
<field
name="special_context"
attrs="{'invisible': [('compute_on_fly', '=', False)]}"
/>
<field name="compute_on_fly" invisible="1" />
</group> </group>
</sheet> </sheet>
<footer> <footer>
<button
name="write" <button string="Save" special="save" class="oe_highlight" />
string="Save"
type="object"
class="oe_highlight"
/>
<button special="cancel" string="Cancel" class="oe_link" /> <button special="cancel" string="Cancel" class="oe_link" />
</footer> </footer>
</form> </form>

View File

@ -1,2 +1,3 @@
server-tools server-tools
server-backend server-backend
queue

View File

@ -0,0 +1,120 @@
============
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/13.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-13-0/reporting-engine-13-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/13.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:%2013.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
~~~~~~~~~~~~
* Kitti U. <kittiu@ecosoft.co.th>
* Saran Lim. <saranl@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/13.0/report_async>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1,5 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from . import models
from . import wizard

View File

@ -0,0 +1,23 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
{
"name": "Report Async",
"summary": "Central place to run reports live or async",
"version": "13.0.1.0.0",
"author": "Ecosoft, Odoo Community Association (OCA)",
"license": "AGPL-3",
"website": "https://github.com/OCA/reporting-engine",
"category": "Generic Modules",
"depends": ["queue_job"],
"data": [
"security/ir.model.access.csv",
"security/ir_rule.xml",
"data/mail_template.xml",
"views/report_async.xml",
"wizard/print_report_wizard.xml",
],
"demo": ["demo/report_async_demo.xml"],
"installable": True,
"maintainers": ["kittiu"],
"development_status": "Beta",
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record id="async_report_delivery" model="mail.template">
<field name="name">Report Async: New Report Available</field>
<field name="model_id" ref="base.model_ir_attachment" />
<field name="subject">Your report is available, ${object.name}</field>
<field
name="email_from"
>${object.company_id.partner_id.email_formatted|safe}</field>
<field name="partner_to">${user.partner_id.id}</field>
<field name="body_html" type="html">
<table
border="0"
cellpadding="0"
cellspacing="0"
style="background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;"
>
<tr>
<td align="center">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
style="padding: 16px; background-color: white; color: #454748; border-collapse:separate;"
>
<tbody>
<tr>
<td align="center" style="min-width: 590px;">
<table
border="0"
cellpadding="0"
cellspacing="0"
width="590"
style="min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;"
>
<tr>
<td
valign="top"
style="font-size: 13px;"
>
% set base_url = 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, )
<div>
Dear ${object.create_uid.partner_id.name or ''},
<br /><br />
Your requested report, ${object.name}, is available for <b
>
<a
href='${download_url}'
>download</a>
</b>.
<br /><br />
Have a nice day!<br />
--<br />${object.company_id.name}
</div>
</td>
</tr>
</table>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
</field>
<field name="auto_delete" eval="True" />
<field name="user_signature" eval="False" />
</record>
</data>
</odoo>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="report_async_print_document" model="report.async">
<field name="action_id" eval="ref('report_async.action_print_report_wizard')" />
<field name="allow_async" eval="0" />
</record>
</odoo>

View File

@ -0,0 +1,327 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * report_async
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: report_async
#: model:mail.template,body_html:report_async.async_report_delivery
msgid ""
"<table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" style=\"background-color: #F1F1F1; font-family:Verdana, Arial,sans-serif; color: #454748; width: 100%; border-collapse:separate;\">\n"
" <tr>\n"
" <td align=\"center\">\n"
" <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"590\" style=\"padding: 16px; background-color: white; color: #454748; border-collapse:separate;\">\n"
" <tbody>\n"
" <tr>\n"
" <td align=\"center\" style=\"min-width: 590px;\">\n"
" <table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" width=\"590\" style=\"min-width: 590px; background-color: white; padding: 0px 8px 0px 8px; border-collapse:separate;\">\n"
" <tr>\n"
" <td valign=\"top\" style=\"font-size: 13px;\">\n"
" % set base_url = object.env['ir.config_parameter'].sudo().get_param('web.base.url')\n"
" % set download_url = '%s/web/content/ir.attachment/%s/datas/%s?download=true' % (base_url, object.id, object.name, )\n"
" <div>\n"
" Dear ${object.create_uid.partner_id.name or ''},\n"
" <br/><br/>\n"
" Your requested report, ${object.name}, is available for <b>\n"
" <a href=\"${download_url}\">download</a>\n"
" </b>.\n"
" <br/><br/>\n"
" Have a nice day!<br/>\n"
" --<br/>${object.company_id.name}\n"
" </div>\n"
" </td>\n"
" </tr>\n"
" </table>\n"
" </td>\n"
" </tr>\n"
" </tbody>\n"
" </table>\n"
" </td>\n"
" </tr>\n"
" </table>\n"
" "
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__allow_async
msgid "Allow Async"
msgstr ""
#. module: report_async
#: code:addons/report_async/models/report_async.py:0
#, python-format
msgid "Background process not allowed."
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.print_report_wizard
msgid "Cancel"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__create_uid
#: model:ir.model.fields,field_description:report_async.field_report_async__create_uid
msgid "Created by"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__create_date
#: model:ir.model.fields,field_description:report_async.field_report_async__create_date
msgid "Created on"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__display_name
#: model:ir.model.fields,field_description:report_async.field_report_async__display_name
msgid "Display Name"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__reference
msgid "Document"
msgstr ""
#. module: report_async
#: model:ir.model.fields.selection,name:report_async.selection__report_async__job_status__done
msgid "Done"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__email_notify
msgid "Email Notification"
msgstr ""
#. module: report_async
#: model:ir.model.fields.selection,name:report_async.selection__report_async__job_status__enqueued
msgid "Enqueued"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.print_report_wizard
msgid "Execute"
msgstr ""
#. module: report_async
#: model:ir.model.fields.selection,name:report_async.selection__report_async__job_status__failed
msgid "Failed"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__file_ids
msgid "File"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_tree
msgid "Files"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__group_ids
msgid "Groups"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__id
#: model:ir.model.fields,field_description:report_async.field_report_async__id
msgid "ID"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__job_ids
msgid "Job"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__job_info
msgid "Job Info"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__job_status
msgid "Job Status"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
msgid "Jobs"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard____last_update
#: model:ir.model.fields,field_description:report_async.field_report_async____last_update
msgid "Last Modified on"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
msgid "Last Run Job Error"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__write_uid
#: model:ir.model.fields,field_description:report_async.field_report_async__write_uid
msgid "Last Updated by"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__write_date
#: model:ir.model.fields,field_description:report_async.field_report_async__write_date
msgid "Last Updated on"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__job_info
msgid "Latest Job Error Message"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__job_status
msgid "Latest Job Status"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__file_ids
msgid "List all files created by this report background process"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__job_ids
msgid "List all jobs related to this running report"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__name
msgid "Name"
msgstr ""
#. module: report_async
#: model_terms:ir.actions.act_window,help:report_async.action_view_files
msgid "No files found"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__group_ids
msgid ""
"Only user in selected groups can use this report.If left blank, everyone can"
" use"
msgstr ""
#. module: report_async
#: model:ir.model.fields.selection,name:report_async.selection__report_async__job_status__pending
msgid "Pending"
msgstr ""
#. module: report_async
#: model:ir.actions.act_window,name:report_async.action_print_report_wizard
msgid "Print Document"
msgstr ""
#. module: report_async
#: model:ir.model,name:report_async.model_print_report_wizard
msgid "Print Report Wizard"
msgstr ""
#. module: report_async
#: model:ir.model,name:report_async.model_ir_actions_report
msgid "Report Action"
msgstr ""
#. module: report_async
#: model:ir.model,name:report_async.model_report_async
msgid "Report Async"
msgstr ""
#. module: report_async
#: model:ir.actions.act_window,name:report_async.action_report_async
#: model:ir.ui.menu,name:report_async.menu_report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_search
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_tree
msgid "Report Center"
msgstr ""
#. module: report_async
#: model:ir.actions.act_window,name:report_async.action_view_files
msgid "Report Files"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_print_report_wizard__action_report_id
msgid "Report Template"
msgstr ""
#. module: report_async
#: model:ir.model.fields,field_description:report_async.field_report_async__action_id
msgid "Reports"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_tree
msgid "Run Background"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_tree
msgid "Run Now"
msgstr ""
#. module: report_async
#: model_terms:ir.actions.act_window,help:report_async.action_report_async
msgid "Run reports asyncronously"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__email_notify
msgid "Send email with link to report, when it is ready"
msgstr ""
#. module: report_async
#: model:ir.model.fields.selection,name:report_async.selection__report_async__job_status__started
msgid "Started"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
msgid ""
"The last <i class=\"fa fa-cogs\"/> <b>running job</b> was failed.\n"
" Please contact your system administrator."
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
msgid ""
"The last <i class=\"fa fa-cogs\"/> <b>running job</b> was succeed.\n"
" You can check the result in <i class=\"fa fa-copy\"/><b> Files</b>"
msgstr ""
#. module: report_async
#: model_terms:ir.ui.view,arch_db:report_async.view_report_async_form
msgid ""
"The report will be running by <i class=\"fa fa-cogs\"/>\n"
" <b>job</b>, and will be available at\n"
" <i class=\"fa fa-copy\"/><b> Files</b>"
msgstr ""
#. module: report_async
#: model:ir.model.fields,help:report_async.field_report_async__allow_async
msgid ""
"This is not automatic field, please check if you want to allow this report "
"in background process"
msgstr ""
#. module: report_async
#: model:mail.template,subject:report_async.async_report_delivery
msgid "Your report is available, ${object.name}"
msgstr ""

View File

@ -0,0 +1,5 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from . import report_async
from . import ir_report

View File

@ -0,0 +1,23 @@
# 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
# Define all supported report_type
REPORT_TYPES = ["qweb-pdf", "qweb-text", "qweb-xml", "csv", "excel", "xlsx"]
class Report(models.Model):
_inherit = "ir.actions.report"
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):
rpt_async_id = res["context"]["active_id"]
report_async = self.env["report.async"].browse(rpt_async_id)
if res["report_type"] in REPORT_TYPES:
report_async.with_delay().run_report(
res["context"].get("active_ids", []), data, self.id, self._uid
)
return {}
return res

View File

@ -0,0 +1,170 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
import base64
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tools.safe_eval import safe_eval
from odoo.addons.queue_job.job import job
# Define all supported report_type
REPORT_TYPES_FUNC = {
"qweb-pdf": "render_qweb_pdf",
"qweb-text": "render_qweb_text",
"qweb-xml": "render_qweb_xml",
"csv": "render_csv",
"excel": "render_excel",
"xlsx": "render_xlsx",
}
class ReportAsync(models.Model):
_name = "report.async"
_description = "Report Async"
action_id = fields.Many2one(
comodel_name="ir.actions.act_window", string="Reports", required=True,
)
allow_async = fields.Boolean(
string="Allow Async",
default=False,
help="This is not automatic field, please check if you want to allow "
"this report in background process",
)
name = fields.Char(string="Name", related="action_id.display_name",)
email_notify = fields.Boolean(
string="Email Notification",
help="Send email with link to report, when it is ready",
)
group_ids = fields.Many2many(
string="Groups",
comodel_name="res.groups",
help="Only user in selected groups can use this report."
"If left blank, everyone can use",
)
job_ids = fields.Many2many(
comodel_name="queue.job",
compute="_compute_job",
help="List all jobs related to this running report",
)
job_status = fields.Selection(
selection=[
("pending", "Pending"),
("enqueued", "Enqueued"),
("started", "Started"),
("done", "Done"),
("failed", "Failed"),
],
compute="_compute_job",
help="Latest Job Status",
)
job_info = fields.Text(compute="_compute_job", help="Latest Job Error Message",)
file_ids = fields.Many2many(
comodel_name="ir.attachment",
compute="_compute_file",
help="List all files created by this report background process",
)
def _compute_job(self):
for rec in self:
rec.job_ids = (
self.sudo()
.env["queue.job"]
.search(
[
("func_string", "like", "report.async(%s,)" % rec.id),
("user_id", "=", self._uid),
],
order="id desc",
)
)
rec.job_status = rec.job_ids[0].sudo().state if rec.job_ids else False
rec.job_info = rec.job_ids[0].sudo().exc_info if rec.job_ids else False
def _compute_file(self):
files = self.env["ir.attachment"].search(
[
("res_model", "=", "report.async"),
("res_id", "in", self.ids),
("create_uid", "=", self._uid),
],
order="id desc",
)
for rec in self:
rec.file_ids = files.filtered(lambda l: l.res_id == rec.id)
def run_now(self):
self.ensure_one()
action = self.env.ref(self.action_id.xml_id)
result = action.read()[0]
ctx = safe_eval(result.get("context", {}))
ctx.update({"async_process": False})
result["context"] = ctx
return result
def run_async(self):
self.ensure_one()
if not self.allow_async:
raise UserError(_("Background process not allowed."))
action = self.env.ref(self.action_id.xml_id)
result = action.read()[0]
ctx = safe_eval(result.get("context", {}))
ctx.update({"async_process": True})
result["context"] = ctx
return result
def view_files(self):
self.ensure_one()
action = self.env.ref("report_async.action_view_files")
result = action.read()[0]
result["domain"] = [("id", "in", self.file_ids.ids)]
return result
def view_jobs(self):
self.ensure_one()
action = self.env.ref("queue_job.action_queue_job")
result = action.read()[0]
result["domain"] = [("id", "in", self.job_ids.ids)]
result["context"] = {}
return result
@api.model
@job
def run_report(self, docids, data, report_id, user_id):
report = self.env["ir.actions.report"].browse(report_id)
func = REPORT_TYPES_FUNC[report.report_type]
# Run report
out_file, file_ext = getattr(report, func)(docids, data)
out_file = base64.b64encode(out_file)
out_name = "{}.{}".format(report.name, file_ext)
# Save report to attachment
attachment = (
self.env["ir.attachment"]
.sudo()
.create(
{
"name": out_name,
"datas": out_file,
"type": "binary",
"res_model": "report.async",
"res_id": self.id,
}
)
)
self._cr.execute(
"""
UPDATE ir_attachment SET create_uid = %s, write_uid = %s
WHERE id = %s""",
(self._uid, self._uid, attachment.id),
)
# Send email
if self.email_notify:
self._send_email(attachment)
def _send_email(self, attachment):
template = self.env.ref("report_async.async_report_delivery")
template.send_mail(
attachment.id, notif_layout="mail.mail_notification_light", force_send=False
)

View File

@ -0,0 +1,2 @@
* Kitti U. <kittiu@ecosoft.co.th>
* Saran Lim. <saranl@ecosoft.co.th>

View File

@ -0,0 +1,16 @@
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.

View File

@ -0,0 +1,19 @@
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.

View File

@ -0,0 +1,3 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
access_report_async,report.async.user,model_report_async,base.group_user,1,0,0,0
access_report_async_sudo,report.async.sudo,model_report_async,base.group_no_one,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_report_async report.async.user model_report_async base.group_user 1 0 0 0
3 access_report_async_sudo report.async.sudo model_report_async base.group_no_one 1 1 1 1

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="rule_report_async_access_by_group" model="ir.rule">
<field name="name">Report Async by Groups</field>
<field name="model_id" ref="model_report_async" />
<field name="groups" eval="[(4, ref('base.group_user'))]" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="False" />
<field name="perm_write" eval="False" />
<field name="perm_unlink" eval="False" />
<field
name="domain_force"
>['|', ('group_ids', '=', False), ('group_ids', 'in', [g.id for g in user.groups_id])]</field>
</record>
<record id="rule_report_async_access_all" model="ir.rule">
<field name="name">Report Async by Groups</field>
<field name="model_id" ref="model_report_async" />
<field name="groups" eval="[(4, ref('base.group_no_one'))]" />
<field name="perm_read" eval="True" />
<field name="perm_create" eval="True" />
<field name="perm_write" eval="True" />
<field name="perm_unlink" eval="True" />
<field name="domain_force">[(1,'=', 1)]</field>
</record>
</odoo>

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,460 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.15.1: http://docutils.sourceforge.net/" />
<title>Report Async</title>
<style type="text/css">
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to
customize this style sheet.
*/
/* used to remove borders from tables and images */
.borderless, table.borderless td, table.borderless th {
border: 0 }
table.borderless td, table.borderless th {
/* Override padding for "table.docutils td" with "! important".
The right padding separates the table cells. */
padding: 0 0.5em 0 0 ! important }
.first {
/* Override more specific margin styles with "! important". */
margin-top: 0 ! important }
.last, .with-subtitle {
margin-bottom: 0 ! important }
.hidden {
display: none }
.subscript {
vertical-align: sub;
font-size: smaller }
.superscript {
vertical-align: super;
font-size: smaller }
a.toc-backref {
text-decoration: none ;
color: black }
blockquote.epigraph {
margin: 2em 5em ; }
dl.docutils dd {
margin-bottom: 0.5em }
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] {
overflow: hidden;
}
/* Uncomment (and remove this text!) to get bold-faced definition list terms
dl.docutils dt {
font-weight: bold }
*/
div.abstract {
margin: 2em 5em }
div.abstract p.topic-title {
font-weight: bold ;
text-align: center }
div.admonition, div.attention, div.caution, div.danger, div.error,
div.hint, div.important, div.note, div.tip, div.warning {
margin: 2em ;
border: medium outset ;
padding: 1em }
div.admonition p.admonition-title, div.hint p.admonition-title,
div.important p.admonition-title, div.note p.admonition-title,
div.tip p.admonition-title {
font-weight: bold ;
font-family: sans-serif }
div.attention p.admonition-title, div.caution p.admonition-title,
div.danger p.admonition-title, div.error p.admonition-title,
div.warning p.admonition-title, .code .error {
color: red ;
font-weight: bold ;
font-family: sans-serif }
/* Uncomment (and remove this text!) to get reduced vertical space in
compound paragraphs.
div.compound .compound-first, div.compound .compound-middle {
margin-bottom: 0.5em }
div.compound .compound-last, div.compound .compound-middle {
margin-top: 0.5em }
*/
div.dedication {
margin: 2em 5em ;
text-align: center ;
font-style: italic }
div.dedication p.topic-title {
font-weight: bold ;
font-style: normal }
div.figure {
margin-left: 2em ;
margin-right: 2em }
div.footer, div.header {
clear: both;
font-size: smaller }
div.line-block {
display: block ;
margin-top: 1em ;
margin-bottom: 1em }
div.line-block div.line-block {
margin-top: 0 ;
margin-bottom: 0 ;
margin-left: 1.5em }
div.sidebar {
margin: 0 0 0.5em 1em ;
border: medium outset ;
padding: 1em ;
background-color: #ffffee ;
width: 40% ;
float: right ;
clear: right }
div.sidebar p.rubric {
font-family: sans-serif ;
font-size: medium }
div.system-messages {
margin: 5em }
div.system-messages h1 {
color: red }
div.system-message {
border: medium outset ;
padding: 1em }
div.system-message p.system-message-title {
color: red ;
font-weight: bold }
div.topic {
margin: 2em }
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle,
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle {
margin-top: 0.4em }
h1.title {
text-align: center }
h2.subtitle {
text-align: center }
hr.docutils {
width: 75% }
img.align-left, .figure.align-left, object.align-left, table.align-left {
clear: left ;
float: left ;
margin-right: 1em }
img.align-right, .figure.align-right, object.align-right, table.align-right {
clear: right ;
float: right ;
margin-left: 1em }
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left }
.align-center {
clear: both ;
text-align: center }
.align-right {
text-align: right }
/* reset inner alignment in figures */
div.align-right {
text-align: inherit }
/* div.align-center * { */
/* text-align: left } */
.align-top {
vertical-align: top }
.align-middle {
vertical-align: middle }
.align-bottom {
vertical-align: bottom }
ol.simple, ul.simple {
margin-bottom: 1em }
ol.arabic {
list-style: decimal }
ol.loweralpha {
list-style: lower-alpha }
ol.upperalpha {
list-style: upper-alpha }
ol.lowerroman {
list-style: lower-roman }
ol.upperroman {
list-style: upper-roman }
p.attribution {
text-align: right ;
margin-left: 50% }
p.caption {
font-style: italic }
p.credits {
font-style: italic ;
font-size: smaller }
p.label {
white-space: nowrap }
p.rubric {
font-weight: bold ;
font-size: larger ;
color: maroon ;
text-align: center }
p.sidebar-title {
font-family: sans-serif ;
font-weight: bold ;
font-size: larger }
p.sidebar-subtitle {
font-family: sans-serif ;
font-weight: bold }
p.topic-title {
font-weight: bold }
pre.address {
margin-bottom: 0 ;
margin-top: 0 ;
font: inherit }
pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
pre.code .literal.string, code .literal.string { color: #0C5404 }
pre.code .name.builtin, code .name.builtin { color: #352B84 }
pre.code .deleted, code .deleted { background-color: #DEB0A1}
pre.code .inserted, code .inserted { background-color: #A3D289}
span.classifier {
font-family: sans-serif ;
font-style: oblique }
span.classifier-delimiter {
font-family: sans-serif ;
font-weight: bold }
span.interpreted {
font-family: sans-serif }
span.option {
white-space: nowrap }
span.pre {
white-space: pre }
span.problematic {
color: red }
span.section-subtitle {
/* font-size relative to parent (h1..h6 element) */
font-size: 80% }
table.citation {
border-left: solid 1px gray;
margin-left: 1px }
table.docinfo {
margin: 2em 4em }
table.docutils {
margin-top: 0.5em ;
margin-bottom: 0.5em }
table.footnote {
border-left: solid 1px black;
margin-left: 1px }
table.docutils td, table.docutils th,
table.docinfo td, table.docinfo th {
padding-left: 0.5em ;
padding-right: 0.5em ;
vertical-align: top }
table.docutils th.field-name, table.docinfo th.docinfo-name {
font-weight: bold ;
text-align: left ;
white-space: nowrap ;
padding-left: 0 }
/* "booktabs" style (no vertical lines) */
table.docutils.booktabs {
border: 0px;
border-top: 2px solid;
border-bottom: 2px solid;
border-collapse: collapse;
}
table.docutils.booktabs * {
border: 0px;
}
table.docutils.booktabs th {
border-bottom: thin solid;
text-align: left;
}
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
font-size: 100% }
ul.auto-toc {
list-style-type: none }
</style>
</head>
<body>
<div class="document" id="report-async">
<h1 class="title">Report Async</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_async"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_async"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>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,</p>
<ol class="arabic simple">
<li>Run Now - run report immediately as per normal.</li>
<li>Run Background - put the report execution to queue job.</li>
</ol>
<p>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.</p>
<p>Notes:</p>
<ul class="simple">
<li>Only user with Technical Feature rights can manage the report.</li>
<li>Every internal user will have right to execute the report allowed for his/her groups.</li>
<li>The files created are owned and viewable only by the person who run the report.</li>
<li>Job queue manager can also see all jobs for each reports.</li>
</ul>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#usage" id="id1">Usage</a></li>
<li><a class="reference internal" href="#bug-tracker" id="id2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="usage">
<h1><a class="toc-backref" href="#id1">Usage</a></h1>
<p>Menu: Dashboard &gt; Report Center</p>
<p>As Technical Feature users, you can manage reports for Report Center.</p>
<ul class="simple">
<li><strong>Report:</strong> choose the report (a window action). Although the option show all window actions
it only make sense for window actions that launch reports.</li>
<li><strong>Allow Async:</strong> 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.</li>
<li><strong>Email Notification:</strong> if checked, once the background process is completed, email with link to download
report will be sent.</li>
<li><strong>Groups:</strong> select user groups allowed to use this report. If left blank, all user can use.</li>
</ul>
<p>As normal user, you can run your reports from Report Center</p>
<ul class="simple">
<li><strong>Run Now button:</strong> to run report immediately as per normal.</li>
<li><strong>Run Background button:</strong> to run report asynchronously. Fall back to run now, if not report that produce file.</li>
<li><strong>Job Status:</strong> show status of the latest run job. If job fail, exception error will also shown</li>
<li><strong>Files:</strong> show all files being produced by the job as run by the user.</li>
<li><strong>Jobs:</strong> show all jobs triggered by this report as run by the user. Only job queue manager have access to this button.</li>
</ul>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/reporting-engine/issues">GitHub Issues</a>.
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
<a class="reference external" href="https://github.com/OCA/reporting-engine/issues/new?body=module:%20report_async%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h1><a class="toc-backref" href="#id3">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id4">Authors</a></h2>
<ul class="simple">
<li>Ecosoft</li>
</ul>
</div>
<div class="section" id="contributors">
<h2><a class="toc-backref" href="#id5">Contributors</a></h2>
<ul class="simple">
<li>Kitti U. &lt;<a class="reference external" href="mailto:kittiu&#64;ecosoft.co.th">kittiu&#64;ecosoft.co.th</a>&gt;</li>
<li>Saran Lim. &lt;<a class="reference external" href="mailto:saranl&#64;ecosoft.co.th">saranl&#64;ecosoft.co.th</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<p>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.</p>
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p>
<p><a class="reference external" href="https://github.com/kittiu"><img alt="kittiu" src="https://github.com/kittiu.png?size=40px" /></a></p>
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_async">OCA/reporting-engine</a> project on GitHub.</p>
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p>
</div>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1 @@
from . import test_report_async

View File

@ -0,0 +1,55 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from odoo.exceptions import UserError
from odoo.tests import common
from odoo.tests.common import Form
class TestJobChannel(common.TransactionCase):
def setUp(self):
super(TestJobChannel, self).setUp()
self.print_doc = self.env.ref("report_async." "report_async_print_document")
self.test_rec = self.env.ref("base.module_mail")
self.test_rpt = self.env.ref("base.ir_module_reference_print")
def _print_wizard(self, res):
obj = self.env[res["res_model"]]
ctx = {
"active_model": self.print_doc._name,
"active_id": self.print_doc.id,
}
ctx.update(res["context"])
with Form(obj.with_context(ctx)) as form:
form.reference = "{},{}".format(self.test_rec._name, self.test_rec.id)
form.action_report_id = self.test_rpt
print_wizard = form.save()
return print_wizard
def test_1_run_now(self):
"""Run now will return report action as normal"""
res = self.print_doc.run_now()
report_action = self._print_wizard(res).print_report()
self.assertEquals(report_action["type"], "ir.actions.report")
def test_2_run_async(self):
"""Run background will return nothing, job started"""
with self.assertRaises(UserError):
self.print_doc.run_async()
self.print_doc.write({"allow_async": True, "email_notify": True})
res = self.print_doc.run_async()
print_wizard = self._print_wizard(res)
report_action = print_wizard.print_report()
self.assertEquals(report_action, {}) # Do not run report yet
self.assertEquals(self.print_doc.job_status, "pending") # Job started
# Test produce file (as queue will not run in test mode)
docids = [print_wizard.reference.id]
data = None
report_id = self.test_rpt.id
user_id = self.env.user.id
self.print_doc.run_report(docids, data, report_id, user_id)
# Check name of the newly producted file
# Note: on env with test-enable, always fall back to render_qweb_html
self.assertIn(self.test_rpt.name, self.print_doc.file_ids[0].name)
# View fileds/jobs
self.print_doc.view_files()
self.print_doc.view_jobs()

View File

@ -0,0 +1,177 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_report_async_tree" model="ir.ui.view">
<field name="name">report.async.tree</field>
<field name="model">report.async</field>
<field name="arch" type="xml">
<tree string="Report Center">
<field name="action_id" />
<button type="object" name="run_now" string="Run Now" icon="fa-bolt" />
<button
type="object"
name="run_async"
string="Run Background"
icon="fa-cogs"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
<button
type="object"
name="view_files"
string="Files"
icon="fa-copy"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
<field name="allow_async" invisible="1" />
<field
name="job_status"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
<field name="email_notify" />
</tree>
</field>
</record>
<record id="view_report_async_form" model="ir.ui.view">
<field name="name">report.async.form</field>
<field name="model">report.async</field>
<field name="arch" type="xml">
<form>
<div
class="alert alert-warning"
role="alert"
attrs="{'invisible': ['|', ('job_status', 'in', ['done', 'failed', False]),
('allow_async', '=', False)]}"
style="margin-bottom:0px;"
>
<p>
The report will be running by <i class="fa fa-cogs" />
<b>job</b>, and will be available at
<i class="fa fa-copy" /><b> Files</b>
</p>
</div>
<div
class="alert alert-danger"
role="alert"
attrs="{'invisible': ['|', ('job_status', '!=', 'failed'),
('allow_async', '=', False)]}"
style="margin-bottom:0px;"
>
<p>
The last <i class="fa fa-cogs" /> <b>running job</b> was failed.
Please contact your system administrator.
</p>
</div>
<div
class="alert alert-success"
role="alert"
attrs="{'invisible': ['|', ('job_status', '!=', 'done'),
('allow_async', '=', False)]}"
style="margin-bottom:0px;"
>
<p>
The last <i class="fa fa-cogs" /> <b
>running job</b> was succeed.
You can check the result in <i class="fa fa-copy" /><b
> Files</b>
</p>
</div>
<sheet>
<div class="oe_read_only oe_right oe_button_box" name="buttons">
<button
type="object"
name="run_now"
string="Run Now"
icon="fa-bolt"
/>
<button
type="object"
name="run_async"
string="Run Background"
icon="fa-cogs"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
<button
type="object"
name="view_files"
string="Files"
icon="fa-copy"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
<button
type="object"
name="view_jobs"
string="Jobs"
icon="fa-align-justify"
groups="queue_job.group_queue_job_manager"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
</div>
<group>
<group>
<field
name="action_id"
options="{'no_open': True, 'no_create_edit': True}"
/>
<field name="allow_async" />
<field
name="email_notify"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
</group>
<group>
<field
name="job_status"
attrs="{'invisible': [('allow_async', '=', False)]}"
/>
<field name="group_ids" widget="many2many_tags" />
</group>
<group
name="job_info"
string="Last Run Job Error"
colspan="2"
attrs="{'invisible': ['|', ('job_info', '=', False), ('allow_async', '=', False)]}"
>
<field nolabel="1" name="job_info" />
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_report_async_search" model="ir.ui.view">
<field name="name">report.async.search</field>
<field name="model">report.async</field>
<field name="arch" type="xml">
<search string="Report Center">
<field name="action_id" />
</search>
</field>
</record>
<record id="action_report_async" model="ir.actions.act_window">
<field name="name">Report Center</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">report.async</field>
<field name="help">Run reports asyncronously</field>
</record>
<menuitem
id="menu_report_async"
parent="base.menu_board_root"
action="action_report_async"
sequence="10"
/>
<record id="action_view_files" model="ir.actions.act_window">
<field name="name">Report Files</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">ir.attachment</field>
<field name="view_id" eval="False" />
<field name="search_view_id" ref="base.view_attachment_search" />
<field name="view_mode">kanban,tree,form</field>
<field
name="domain"
>[('res_model', '=', 'report.async'), ('create_uid', '=', uid)]</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
No files found
</p>
</field>
</record>
</odoo>

View File

@ -0,0 +1,4 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)
from . import print_report_wizard

View File

@ -0,0 +1,41 @@
# 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 api, fields, models
class PrintReportWizard(models.TransientModel):
_name = "print.report.wizard"
_description = "Print Report Wizard"
reference = fields.Reference(
string="Document", selection="_reference_models", required=True,
)
action_report_id = fields.Many2one(
comodel_name="ir.actions.report", string="Report Template", required=True,
)
@api.model
def _reference_models(self):
excludes = ["res.company"]
models = self.env["ir.model"].search(
[
("state", "!=", "manual"),
("transient", "=", False),
("model", "not in", excludes),
]
)
return [(model.model, model.name) for model in models]
@api.onchange("reference")
def _onchange_reference(self):
self.ensure_one()
domain = [("id", "in", [])]
self.action_report_id = False
if self.reference:
domain = [("model", "=", self.reference._name)]
return {"domain": {"action_report_id": domain}}
def print_report(self):
self.ensure_one()
return self.action_report_id.report_action(self.reference, config=False)

View File

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="print_report_wizard" model="ir.ui.view">
<field name="name">print.report.wizard</field>
<field name="model">print.report.wizard</field>
<field name="arch" type="xml">
<form>
<group>
<group>
<field name="reference" />
</group>
<group>
<field
name="action_report_id"
options="{'no_open': True, 'no_create_edit': True}"
/>
</group>
</group>
<footer>
<button
name="print_report"
type="object"
string="Execute"
class="oe_highlight"
/>
<button special="cancel" string="Cancel" />
</footer>
</form>
</field>
</record>
<record id="action_print_report_wizard" model="ir.actions.act_window">
<field name="name">Print Document</field>
<field name="res_model">print.report.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</odoo>

View File

@ -10,7 +10,10 @@
"author": "XCG Consulting," "ACSONE SA/NV," "Odoo Community Association (OCA)", "author": "XCG Consulting," "ACSONE SA/NV," "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"depends": ["web"], "depends": ["web"],
"external_dependencies": {"python": ["py3o.template", "py3o.formats", "PyPDF2"]}, "external_dependencies": {
"python": ["py3o.template", "py3o.formats", "PyPDF2"],
"deb": ["libreoffice"],
},
"data": [ "data": [
"security/ir.model.access.csv", "security/ir.model.access.csv",
"views/menu.xml", "views/menu.xml",

View File

@ -9,7 +9,10 @@
"author": "XCG Consulting," "ACSONE SA/NV," "Odoo Community Association (OCA)", "author": "XCG Consulting," "ACSONE SA/NV," "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"depends": ["report_py3o"], "depends": ["report_py3o"],
"external_dependencies": {"python": ["py3o.template", "py3o.formats"]}, "external_dependencies": {
"python": ["py3o.template", "py3o.formats"],
"deb": ["libreoffice"],
},
"demo": ["demo/report_py3o.xml", "demo/py3o_pdf_options.xml"], "demo": ["demo/report_py3o.xml", "demo/py3o_pdf_options.xml"],
"data": [ "data": [
"views/ir_actions_report.xml", "views/ir_actions_report.xml",

View File

@ -38,7 +38,7 @@ Installation
To install this module, you need to install Java JDK Headlees, e.g.: To install this module, you need to install Java JDK Headlees, e.g.:
apt-get install openjdk-8-jre-headless apt-get install default-jre-headless
Configuration Configuration
============= =============
@ -88,13 +88,17 @@ when signing date is important, for example, when signing customer invoices.
You can try the signing with the demo report that is included for customers You can try the signing with the demo report that is included for customers
called "Test PDF certificate". called "Test PDF certificate".
You can set extra parameters of JSignPdf library in the system parameter
named 'report_qweb_signer.java_position_parameters', for example '-V' to
visible signature into pdf. You can also set extra parameters for Java in the
system parameter named 'report_qweb_signer.java_parameters'.
Known issues / Roadmap Known issues / Roadmap
====================== ======================
* When signing multiple documents (if 'Allow only one document' is disable) * When signing multiple documents (if 'Allow only one document' is disable)
then 'Save as attachment' is not applied and signed result is not then 'Save as attachment' is not applied and signed result is not
saved as attachment. saved as attachment.
* To have a visible signature through an image embedded in the resulting PDF.
* Add tests. * Add tests.
Bug Tracker Bug Tracker
@ -125,6 +129,8 @@ Contributors
* Pedro M. Baeza * Pedro M. Baeza
* Jairo Llopis * Jairo Llopis
* David Vidal * David Vidal
* Santi Argüeso <santi@comunitea.com>
* Omar Castiñeira <omar@comunitea.com>
Other credits Other credits
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
@ -132,9 +138,7 @@ Other credits
External utilities External utilities
++++++++++++++++++ ++++++++++++++++++
* iText v1.4.8: © 2000-2006, Paulo Soares, Bruno Lowagie and others - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ - http://sourceforge.net/projects/itext * JSignPdf: © Josef Cacek - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ - http://jsignpdf.sourceforge.net/
* jPdfSign: © 2006 Jan Peter Stotz - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ (inherited from iText) - http://private.sit.fraunhofer.de/~stotz/software/jpdfsign
* Modified jPdfSign: © 2015 Antonio Espinosa - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ (inherited from iText) - static/src/java/JPdfSign.java
Icon Icon
++++ ++++

View File

@ -13,7 +13,10 @@
"license": "AGPL-3", "license": "AGPL-3",
"installable": True, "installable": True,
"depends": ["web_editor"], "depends": ["web_editor"],
"external_dependencies": {"python": ["endesive", "cryptography"]}, "external_dependencies": {
"python": ["endesive", "cryptography"],
"deb": ["default-jre-headless"],
},
"data": [ "data": [
"data/defaults.xml", "data/defaults.xml",
"security/ir.model.access.csv", "security/ir.model.access.csv",

View File

@ -2,6 +2,10 @@
<odoo noupdate="1"> <odoo noupdate="1">
<record model="ir.config_parameter" id="report_qweb_signer_java_param"> <record model="ir.config_parameter" id="report_qweb_signer_java_param">
<field name="key">report_qweb_signer.java_parameters</field> <field name="key">report_qweb_signer.java_parameters</field>
<field name="value">-Xms4M -Xmx4M -XX:CompressedClassSpaceSize=256m</field> <field name="value">-Xms16M -Xmx16M -XX:CompressedClassSpaceSize=256m</field>
</record>
<record model="ir.config_parameter" id="report_qweb_signer_java_position_param">
<field name="key">report_qweb_signer.java_position_parameters</field>
<field name="value">-llx 400 -lly 820 -urx 600 -ury 100 -fs 8</field>
</record> </record>
</odoo> </odoo>

View File

@ -33,14 +33,16 @@ License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
</t> </t>
</t> </t>
</template> </template>
<report <record id="partner_demo_report" model="ir.actions.report">
id="partner_demo_report" <field name="name">Test PDF certificate</field>
model="res.partner" <field name="model">res.partner</field>
string="Test PDF certificate" <field name="report_type">qweb-pdf</field>
report_type="qweb-pdf" <field name="report_name">report_qweb_signer.report_partner_demo</field>
name="report_qweb_signer.report_partner_demo" <field
file="report_qweb_signer.report_partner_demo" name="attachment"
attachment_use="True" >'test_' + (object.name or '').replace(' ', '_').lower() + '.pdf'</field>
attachment="'test_' + (object.name or '').replace(' ', '_').lower() + '.pdf'" <field name="attachment_use">True</field>
/> <field name="binding_model_id" ref="base.model_res_partner" />
<field name="binding_type">report</field>
</record>
</odoo> </odoo>

View File

@ -39,11 +39,13 @@ class IrActionsReport(models.Model):
"""Obtain the proper certificate for the report and the conditions.""" """Obtain the proper certificate for the report and the conditions."""
if self.report_type != "qweb-pdf": if self.report_type != "qweb-pdf":
return False return False
company_id = self.env.company.id
if res_ids:
obj = self.env[self.model].browse(res_ids[0])
if "company_id" in obj:
company_id = obj.company_id.id or company_id
certificates = self.env["report.certificate"].search( certificates = self.env["report.certificate"].search(
[ [("company_id", "=", company_id), ("model_id", "=", self.model)]
("company_id", "=", self.env.user.company_id.id),
("model_id", "=", self.model),
]
) )
if not certificates: if not certificates:
return False return False
@ -122,8 +124,13 @@ class IrActionsReport(models.Model):
irc_param = self.env["ir.config_parameter"].sudo() irc_param = self.env["ir.config_parameter"].sudo()
java_bin = "java -jar" java_bin = "java -jar"
java_param = irc_param.get_param("report_qweb_signer.java_parameters") java_param = irc_param.get_param("report_qweb_signer.java_parameters")
jar = "{}/../static/jar/jPdfSign.jar".format(me) java_position_param = irc_param.get_param(
return "{} {} {} {}".format(java_bin, java_param, jar, opts) "report_qweb_signer.java_position_parameters"
)
jar = "{}/../static/jar/JSignPdf.jar".format(me)
return "{} {} {} {} {}".format(
java_bin, java_param, jar, opts, java_position_param
)
def _get_endesive_params(self, certificate): def _get_endesive_params(self, certificate):
date = datetime.datetime.utcnow() - datetime.timedelta(hours=12) date = datetime.datetime.utcnow() - datetime.timedelta(hours=12)
@ -160,7 +167,7 @@ class IrActionsReport(models.Model):
return pdfsigned return pdfsigned
def pdf_sign(self, pdf, certificate): def pdf_sign(self, pdf, certificate):
pdfsigned = pdf + ".signed.pdf" pdfsigned = pdf[:-4] + "_signed.pdf"
p12 = _normalize_filepath(certificate.path) p12 = _normalize_filepath(certificate.path)
passwd = _normalize_filepath(certificate.password_file) passwd = _normalize_filepath(certificate.password_file)
method_used = certificate.signing_method method_used = certificate.signing_method
@ -169,7 +176,10 @@ class IrActionsReport(models.Model):
_("Signing report (PDF): " "Certificate or password file not found") _("Signing report (PDF): " "Certificate or password file not found")
) )
if method_used == "java": if method_used == "java":
signer_opts = '"{}" "{}" "{}" "{}"'.format(p12, pdf, pdfsigned, passwd) passwd_f = open(passwd, "tr")
passwd = passwd_f.read().strip()
passwd_f.close()
signer_opts = ' "{}" -ksf "{}" -ksp "{}" -d "/tmp"'.format(pdf, p12, passwd)
signer = self._signer_bin(signer_opts) signer = self._signer_bin(signer_opts)
process = subprocess.Popen( process = subprocess.Popen(
signer, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True signer, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True
@ -220,7 +230,7 @@ class IrActionsReport(models.Model):
for fname in (pdf, signed): for fname in (pdf, signed):
try: try:
os.unlink(fname) os.unlink(fname)
except (OSError, IOError): except OSError:
_logger.error("Error when trying to remove file %s", fname) _logger.error("Error when trying to remove file %s", fname)
if certificate.attachment: if certificate.attachment:
self._attach_signed_write(res_ids, certificate, content) self._attach_signed_write(res_ids, certificate, content)

View File

@ -31,6 +31,7 @@ class ReportCertificate(models.Model):
required=True, required=True,
comodel_name="ir.model", comodel_name="ir.model",
help="Model where apply this certificate", help="Model where apply this certificate",
ondelete="cascade",
) )
domain = fields.Char( domain = fields.Char(
string="Domain", help="Domain for filtering if sign or not the document", string="Domain", help="Domain for filtering if sign or not the document",

View File

@ -5,3 +5,5 @@
* Pedro M. Baeza * Pedro M. Baeza
* Jairo Llopis * Jairo Llopis
* David Vidal * David Vidal
* Santi Argüeso <santi@comunitea.com>
* Omar Castiñeira <omar@comunitea.com>

View File

@ -1,9 +1,7 @@
External utilities External utilities
++++++++++++++++++ ++++++++++++++++++
* iText v1.4.8: © 2000-2006, Paulo Soares, Bruno Lowagie and others - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ - http://sourceforge.net/projects/itext * JSignPdf: © Josef Cacek - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ - http://jsignpdf.sourceforge.net/
* jPdfSign: © 2006 Jan Peter Stotz - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ (inherited from iText) - http://private.sit.fraunhofer.de/~stotz/software/jpdfsign
* Modified jPdfSign: © 2015 Antonio Espinosa - License `MPL <http://www.mozilla.org/MPL>`__ or `LGPL2 <http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html>`__ (inherited from iText) - static/src/java/JPdfSign.java
Icon Icon
++++ ++++

View File

@ -1,3 +1,3 @@
To install this module, you need to install Java JDK Headlees, e.g.: To install this module, you need to install Java JDK Headlees, e.g.:
apt-get install openjdk-8-jre-headless apt-get install default-jre-headless

View File

@ -1,5 +1,4 @@
* When signing multiple documents (if 'Allow only one document' is disable) * When signing multiple documents (if 'Allow only one document' is disable)
then 'Save as attachment' is not applied and signed result is not then 'Save as attachment' is not applied and signed result is not
saved as attachment. saved as attachment.
* To have a visible signature through an image embedded in the resulting PDF.
* Add tests. * Add tests.

View File

@ -8,3 +8,8 @@ when signing date is important, for example, when signing customer invoices.
You can try the signing with the demo report that is included for customers You can try the signing with the demo report that is included for customers
called "Test PDF certificate". called "Test PDF certificate".
You can set extra parameters of JSignPdf library in the system parameter
named 'report_qweb_signer.java_position_parameters', for example '-V' to
visible signature into pdf. You can also set extra parameters for Java in the
system parameter named 'report_qweb_signer.java_parameters'.

View File

@ -398,7 +398,7 @@ PDFs using a PKCS#12 certificate.</p>
<h1><a class="toc-backref" href="#id1">Installation</a></h1> <h1><a class="toc-backref" href="#id1">Installation</a></h1>
<p>To install this module, you need to install Java JDK Headlees, e.g.:</p> <p>To install this module, you need to install Java JDK Headlees, e.g.:</p>
<blockquote> <blockquote>
apt-get install openjdk-8-jre-headless</blockquote> apt-get install default-jre-headless</blockquote>
</div> </div>
<div class="section" id="configuration"> <div class="section" id="configuration">
<h1><a class="toc-backref" href="#id2">Configuration</a></h1> <h1><a class="toc-backref" href="#id2">Configuration</a></h1>
@ -443,6 +443,10 @@ next time saved one is downloaded without signing again. This is appropiate
when signing date is important, for example, when signing customer invoices.</p> when signing date is important, for example, when signing customer invoices.</p>
<p>You can try the signing with the demo report that is included for customers <p>You can try the signing with the demo report that is included for customers
called “Test PDF certificate”.</p> called “Test PDF certificate”.</p>
<p>You can set extra parameters of JSignPdf library in the system parameter
named report_qweb_signer.java_position_parameters, for example -V to
visible signature into pdf. You can also set extra parameters for Java in the
system parameter named report_qweb_signer.java_parameters.</p>
</div> </div>
<div class="section" id="known-issues-roadmap"> <div class="section" id="known-issues-roadmap">
<h1><a class="toc-backref" href="#id5">Known issues / Roadmap</a></h1> <h1><a class="toc-backref" href="#id5">Known issues / Roadmap</a></h1>
@ -450,7 +454,6 @@ called “Test PDF certificate”.</p>
<li>When signing multiple documents (if Allow only one document is disable) <li>When signing multiple documents (if Allow only one document is disable)
then Save as attachment is not applied and signed result is not then Save as attachment is not applied and signed result is not
saved as attachment.</li> saved as attachment.</li>
<li>To have a visible signature through an image embedded in the resulting PDF.</li>
<li>Add tests.</li> <li>Add tests.</li>
</ul> </ul>
</div> </div>
@ -484,6 +487,10 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
</ul> </ul>
</blockquote> </blockquote>
</li> </li>
<li><p class="first">Santi Argüeso &lt;<a class="reference external" href="mailto:santi&#64;comunitea.com">santi&#64;comunitea.com</a>&gt;</p>
</li>
<li><p class="first">Omar Castiñeira &lt;<a class="reference external" href="mailto:omar&#64;comunitea.com">omar&#64;comunitea.com</a>&gt;</p>
</li>
</ul> </ul>
</div> </div>
<div class="section" id="other-credits"> <div class="section" id="other-credits">
@ -491,9 +498,7 @@ If you spotted it first, help us smashing it by providing a detailed and welcome
<div class="section" id="external-utilities"> <div class="section" id="external-utilities">
<h3><a class="toc-backref" href="#id11">External utilities</a></h3> <h3><a class="toc-backref" href="#id11">External utilities</a></h3>
<ul class="simple"> <ul class="simple">
<li>iText v1.4.8: © 2000-2006, Paulo Soares, Bruno Lowagie and others - License <a class="reference external" href="http://www.mozilla.org/MPL">MPL</a> or <a class="reference external" href="http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html">LGPL2</a> - <a class="reference external" href="http://sourceforge.net/projects/itext">http://sourceforge.net/projects/itext</a></li> <li>JSignPdf: © Josef Cacek - License <a class="reference external" href="http://www.mozilla.org/MPL">MPL</a> or <a class="reference external" href="http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html">LGPL2</a> - <a class="reference external" href="http://jsignpdf.sourceforge.net/">http://jsignpdf.sourceforge.net/</a></li>
<li>jPdfSign: © 2006 Jan Peter Stotz - License <a class="reference external" href="http://www.mozilla.org/MPL">MPL</a> or <a class="reference external" href="http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html">LGPL2</a> (inherited from iText) - <a class="reference external" href="http://private.sit.fraunhofer.de/~stotz/software/jpdfsign">http://private.sit.fraunhofer.de/~stotz/software/jpdfsign</a></li>
<li>Modified jPdfSign: © 2015 Antonio Espinosa - License <a class="reference external" href="http://www.mozilla.org/MPL">MPL</a> or <a class="reference external" href="http://www.gnu.org/licenses/old-licenses/lgpl-2.0.html">LGPL2</a> (inherited from iText) - static/src/java/JPdfSign.java</li>
</ul> </ul>
</div> </div>
<div class="section" id="icon"> <div class="section" id="icon">

Binary file not shown.

View File

@ -7,9 +7,9 @@ Report xlsx helpers
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status :target: https://odoo-community.org/page/development-status
:alt: Beta :alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png .. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3

View File

@ -6,7 +6,8 @@
"author": "Noviat, Odoo Community Association (OCA)", "author": "Noviat, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"category": "Reporting", "category": "Reporting",
"version": "13.0.1.1.1", "development_status": "Production/Stable",
"version": "13.0.1.1.3",
"license": "AGPL-3", "license": "AGPL-3",
"depends": ["report_xlsx"], "depends": ["report_xlsx"],
"installable": True, "installable": True,

View File

@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_xlsx_helper"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_xlsx_helper"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_xlsx_helper"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_xlsx_helper"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module provides a set of tools to facilitate the creation of excel reports with format xlsx.</p> <p>This module provides a set of tools to facilitate the creation of excel reports with format xlsx.</p>
<p><strong>Table of contents</strong></p> <p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents"> <div class="contents local topic" id="contents">

View File

@ -7,9 +7,9 @@ XML Reports
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png
:target: https://odoo-community.org/page/development-status :target: https://odoo-community.org/page/development-status
:alt: Beta :alt: Production/Stable
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png .. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3

View File

@ -2,9 +2,10 @@
# License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnuorg/licenses/agpl.html).
{ {
"name": "XML Reports", "name": "XML Reports",
"version": "13.0.1.0.1", "version": "13.0.1.1.0",
"category": "Reporting", "category": "Reporting",
"website": "https://github.com/OCA/reporting-engine", "website": "https://github.com/OCA/reporting-engine",
"development_status": "Production/Stable",
"author": "Tecnativa, Odoo Community Association (OCA), Avoin.Systems", "author": "Tecnativa, Odoo Community Association (OCA), Avoin.Systems",
"license": "AGPL-3", "license": "AGPL-3",
"installable": True, "installable": True,

View File

@ -367,7 +367,7 @@ ul.auto-toc {
!! This file is generated by oca-gen-addon-readme !! !! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !! !! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_xml"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_xml"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> <p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/reporting-engine/tree/13.0/report_xml"><img alt="OCA/reporting-engine" src="https://img.shields.io/badge/github-OCA%2Freporting--engine-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/reporting-engine-13-0/reporting-engine-13-0-report_xml"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/143/13.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p>
<p>This module was written to extend the functionality of the reporting engine to <p>This module was written to extend the functionality of the reporting engine to
support XML reports and allow modules to generate them by code or by QWeb support XML reports and allow modules to generate them by code or by QWeb
templates.</p> templates.</p>

View File

@ -2,3 +2,4 @@ py3o.template
py3o.formats py3o.formats
genshi>=0.7 genshi>=0.7
cryptography cryptography
endesive

View File

@ -1 +1 @@
13.0.20211016.0 13.0.20220413.0

View File

@ -12,6 +12,7 @@ setuptools.setup(
'odoo13-addon-bi_sql_editor', 'odoo13-addon-bi_sql_editor',
'odoo13-addon-kpi', 'odoo13-addon-kpi',
'odoo13-addon-kpi_dashboard', 'odoo13-addon-kpi_dashboard',
'odoo13-addon-report_async',
'odoo13-addon-report_batch', 'odoo13-addon-report_batch',
'odoo13-addon-report_context', 'odoo13-addon-report_context',
'odoo13-addon-report_csv', 'odoo13-addon-report_csv',

View File

@ -0,0 +1 @@
../../../../report_async

View File

@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)