qrid 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
qrid/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .codec import decode_qr_id, encode_qr_id, QRIdPayload
2
+
3
+ __all__ = ["decode_qr_id", "encode_qr_id", "QRIdPayload"]
qrid/codec.py ADDED
@@ -0,0 +1,90 @@
1
+ import base64
2
+ import binascii
3
+ import io
4
+ import json
5
+ from typing import TypedDict
6
+
7
+
8
+ class QRIdPayload(TypedDict):
9
+ v: int
10
+ code: str
11
+ id: str
12
+ company: str
13
+ email: str
14
+ address: str
15
+
16
+
17
+ def decode_qr_id(encoded: str) -> QRIdPayload:
18
+ """Decode a base64-encoded QR ID string into its structured payload.
19
+
20
+ Mirrors QRId\\Codec::decodeQRId() in qrid/codec (PHP).
21
+
22
+ Args:
23
+ encoded: The base64 string read from a MergeID QR code.
24
+
25
+ Returns:
26
+ A TypedDict with keys: v, code, id, company, email, address.
27
+
28
+ Raises:
29
+ ValueError: When the base64 input is malformed.
30
+ json.JSONDecodeError: When the decoded content is not valid JSON.
31
+ """
32
+ trimmed = encoded.strip()
33
+ try:
34
+ json_bytes = base64.b64decode(trimmed, validate=True)
35
+ except binascii.Error:
36
+ raise ValueError(
37
+ "Invalid base64 input: could not decode the provided string."
38
+ )
39
+ return json.loads(json_bytes.decode("utf-8"))
40
+
41
+
42
+ def encode_qr_id(
43
+ code: str,
44
+ id: str,
45
+ company: str,
46
+ email: str,
47
+ address: str,
48
+ ) -> str:
49
+ """Encode invoice identity fields and return an SVG QR code string.
50
+
51
+ Mirrors QRId\\Codec::encodeQRId() in qrid/codec (PHP).
52
+ Requires the encode extra: pip install 'qrid[encode]'
53
+
54
+ Args:
55
+ code: Installation or activity code.
56
+ id: Tax / company registration ID.
57
+ company: Company legal name (UTF-8).
58
+ email: Primary billing or contact e-mail address.
59
+ address: Physical address of the company.
60
+
61
+ Returns:
62
+ An SVG markup string containing the generated QR code.
63
+
64
+ Raises:
65
+ ImportError: When the segno package is not installed.
66
+ """
67
+ try:
68
+ import segno
69
+ except ImportError:
70
+ raise ImportError(
71
+ "segno is required for encode_qr_id(). "
72
+ "Install with: pip install 'qrid[encode]'"
73
+ )
74
+
75
+ payload: QRIdPayload = {
76
+ "v": 1,
77
+ "code": code,
78
+ "id": id,
79
+ "company": company,
80
+ "email": email,
81
+ "address": address,
82
+ }
83
+ encoded = base64.b64encode(
84
+ json.dumps(payload, ensure_ascii=False).encode("utf-8")
85
+ ).decode()
86
+
87
+ qr = segno.make_qr(encoded)
88
+ buf = io.BytesIO()
89
+ qr.save(buf, kind="svg", nl=False)
90
+ return buf.getvalue().decode("utf-8")
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: qrid
3
+ Version: 1.0.0
4
+ Summary: Decode and encode MergeID electronic invoice QR codes
5
+ Project-URL: Homepage, https://github.com/Quality-XP-Development-SESSA/qrid-python
6
+ Project-URL: Repository, https://github.com/Quality-XP-Development-SESSA/qrid-python
7
+ Author-email: Valentin Secades Mendez <vsecades@qxdev.com>
8
+ License: MIT
9
+ Keywords: codec,decoder,invoice,mergeid,qr,qrcode
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Typing :: Typed
18
+ Requires-Python: >=3.9
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7.0; extra == 'dev'
21
+ Requires-Dist: segno>=1.6; extra == 'dev'
22
+ Provides-Extra: encode
23
+ Requires-Dist: segno>=1.6; extra == 'encode'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # qrid — Python
27
+
28
+ Decode and encode **MergeID electronic invoice QR codes**.
29
+
30
+ Python port of [`qrid/codec`](https://packagist.org/packages/qrid/codec) (PHP). All three implementations (PHP, Node.js, Python) share the same payload format and function signatures, so QR codes generated by any one of them scan correctly in the others.
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ # Decode only (no extra dependencies)
36
+ pip install qrid
37
+
38
+ # Decode + encode SVG
39
+ pip install 'qrid[encode]'
40
+ ```
41
+
42
+ ## Usage
43
+
44
+ ### Decode
45
+
46
+ ```python
47
+ from qrid import decode_qr_id
48
+
49
+ # `encoded` is the raw string value scanned from a MergeID QR code
50
+ payload = decode_qr_id(encoded)
51
+
52
+ print(payload["v"]) # Payload schema version (int, currently 1)
53
+ print(payload["code"]) # Installation / activity code (e.g. "ACT-001")
54
+ print(payload["id"]) # Tax or company ID (e.g. "3101679980")
55
+ print(payload["company"]) # Company legal name
56
+ print(payload["email"]) # Billing e-mail address
57
+ print(payload["address"]) # Physical address
58
+ ```
59
+
60
+ `decode_qr_id` strips surrounding whitespace before decoding, so strings
61
+ copied with accidental padding are handled transparently.
62
+
63
+ **Exceptions raised:**
64
+
65
+ | Exception | Cause |
66
+ | --- | --- |
67
+ | `ValueError` | Input is not valid base64 |
68
+ | `json.JSONDecodeError` | Decoded bytes are not valid JSON |
69
+
70
+ ```python
71
+ import json
72
+ from qrid import decode_qr_id
73
+
74
+ try:
75
+ payload = decode_qr_id(raw)
76
+ except ValueError:
77
+ # QR data was not base64
78
+ ...
79
+ except json.JSONDecodeError:
80
+ # QR data decoded but was not the expected JSON structure
81
+ ...
82
+ ```
83
+
84
+ ### Encode (requires `qrid[encode]`)
85
+
86
+ ```python
87
+ from qrid import encode_qr_id
88
+
89
+ svg = encode_qr_id(
90
+ code="ACT-001",
91
+ id="3101679980",
92
+ company="Acme Corp S.A.",
93
+ email="billing@acme.example",
94
+ address="123 Main St, San José, Costa Rica",
95
+ )
96
+
97
+ # Write to a file
98
+ with open("invoice_qr.svg", "w") as f:
99
+ f.write(svg)
100
+
101
+ # Or serve directly
102
+ # Content-Type: image/svg+xml
103
+ ```
104
+
105
+ **Exceptions raised:**
106
+
107
+ | Exception | Cause |
108
+ | --- | --- |
109
+ | `ImportError` | `segno` is not installed (`pip install 'qrid[encode]'`) |
110
+
111
+ ## Payload format
112
+
113
+ The QR code data is a UTF-8 JSON object encoded as standard base64 (no line-breaks):
114
+
115
+ ```json
116
+ {
117
+ "v": 1,
118
+ "code": "ACT-001",
119
+ "id": "3101679980",
120
+ "company": "Acme Corp S.A.",
121
+ "email": "billing@acme.example",
122
+ "address": "123 Main St, San José, Costa Rica"
123
+ }
124
+ ```
125
+
126
+ | Field | Type | Description |
127
+ | --- | --- | --- |
128
+ | `v` | `int` | Payload schema version. Currently always `1`. |
129
+ | `code` | `str` | Installation or activity code that links the QR to an internal record. |
130
+ | `id` | `str` | Tax / company registration ID. |
131
+ | `company` | `str` | Legal company name (UTF-8, including accented characters). |
132
+ | `email` | `str` | Primary billing or contact e-mail address. |
133
+ | `address` | `str` | Physical address of the company. |
134
+
135
+ ## Requirements
136
+
137
+ | Dependency | Version | Required for |
138
+ | --- | --- | --- |
139
+ | Python | `>= 3.9` | Always |
140
+ | `segno` | `>= 1.6` | `encode_qr_id()` only |
141
+
142
+ ## Running tests
143
+
144
+ ```bash
145
+ pip install 'qrid[dev]'
146
+ pytest
147
+ ```
148
+
149
+ ## License
150
+
151
+ MIT
@@ -0,0 +1,5 @@
1
+ qrid/__init__.py,sha256=9RQQFhDlMpfervwISGgFJrHMtHsLQFa0Hrm6YSRSOTw,118
2
+ qrid/codec.py,sha256=_MMhzgR6kMYlmL7CRIot8UoGmnzzWcRdaodaCfXQdB8,2319
3
+ qrid-1.0.0.dist-info/METADATA,sha256=UZjaJHMcvwGBM2ZN7tMpa0f9PuV2BnBXQgzRGAfzhvw,4082
4
+ qrid-1.0.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
5
+ qrid-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.31.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any