[ADD] gotenberg module

This commit is contained in:
Aleksei Ostriakov 2024-11-22 14:31:34 +05:00
parent 2f38569c5e
commit ce102380ad
9 changed files with 276 additions and 0 deletions

63
gotenberg/README.md Normal file
View File

@ -0,0 +1,63 @@
# Gotenberg integration in Odoo
##Gotenberg is a Docker-powered stateless API for PDF files.
**In other words:**
- It's a Docker image containing all the required dependencies; no need to install them on each environment.
- It scales smoothly and works nicely in a distributed context.
- It provides multipart/form-data endpoints for converting documents to PDF files, transforming them, merging them, and more!
- It has HTTP/2 support (H2C).
Gotenberg provides a developer-friendly API to interact with powerful tools like Chromium and LibreOffice
to convert many documents (HTML, Markdown, Word, Excel, etc.) to PDF, transform them, merge them, and more!
## Quick Start
Open a terminal and run the following command:
```
docker run --rm -p 3000:3000 gotenberg/gotenberg:6
```
or
```
docker run --rm -p 3000:3000 thecodingmachine/gotenberg:6
```
The API is now available on your host at http://localhost:3000.
Head to the [documentation](https://gotenberg.dev/docs/about) to learn how to interact with it 🚀
## Configuration
For a service running in a docker, you need to add an environment variable **GOTENBERG_SERVER**
For a service running on a remote server, you need to specify the connection data in the settings.
## Use
## Development and Testing
### Requirements
There are a few things that we need for running the test suite.
- A database instance WITH demo data. So when you are creating a database from that database creation screen, make sure to mark to include demo data.
- Run odoo with the --test-enable flag
- Run odoo with the -d {my_database} flag
- Run odoo with the -i {modules_to_install} flag
- (optional) Sometimes its also nice to use --stop-after-init
### Run The Tests
```shell
$ docker-compose stop
$ docker-compose run web \
--test-enable \
--stop-after-init \
-d test_db \
-i test_module
```

4
gotenberg/__init__.py Normal file
View File

@ -0,0 +1,4 @@
from . import models # noqa: F401
from . import service # noqa: F401
# from . import tests # noqa: F401

58
gotenberg/__manifest__.py Normal file
View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# noinspection PyStatementEffect
{
"name": "Gotenberg™ integration",
"summary": """Gotenberg integration with Odoo for file conversion.""",
"description": """
This module complements the functionality of docx_report_generation,
namely it allows you to generate printed forms in PDF from docx templates.
""",
"license": "LGPL-3",
"author": "RYDLAB",
"website": "http://rydlab.ru",
"category": "Productivity",
"version": "0.1",
# |-------------------------------------------------------------------------
# | Dependencies
# |-------------------------------------------------------------------------
# |
# | References of all modules that this module depends on. If this module
# | is ever installed or upgrade, it will automatically install any
# | dependencies as well.
# |
"depends": ["base_setup"],
# |-------------------------------------------------------------------------
# | Data References
# |-------------------------------------------------------------------------
# |
# | References to all XML data that this module relies on. These XML files
# | are automatically pulled into the system and processed.
# |
"data": [
"views/res_config_settings_views.xml",
],
# |-------------------------------------------------------------------------
# | Demo Data
# |-------------------------------------------------------------------------
# |
# | A reference to demo data
# |
"demo": [],
# |-------------------------------------------------------------------------
# | Is Installable
# |-------------------------------------------------------------------------
# |
# | Gives the user the option to look at Local Modules and install, upgrade
# | or uninstall. This seems to be used by most developers as a switch for
# | modules that are either active / inactive.
# |
"installable": True,
# |-------------------------------------------------------------------------
# | Auto Install
# |-------------------------------------------------------------------------
# |
# | Lets Odoo know if this module should be automatically installed when
# | the server is started.
# |
"auto_install": False,
}

View File

@ -0,0 +1,2 @@
# noinspection PyUnresolvedReferences
from . import res_config_settings

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
module_gotenberg = fields.Boolean(string="Gotenberg")
server = fields.Char(
string="Server",
config_parameter="service.gotenberg_server",
)
method_authentication = fields.Selection(
[
("none", "None"),
("basic", "Basic Authentication"),
],
default="none",
config_parameter="service.gotenberg_method_authentication",
)
username = fields.Char(
string="Username", config_parameter="service.gotenberg_username"
)
password = fields.Char(
string="Password", config_parameter="service.gotenberg__password"
)

View File

@ -0,0 +1,3 @@
# noinspection PyUnresolvedReferences
from . import environment
from . import utils

View File

@ -0,0 +1,14 @@
from contextlib import contextmanager
from odoo import api, registry, SUPERUSER_ID
from odoo.tests import common
@contextmanager
def environment():
"""Return an environment with a new cursor for the current database; the
cursor is committed and closed after the context block.
"""
reg = registry(common.get_db_name())
with reg.cursor() as cr:
yield api.Environment(cr, SUPERUSER_ID, {})

View File

@ -0,0 +1,53 @@
import re
import os
from .environment import environment
GOTENBERG_DEFAULT_SERVER = "localhost:3000"
CONVERT_PDF_FROM_OFFICE_PATH = "convert/office"
HOST_PATTERN = re.compile(r"https?://(www\.)?")
def get_hostname(server):
return HOST_PATTERN.sub("", server).strip().strip("/")
def _gotenberg_server() -> str:
env_value = os.environ.get("GOTENBERG_SERVER")
with environment() as env:
param_value = (
env["ir.config_parameter"].sudo().get_param("service.gotenberg_server")
)
server = env_value if env_value else param_value
return server if server else GOTENBERG_DEFAULT_SERVER
def convert_pdf_from_office_url() -> str:
return _gotenberg_server() + CONVERT_PDF_FROM_OFFICE_PATH
def get_auth():
with environment() as env:
conf = env["ir.config_parameter"].sudo()
auth = conf.get_param("service.gotenberg_method_authentication")
if auth == "basic":
username = conf.get_param("service.gotenberg_username")
password = conf.get_param("service.gotenberg__password")
return username, password
return
def check_gotenberg_installed():
with environment() as env:
gotenberg_rec = (
env["ir.module.module"].sudo().search([("name", "=", "gotenberg")])
)
return (
True
if gotenberg_rec and gotenberg_rec.sudo().state == "installed"
else False
)

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">gotenberg.config.settings</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="base_setup.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='recaptcha']" position="after">
<div class="col-12 col-lg-6 o_setting_box" id="gotenberg_setting">
<div class="o_setting_left_pane">
<field name="module_gotenberg"/>
</div>
<div class="o_setting_right_pane">
<label for="module_gotenberg"/>
<div class="text-muted">
Convert documents from Word to PDF
</div>
<div class="content-group" attrs="{'invisible': [('module_gotenberg','=',False)]}"
id="msg_module_gotenberg">
<div class="mt16 text-warning">
<strong>Save</strong>
this page and come back here to set up the feature.
</div>
</div>
</div>
</div>
</xpath>
<div id="msg_module_gotenberg" position="replace">
<div class="content-group"
attrs="{'invisible': [('module_gotenberg','=',False)]}">
<div class="content-group mt16">
<label for="server" class="o_light_label"/>
<field name="server"/>
</div>
<div class="content-group mt16">
<label for="method_authentication" class="o_light_label"/>
<field name="method_authentication"/>
</div>
<div class="content-group mt16"
attrs="{'invisible': [('method_authentication','!=','basic')]}">
<label for="username" class="o_light_label"/>
<field name="username"/>
</div>
<div class="content-group mt16"
attrs="{'invisible': [('method_authentication','!=','basic')]}">
<label for="password" class="o_light_label"/>
<field name="password" password="True"/>
</div>
</div>
</div>
</field>
</record>
</odoo>