diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b68390723c6794e3ddd91776b02b935150def92b_LmdpdGxhYi1jaS55bWw=..443952591e0c07435b5f9b18308c552702e6f94d_LmdpdGxhYi1jaS55bWw= 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -9,7 +9,7 @@ mypy: variables: - INSTALL_SECTION: "[test,schema-validation]" + INSTALL_SECTION: "[test,schema-validation,qrcode]" test: variables: @@ -13,7 +13,7 @@ test: variables: - INSTALL_SECTION: "[test,schema-validation]" + INSTALL_SECTION: "[test,schema-validation,qrcode]" test-no-schema-validation: extends: test diff --git a/__init__.py b/__init__.py index b68390723c6794e3ddd91776b02b935150def92b_X19pbml0X18ucHk=..443952591e0c07435b5f9b18308c552702e6f94d_X19pbml0X18ucHk= 100644 --- a/__init__.py +++ b/__init__.py @@ -54,3 +54,4 @@ ) from .xref import Xref, JsonLD_ID from .image import ImageFile, ImageDataURL +from .qr_code import QRCodeFile, QRCodeDataURL, stringToQRCode, QRToImage diff --git a/pyproject.toml b/pyproject.toml index b68390723c6794e3ddd91776b02b935150def92b_cHlwcm9qZWN0LnRvbWw=..443952591e0c07435b5f9b18308c552702e6f94d_cHlwcm9qZWN0LnRvbWw= 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,6 +19,7 @@ [project.optional-dependencies] schema-validation = ["fastjsonschema"] +qrcode = ["qrcode"] doc = ["sphinx"] test = [] diff --git a/qr_code.py b/qr_code.py new file mode 100644 index 0000000000000000000000000000000000000000..443952591e0c07435b5f9b18308c552702e6f94d_cXJfY29kZS5weQ== --- /dev/null +++ b/qr_code.py @@ -0,0 +1,90 @@ +############################################################################## +# +# Converter Odoo module +# Copyright © 2020, 2025 XCG Consulting <https://xcg-consulting.fr> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# +############################################################################## + +from collections.abc import Mapping +from typing import Any + +from odoo import models # type: ignore[import-untyped] + +from .base import Converter + +_qrcode: None | Exception = None +try: + import qrcode # type: ignore[import-untyped] +except ImportError as e: + _qrcode = e + + +def QRToImage(qr): + """Generate a image dict from a QR Code""" + return {"body": qr.data.decode("ascii"), "mime-type": "image/png"} + + +def stringToQRCode(data: str): + """Generate a QR code from a string and return it as a base64-encoded image.""" + if not data: + return False + + if _qrcode is not None: + raise _qrcode + + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=4, + ) + qr.add_data(data) + qr.make(fit=True) + return qr + + +class QRCodeFile(Converter): + def __init__(self, fieldname): + self.fieldname = fieldname + + def odoo_to_message( + self, instance: models.Model, ctx: Mapping | None = None + ) -> Any: + value = getattr(instance, self.fieldname) + + if not value: + return {} + + return QRToImage(stringToQRCode(value)) + + +class QRCodeDataURL(Converter): + def __init__(self, fieldname): + self.fieldname = fieldname + + def odoo_to_message( + self, instance: models.Model, ctx: Mapping | None = None + ) -> Any: + value = getattr(instance, self.fieldname) + + if not value: + return "" + + image = QRToImage(stringToQRCode(value)) + return "data:{};base64,{}".format( + image["mime-type"], + image["body"], + )