some docs added

This commit is contained in:
Alexandr 2021-07-26 13:37:54 +05:00
parent c5f6f9c058
commit 2e80dac5dd
5 changed files with 74 additions and 4 deletions

View File

@ -1 +1,10 @@
# DOCS report # DOCS report
Adds docx reports printing from docx templates like standard Odoo reports
with qweb templates. Standard Odoo reports also available.
For generating pdf from docx external service the "gotenberg" is used.
It should work at the same server as Odoo app. If "gotenberg" absent, there
will be only reports in docx format.
To get and start "gotenberg" container use command:
docker run -h docx_to_pdf -e DEFAULT_LISTEN_PORT=8808 thecodingmachine/gotenberg

View File

@ -1,13 +1,18 @@
{ {
"name": "DOCX report", "name": "DOCX report",
"summary": """ "summary": """Printing reports in docx format from docx templates.""",
Print docx report from docx template""", "description": """
"description": """""", Adds docx reports printing from docx templates like standard Odoo reports
with qweb templates. Standard Odoo reports also available.
For generating pdf from docx external service the "gotenberg" is used.
It should work at the same server as Odoo app. If "gotenberg" absent, there
will be only reports in docx format.
""",
"author": "RYDLAB", "author": "RYDLAB",
"website": "http://rydlab.ru", "website": "http://rydlab.ru",
"category": "Technical", "category": "Technical",
"version": "0.0.1", "version": "0.0.1",
"depends": ["base", "web"], "depends": ["base", "web", "custom_report_field", "report_monetary_helpers"],
"external_dependencies": {"python": ["docxcompose", "docxtpl"]}, "external_dependencies": {"python": ["docxcompose", "docxtpl"]},
"data": [ "data": [
"views/assets.xml", "views/assets.xml",

View File

@ -20,6 +20,9 @@ _logger = getLogger(__name__)
class DocxReportController(ReportController): class DocxReportController(ReportController):
@route() @route()
def report_routes(self, reportname, docids=None, converter=None, **data): def report_routes(self, reportname, docids=None, converter=None, **data):
"""
Запускает генерацию файла отчета и возвращает его
"""
report = request.env["ir.actions.report"]._get_report_from_name(reportname) report = request.env["ir.actions.report"]._get_report_from_name(reportname)
context = dict(request.env.context) context = dict(request.env.context)
_data = dict() _data = dict()
@ -61,6 +64,9 @@ class DocxReportController(ReportController):
@route() @route()
def report_download(self, data, token, context=None): def report_download(self, data, token, context=None):
"""
Обрабатывает запрос на скачивание файла отчета
"""
requestcontent = json_loads(data) requestcontent = json_loads(data)
url, type = requestcontent[0], requestcontent[1] url, type = requestcontent[0], requestcontent[1]
try: try:

View File

@ -51,6 +51,12 @@ class IrActionsReport(models.Model):
pass pass
def retrieve_attachment(self, record): def retrieve_attachment(self, record):
"""
Поиск существующего файла отчета во вложениях записи по:
1. name
2. res_model
3. res_id
"""
result = super().retrieve_attachment(record) result = super().retrieve_attachment(record)
if result: if result:
if self.report_type == "docx-docx": if self.report_type == "docx-docx":
@ -69,6 +75,10 @@ class IrActionsReport(models.Model):
@api.model @api.model
def _render_docx_pdf(self, res_ids=None, data=None): def _render_docx_pdf(self, res_ids=None, data=None):
"""
Подготавливает данные для рендера файла отчета, вызывает метод рендера
И обрабатывает результат рендера
"""
if not data: if not data:
data = {} data = {}
data.setdefault("report_type", "pdf") data.setdefault("report_type", "pdf")
@ -127,6 +137,10 @@ class IrActionsReport(models.Model):
@api.model @api.model
def _render_docx_docx(self, res_ids=None, data=None): def _render_docx_docx(self, res_ids=None, data=None):
"""
Подготавливает данные для рендера файла отчета, вызывает метод рендера
И обрабатывает результат рендера
"""
if not data: if not data:
data = {} data = {}
data.setdefault("report_type", "docx") data.setdefault("report_type", "docx")
@ -174,6 +188,10 @@ class IrActionsReport(models.Model):
return docx_content, "docx" return docx_content, "docx"
def _post_docx(self, save_in_attachment, docx_content=None, res_ids=None): def _post_docx(self, save_in_attachment, docx_content=None, res_ids=None):
"""
Добавляет сгенерированный файл в аттачменты
"""
def close_streams(streams): def close_streams(streams):
for stream in streams: for stream in streams:
try: try:
@ -233,6 +251,9 @@ class IrActionsReport(models.Model):
return result return result
def _postprocess_docx_report(self, record, buffer): def _postprocess_docx_report(self, record, buffer):
"""
Непосредственно создает запись в ir.attachment
"""
attachment_name = safe_eval(self.attachment, {"object": record, "time": time}) attachment_name = safe_eval(self.attachment, {"object": record, "time": time})
if not attachment_name: if not attachment_name:
return None return None
@ -257,6 +278,9 @@ class IrActionsReport(models.Model):
return buffer return buffer
def _merge_docx(self, streams): def _merge_docx(self, streams):
"""
Объединяет несколько docx файлов в один
"""
if streams: if streams:
writer = Document(streams[0]) writer = Document(streams[0])
composer = Composer(writer) composer = Composer(writer)
@ -268,6 +292,9 @@ class IrActionsReport(models.Model):
return streams return streams
def _render_docx(self, docids, data=None): def _render_docx(self, docids, data=None):
"""
Получает данные для рендеринга и вызывает его.
"""
if not data: if not data:
data = {} data = {}
data.setdefault("report_type", "docx") data.setdefault("report_type", "docx")
@ -275,6 +302,9 @@ class IrActionsReport(models.Model):
return self._render_docx_template(self.report_docx_template, values=data) return self._render_docx_template(self.report_docx_template, values=data)
def _render_docx_template(self, template, values=None): def _render_docx_template(self, template, values=None):
"""
Непосредственно рендеринг docx файла
"""
if values is None: if values is None:
values = {} values = {}
@ -322,6 +352,9 @@ class IrActionsReport(models.Model):
return docx_content return docx_content
def _get_pdf_from_office(self, content_stream): def _get_pdf_from_office(self, content_stream):
"""
Вызов конвертации docx в pdf с помощью gotenberg
"""
result = None result = None
try: try:
response = post_request( response = post_request(

View File

@ -6,6 +6,9 @@ odoo.define("docx_report.ReportActionManager", function (require) {
var session = require("web.session"); var session = require("web.session");
ActionManager.include({ ActionManager.include({
/**
* Запрос на скачивание сгенерированного файла отчета
*/
_downloadReport: function (url, action) { _downloadReport: function (url, action) {
var self = this; var self = this;
var template_type = (action.report_type && action.report_type.split("-")[0]) || "qweb"; var template_type = (action.report_type && action.report_type.split("-")[0]) || "qweb";
@ -36,6 +39,13 @@ odoo.define("docx_report.ReportActionManager", function (require) {
} }
}); });
}, },
/**
* Этот метод вызывается при нажатии на пункт меню для печати отчета.
*
* Вызывает _triggerDownload с различными аргументами.
* Расширяется новыми вариантами.
* В оригинальном методе есть и другой функционал.
*/
_executeReportAction: function (action, options) { _executeReportAction: function (action, options) {
if (action.report_type === "docx-docx") { if (action.report_type === "docx-docx") {
return this._triggerDownload(action, options, "docx"); return this._triggerDownload(action, options, "docx");
@ -45,6 +55,10 @@ odoo.define("docx_report.ReportActionManager", function (require) {
return this._super.apply(this, arguments); return this._super.apply(this, arguments);
} }
}, },
/**
* Запускает скачивание файла отчета
*/
_triggerDownload: function (action, options, type){ _triggerDownload: function (action, options, type){
var self = this; var self = this;
var reportUrls = this._makeReportUrls(action); var reportUrls = this._makeReportUrls(action);
@ -57,6 +71,9 @@ odoo.define("docx_report.ReportActionManager", function (require) {
} }
}); });
}, },
/**
* Генерирует URL для запроса отчета
*/
_makeReportUrls: function (action) { _makeReportUrls: function (action) {
var reportUrls = this._super.apply(this, arguments); var reportUrls = this._super.apply(this, arguments);
reportUrls.docx = "/report/docx/" + action.report_name; reportUrls.docx = "/report/docx/" + action.report_name;