porting to 16 version finished

This commit is contained in:
alexandr.uritskiy 2022-12-29 13:42:39 +05:00
parent da4f636fde
commit 2ba48666f3
4 changed files with 217 additions and 33 deletions

View File

@ -10,7 +10,7 @@ from odoo.http import (
from odoo.tools import html_escape from odoo.tools import html_escape
from odoo.tools.safe_eval import safe_eval, time from odoo.tools.safe_eval import safe_eval, time
from odoo.addons.web.controllers.main import ReportController from odoo.addons.web.controllers.report import ReportController
class DocxReportController(ReportController): class DocxReportController(ReportController):
@ -52,8 +52,8 @@ class DocxReportController(ReportController):
] ]
return request.make_response(pdf, headers=pdfhttpheaders) return request.make_response(pdf, headers=pdfhttpheaders)
else: else:
return super().report_routes( return super(DocxReportController, self).report_routes(
reportname, docids=docids, converter=converter, **data reportname, docids, converter, **data
) )
@route() @route()

70
i18n/docx_report.pot Normal file
View File

@ -0,0 +1,70 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * docx_report
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-29 08:24+0000\n"
"PO-Revision-Date: 2022-12-29 08:24+0000\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: docx_report
#: model:ir.model.fields.selection,name:docx_report.selection__ir_actions_report__report_type__docx-docx
msgid "DOCX"
msgstr ""
#. module: docx_report
#: model:ir.model.fields.selection,name:docx_report.selection__ir_actions_report__report_type__docx-pdf
msgid "DOCX(PDF)"
msgstr ""
#. module: docx_report
#. odoo-python
#: code:addons/docx_report/models/ir_actions_report.py:0
#, python-format
msgid ""
"Gotenberg converting service not available. The PDF can not be created."
msgstr ""
#. module: docx_report
#. odoo-python
#: code:addons/docx_report/models/ir_actions_report.py:0
#, python-format
msgid "One of the documents you try to merge caused failure."
msgstr ""
#. module: docx_report
#: model:ir.model,name:docx_report.model_ir_actions_report
msgid "Report Action"
msgstr ""
#. module: docx_report
#: model:ir.model.fields,field_description:docx_report.field_ir_actions_report__report_type
msgid "Report Type"
msgstr ""
#. module: docx_report
#: model:ir.model.fields,field_description:docx_report.field_ir_actions_report__report_docx_template
msgid "Report docx template"
msgstr ""
#. module: docx_report
#: model:ir.model.fields,field_description:docx_report.field_ir_actions_report__report_name
msgid "Template Name"
msgstr ""
#. module: docx_report
#: model:ir.model.fields,help:docx_report.field_ir_actions_report__report_type
msgid ""
"The type of the report that will be rendered, each one having its own "
"rendering method. HTML means the report will be opened directly in your "
"browser PDF means the report will be rendered using Wkhtmltopdf and "
"downloaded by the user."
msgstr ""

75
i18n/ru.po Normal file
View File

@ -0,0 +1,75 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * docx_report
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-12-29 08:24+0000\n"
"PO-Revision-Date: 2022-12-29 08:24+0000\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: docx_report
#: model:ir.model.fields.selection,name:docx_report.selection__ir_actions_report__report_type__docx-docx
msgid "DOCX"
msgstr "DOCX"
#. module: docx_report
#: model:ir.model.fields.selection,name:docx_report.selection__ir_actions_report__report_type__docx-pdf
msgid "DOCX(PDF)"
msgstr "DOCX(PDF)"
#. module: docx_report
#. odoo-python
#: code:addons/docx_report/models/ir_actions_report.py:0
#, python-format
msgid ""
"Gotenberg converting service not available. The PDF can not be created."
msgstr ""
"Файл PDF не может быть создан, так как сервис конвертации Gotenberg не доступен."
#. module: docx_report
#. odoo-python
#: code:addons/docx_report/models/ir_actions_report.py:0
#, python-format
msgid "One of the documents you try to merge caused failure."
msgstr "Один из документов, которые вы пытаетесь соединить, вызывает ошибку."
#. module: docx_report
#: model:ir.model,name:docx_report.model_ir_actions_report
msgid "Report Action"
msgstr "Действие для отчета."
#. module: docx_report
#: model:ir.model.fields,field_description:docx_report.field_ir_actions_report__report_type
msgid "Report Type"
msgstr "Тип отчета"
#. module: docx_report
#: model:ir.model.fields,field_description:docx_report.field_ir_actions_report__report_docx_template
msgid "Report docx template"
msgstr "Шаблон для отчета docx"
#. module: docx_report
#: model:ir.model.fields,field_description:docx_report.field_ir_actions_report__report_name
msgid "Template Name"
msgstr "Имя шаблона"
#. module: docx_report
#: model:ir.model.fields,help:docx_report.field_ir_actions_report__report_type
msgid ""
"The type of the report that will be rendered, each one having its own "
"rendering method. HTML means the report will be opened directly in your "
"browser PDF means the report will be rendered using Wkhtmltopdf and "
"downloaded by the user."
msgstr ""
"Тип генерируемого отчета. Каждый тип имеет свой собственный"
" метод генерации. HTML означает, что отчет будет открыт непосредственно в"
" вашем браузере, PDF означает, что отчет будет сгенерирован с помощью "
"Wkhtmltopdf и загружен пользователем."

View File

@ -64,7 +64,7 @@ class IrActionsReport(models.Model):
def retrieve_attachment(self, record): def retrieve_attachment(self, record):
""" """
Поиск существующего файла отчета во вложениях записи по: Searc for existing report file in record's attachments by fields:
1. name 1. name
2. res_model 2. res_model
3. res_id 3. res_id
@ -88,8 +88,8 @@ 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):
""" """
Подготавливает данные для рендера файла отчета, вызывает метод рендера Prepares the data for report file rendering, calls for the render method
И обрабатывает результат рендера and handle rendering result.
""" """
if not data: if not data:
data = {} data = {}
@ -100,7 +100,7 @@ class IrActionsReport(models.Model):
save_in_attachment = OrderedDict() save_in_attachment = OrderedDict()
# Maps the streams in `save_in_attachment` back to the records they came from # Maps the streams in `save_in_attachment` back to the records they came from
stream_record = dict() # stream_record = dict()
if res_ids: if res_ids:
Model = self.env[self_sudo.model] Model = self.env[self_sudo.model]
record_ids = Model.browse(res_ids) record_ids = Model.browse(res_ids)
@ -108,19 +108,20 @@ class IrActionsReport(models.Model):
if self_sudo.attachment: if self_sudo.attachment:
for record_id in record_ids: for record_id in record_ids:
attachment = self_sudo.retrieve_attachment(record_id) attachment = self_sudo.retrieve_attachment(record_id)
if attachment: if attachment and self_sudo.attachment_use:
stream = self_sudo._retrieve_stream_from_attachment(attachment) # stream = self_sudo._retrieve_stream_from_attachment(attachment)
stream = BytesIO(attachment.raw)
save_in_attachment[record_id.id] = stream save_in_attachment[record_id.id] = stream
stream_record[stream] = record_id # stream_record[stream] = record_id
if not self_sudo.attachment_use or not attachment: if not self_sudo.attachment_use or not attachment:
docx_record_ids += record_id docx_record_ids += record_id
else: else:
docx_record_ids = record_ids docx_record_ids = record_ids
res_ids = docx_record_ids.ids res_ids = docx_record_ids.ids
if save_in_attachment and not res_ids: if save_in_attachment: # and not res_ids:
_logger.info("The PDF report has been generated from attachment.") _logger.info("The PDF report has been generated from attachment.")
self._raise_on_unreadable_pdfs(save_in_attachment.values(), stream_record) # self._raise_on_unreadable_pdfs(save_in_attachment.values(), stream_record)
return self_sudo._post_pdf(save_in_attachment), "pdf" return self_sudo._post_pdf(save_in_attachment), "pdf"
docx_content = self._render_docx(res_ids, data=data) docx_content = self._render_docx(res_ids, data=data)
@ -139,24 +140,22 @@ class IrActionsReport(models.Model):
) )
if res_ids: if res_ids:
self._raise_on_unreadable_pdfs(save_in_attachment.values(), stream_record) # self._raise_on_unreadable_pdfs(save_in_attachment.values(), stream_record)
_logger.info( # saving pdf in attachment.
"The PDF report has been generated for model: %s, records %s."
% (self_sudo.model, str(res_ids))
)
return ( return (
self_sudo._post_pdf( self_sudo._post_pdf(
save_in_attachment, pdf_content=pdf_content, res_ids=res_ids save_in_attachment, pdf_content=pdf_content, res_ids=res_ids
), ),
"pdf", "pdf",
) )
return pdf_content, "pdf" return pdf_content, "pdf"
@api.model @api.model
def _render_docx_docx(self, res_ids=None, data=None): def _render_docx_docx(self, res_ids=None, data=None):
""" """
Подготавливает данные для рендера файла отчета, вызывает метод рендера Prepares the data for report file rendering, calls for the render method
И обрабатывает результат рендера and handle rendering result.
""" """
if not data: if not data:
data = {} data = {}
@ -176,7 +175,8 @@ class IrActionsReport(models.Model):
for record_id in record_ids: for record_id in record_ids:
attachment = self_sudo.retrieve_attachment(record_id) attachment = self_sudo.retrieve_attachment(record_id)
if attachment: if attachment:
stream = self_sudo._retrieve_stream_from_attachment(attachment) # stream = self_sudo._retrieve_stream_from_attachment(attachment)
stream = BytesIO(attachment.raw)
save_in_attachment[record_id.id] = stream save_in_attachment[record_id.id] = stream
stream_record[stream] = record_id stream_record[stream] = record_id
if not self_sudo.attachment_use or not attachment: if not self_sudo.attachment_use or not attachment:
@ -204,11 +204,52 @@ class IrActionsReport(models.Model):
) )
return docx_content, "docx" return docx_content, "docx"
def _post_pdf(self, save_in_attachment, pdf_content=None, res_ids=None):
"""
Adds pdf file in record's attachments.
TODO: For now bunch generation is not supported.
2 execution ways:
- save_in_attachment and not res_ids - when get reports from attachments
- res_ids and not save_in_attachment - when generate report.
"""
self_sudo = self.sudo()
attachment_vals_list = []
if save_in_attachment:
# here get streams from save_in_attachment, make pdf file and return it
# bunch generation here is already realized.
reports_data = list(save_in_attachment.values())
if len(reports_data) == 1:
# If only one report, no need to merge files. Returns as is.
return reports_data[0].getvalue()
else:
return self._merge_pdfs(reports_data)
for res_id in res_ids:
record = self.env[self_sudo.model].browse(res_id)
attachment_name = safe_eval(self_sudo.attachment, {'object': record, 'time': time})
# Unable to compute a name for the attachment.
if not attachment_name:
continue
attachment_vals_list.append({
'name': attachment_name,
'raw': pdf_content, # stream_data['stream'].getvalue(),
'res_model': self_sudo.model,
'res_id': record.id,
'type': 'binary',
})
if attachment_vals_list:
attachment_names = ', '.join(x['name'] for x in attachment_vals_list)
try:
self.env['ir.attachment'].create(attachment_vals_list)
except AccessError:
_logger.info("Cannot save PDF report %r attachments for user %r", attachment_names, self.env.user.display_name)
else:
_logger.info("The PDF documents %r are now saved in the database", attachment_names)
return pdf_content
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):
""" """
Добавляет сгенерированный файл в аттачменты Adds generated file in attachments.
""" """
def close_streams(streams): def close_streams(streams):
for stream in streams: for stream in streams:
try: try:
@ -218,9 +259,7 @@ class IrActionsReport(models.Model):
if len(save_in_attachment) == 1 and not docx_content: if len(save_in_attachment) == 1 and not docx_content:
return list(save_in_attachment.values())[0].getvalue() return list(save_in_attachment.values())[0].getvalue()
streams = [] streams = []
if docx_content: if docx_content:
# Build a record_map mapping id -> record # Build a record_map mapping id -> record
record_map = { record_map = {
@ -229,7 +268,6 @@ class IrActionsReport(models.Model):
[res_id for res_id in res_ids if res_id] [res_id for res_id in res_ids if res_id]
) )
} }
# If no value in attachment or no record specified, only append the whole docx. # If no value in attachment or no record specified, only append the whole docx.
if not record_map or not self.attachment: if not record_map or not self.attachment:
streams.append(docx_content) streams.append(docx_content)
@ -250,11 +288,9 @@ class IrActionsReport(models.Model):
streams.append(docx_content) streams.append(docx_content)
else: else:
streams.append(docx_content) streams.append(docx_content)
if self.attachment_use: if self.attachment_use:
for stream in save_in_attachment.values(): for stream in save_in_attachment.values():
streams.append(stream) streams.append(stream)
if len(streams) == 1: if len(streams) == 1:
result = streams[0].getvalue() result = streams[0].getvalue()
else: else:
@ -271,7 +307,7 @@ class IrActionsReport(models.Model):
def _postprocess_docx_report(self, record, buffer): def _postprocess_docx_report(self, record, buffer):
""" """
Непосредственно создает запись в ir.attachment Creates the record in the "ir.attachment" model.
""" """
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:
@ -311,19 +347,22 @@ class IrActionsReport(models.Model):
else: else:
return streams return streams
def _render_docx(self, docids, data=None): def _render_docx(self, docids: list, data: dict=None):
""" """
Получает данные для рендеринга и вызывает его. Receive the data for rendering and calls for it.
docids: list of record's ids for which report is generated.
data: dict, conains "context", "report_type".
""" """
if not data: if not data:
data = {} data = {}
data.setdefault("report_type", "docx") data.setdefault("report_type", "docx")
data = self._get_rendering_context(docids, data) data = self._get_rendering_context(self, docids, data) # self contains current record of ir.actions.report 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: bytes, values: dict = None): def _render_docx_template(self, template: bytes, values: dict = None):
""" """
Непосредственно рендеринг docx файла docx file rendering itself.
""" """
if values is None: if values is None:
values = {} values = {}
@ -388,7 +427,7 @@ class IrActionsReport(models.Model):
@staticmethod @staticmethod
def _get_pdf_from_office(content_stream): def _get_pdf_from_office(content_stream):
""" """
Вызов конвертации docx в pdf с помощью gotenberg Converting docx into pdf with Gotenberg service.
""" """
result = None result = None
url = convert_pdf_from_office_url() url = convert_pdf_from_office_url()