digifact-sdk 2.0.1__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.
- digifact_sdk/__init__.py +20 -0
- digifact_sdk/builder.py +911 -0
- digifact_sdk/client.py +704 -0
- digifact_sdk/exceptions.py +76 -0
- digifact_sdk/tax.py +133 -0
- digifact_sdk-2.0.1.dist-info/METADATA +207 -0
- digifact_sdk-2.0.1.dist-info/RECORD +9 -0
- digifact_sdk-2.0.1.dist-info/WHEEL +5 -0
- digifact_sdk-2.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Exceptions for the Digifact FEL SDK."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class DigifactError(Exception):
|
|
6
|
+
"""Base exception for all Digifact SDK errors."""
|
|
7
|
+
|
|
8
|
+
def __init__(self, message: str, code: int | None = None, raw: dict | None = None) -> None:
|
|
9
|
+
super().__init__(message)
|
|
10
|
+
self.code = code
|
|
11
|
+
self.raw = raw or {}
|
|
12
|
+
|
|
13
|
+
def __repr__(self) -> str:
|
|
14
|
+
return f"DigifactError(message={str(self)!r}, code={self.code!r})"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DigifactAuthError(DigifactError):
|
|
18
|
+
"""Authentication / token error."""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DigifactApiError(DigifactError):
|
|
22
|
+
"""API returned a non-success response."""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class DigifactValidationError(DigifactError):
|
|
26
|
+
"""Payload validation error (SAT or Digifact rejection)."""
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class DigifactNitNotFoundError(DigifactError):
|
|
30
|
+
"""NIT lookup returned no result."""
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
# ── SAT hint classifier ──────────────────────────────────────────────────────
|
|
34
|
+
|
|
35
|
+
_HINTS: list[tuple[list[str], str]] = [
|
|
36
|
+
(
|
|
37
|
+
["AfiliacionIVA", "MINIRTU", "RTU"],
|
|
38
|
+
"El NIT del emisor no tiene la afiliación de IVA indicada en su RTU (AfiliacionIVA). "
|
|
39
|
+
"Verifica que AfiliacionIVA sea GEN, PEQ o EXE según el RTU del emisor.",
|
|
40
|
+
),
|
|
41
|
+
(
|
|
42
|
+
["TipoPersoneria"],
|
|
43
|
+
"El valor de TipoPersoneria debe coincidir exactamente con el código registrado en el "
|
|
44
|
+
"RTU del emisor. Consulta el RTU en portal.sat.gob.gt.",
|
|
45
|
+
),
|
|
46
|
+
(
|
|
47
|
+
["SECCION 3.5", "9015", "ID Receptor"],
|
|
48
|
+
"NCRE/NDEB: el receptor del documento origen debe coincidir con el receptor del "
|
|
49
|
+
"documento de nota. Asegúrate de referenciar una factura cuyo comprador sea el mismo "
|
|
50
|
+
"que el de la nota.",
|
|
51
|
+
),
|
|
52
|
+
(
|
|
53
|
+
["NAMESPACE_UNKNOWN", "5035"],
|
|
54
|
+
"El complemento CCA requiere que el emisor tenga habilitado el namespace CCA en "
|
|
55
|
+
"Digifact. Contacta a soporte@digifact.com.gt.",
|
|
56
|
+
),
|
|
57
|
+
(
|
|
58
|
+
["FRASES"],
|
|
59
|
+
"Este tipo de DTE no permite las frases indicadas. Para FESP no incluyas "
|
|
60
|
+
"TipoFrase/Escenario en la sección Seller.",
|
|
61
|
+
),
|
|
62
|
+
(
|
|
63
|
+
["FechaEmision", "fecha"],
|
|
64
|
+
"Verifica el formato de fecha: debe ser 'YYYY-MM-DD HH:MM:SS' para cancelaciones y "
|
|
65
|
+
"ncredtotal, o 'YYYY-MM-DDTHH:MM:SS-06:00' para IssuedDateTime.",
|
|
66
|
+
),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def classify_error(message: str) -> str | None:
|
|
71
|
+
"""Return a developer hint for a known SAT/Digifact error pattern, or None."""
|
|
72
|
+
upper = message.upper()
|
|
73
|
+
for keywords, hint in _HINTS:
|
|
74
|
+
if any(kw.upper() in upper for kw in keywords):
|
|
75
|
+
return hint
|
|
76
|
+
return None
|
digifact_sdk/tax.py
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""IVA calculations, money formatting, and Guatemala time helpers."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import re
|
|
5
|
+
from datetime import datetime, timezone, timedelta
|
|
6
|
+
from decimal import Decimal, ROUND_HALF_UP, getcontext
|
|
7
|
+
|
|
8
|
+
# Use 28-digit precision to avoid rounding drift
|
|
9
|
+
getcontext().prec = 28
|
|
10
|
+
|
|
11
|
+
_GT_TZ = timezone(timedelta(hours=-6))
|
|
12
|
+
_IVA_RATE = Decimal("12")
|
|
13
|
+
_IVA_DIVISOR = Decimal("112")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# ── Time helpers ─────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
def gt_now() -> tuple[str, str, str]:
|
|
19
|
+
"""Return (iso_with_offset, space_datetime, date_only) in Guatemala time (UTC-6)."""
|
|
20
|
+
gt = datetime.now(_GT_TZ)
|
|
21
|
+
dt_offset = gt.strftime("%Y-%m-%dT%H:%M:%S-06:00")
|
|
22
|
+
dt_space = gt.strftime("%Y-%m-%d %H:%M:%S")
|
|
23
|
+
date_only = gt.strftime("%Y-%m-%d")
|
|
24
|
+
return dt_offset, dt_space, date_only
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def gt_now_dt() -> datetime:
|
|
28
|
+
"""Return current datetime in Guatemala timezone."""
|
|
29
|
+
return datetime.now(_GT_TZ)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ── Tax ID helpers ────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
def pad_taxid(taxid: str) -> str:
|
|
35
|
+
"""Strip non-digits and left-pad to 12 characters with zeros.
|
|
36
|
+
|
|
37
|
+
Example: '44653948' → '000044653948'
|
|
38
|
+
"""
|
|
39
|
+
digits = re.sub(r"\D", "", taxid)
|
|
40
|
+
return digits.rjust(12, "0")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
# ── Money helpers ─────────────────────────────────────────────────────────────
|
|
44
|
+
|
|
45
|
+
def fmt(value: Decimal | float | str, decimals: int = 6) -> str:
|
|
46
|
+
"""Format a Decimal (or float/str) as a string with *decimals* decimal places."""
|
|
47
|
+
d = Decimal(str(value))
|
|
48
|
+
quantize_str = Decimal("1." + "0" * decimals)
|
|
49
|
+
return str(d.quantize(quantize_str, rounding=ROUND_HALF_UP))
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def calc_iva(line_total: "Decimal | float | str") -> tuple[Decimal, Decimal]:
|
|
53
|
+
"""Return (taxable_amount, iva_amount) for an IVA-inclusive line_total.
|
|
54
|
+
|
|
55
|
+
taxable_amount = line_total / 1.12
|
|
56
|
+
iva_amount = line_total - taxable_amount
|
|
57
|
+
"""
|
|
58
|
+
line_total = Decimal(str(line_total))
|
|
59
|
+
taxable = (line_total * 100 / _IVA_DIVISOR).quantize(
|
|
60
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
61
|
+
)
|
|
62
|
+
iva = (line_total - taxable).quantize(
|
|
63
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
64
|
+
)
|
|
65
|
+
return taxable, iva
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class LineCalc:
|
|
69
|
+
"""Holds all calculated values for a single invoice line item."""
|
|
70
|
+
|
|
71
|
+
def __init__(
|
|
72
|
+
self,
|
|
73
|
+
qty: Decimal,
|
|
74
|
+
unit_price: Decimal,
|
|
75
|
+
*,
|
|
76
|
+
taxable: bool = True,
|
|
77
|
+
discount: Decimal | None = None,
|
|
78
|
+
) -> None:
|
|
79
|
+
self.qty = qty
|
|
80
|
+
self.unit_price = unit_price
|
|
81
|
+
self.gross = (qty * unit_price).quantize(Decimal("0.000001"), rounding=ROUND_HALF_UP)
|
|
82
|
+
self.discount = (discount or Decimal("0")).quantize(
|
|
83
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
84
|
+
)
|
|
85
|
+
self.line_total = (self.gross - self.discount).quantize(
|
|
86
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
87
|
+
)
|
|
88
|
+
if taxable:
|
|
89
|
+
self.taxable_amount, self.iva_amount = calc_iva(self.line_total)
|
|
90
|
+
else:
|
|
91
|
+
self.taxable_amount = Decimal("0")
|
|
92
|
+
self.iva_amount = Decimal("0")
|
|
93
|
+
|
|
94
|
+
# Convenience string formatters
|
|
95
|
+
def f_qty(self) -> str:
|
|
96
|
+
return fmt(self.qty)
|
|
97
|
+
|
|
98
|
+
def f_price(self) -> str:
|
|
99
|
+
return fmt(self.unit_price)
|
|
100
|
+
|
|
101
|
+
def f_line_total(self) -> str:
|
|
102
|
+
return fmt(self.line_total)
|
|
103
|
+
|
|
104
|
+
def f_taxable(self) -> str:
|
|
105
|
+
return fmt(self.taxable_amount)
|
|
106
|
+
|
|
107
|
+
def f_iva(self) -> str:
|
|
108
|
+
return fmt(self.iva_amount)
|
|
109
|
+
|
|
110
|
+
def f_discount(self) -> str:
|
|
111
|
+
return fmt(self.discount, decimals=2)
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class InvoiceTotals:
|
|
115
|
+
"""Aggregate totals for a full invoice."""
|
|
116
|
+
|
|
117
|
+
def __init__(self, lines: list[LineCalc]) -> None:
|
|
118
|
+
self.lines = lines
|
|
119
|
+
self.grand_total = sum(ln.line_total for ln in lines).quantize(
|
|
120
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
121
|
+
)
|
|
122
|
+
self.total_iva = sum(ln.iva_amount for ln in lines).quantize(
|
|
123
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
124
|
+
)
|
|
125
|
+
self.total_taxable = sum(ln.taxable_amount for ln in lines).quantize(
|
|
126
|
+
Decimal("0.000001"), rounding=ROUND_HALF_UP
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
def f_grand_total(self) -> str:
|
|
130
|
+
return fmt(self.grand_total)
|
|
131
|
+
|
|
132
|
+
def f_total_iva(self) -> str:
|
|
133
|
+
return fmt(self.total_iva)
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: digifact-sdk
|
|
3
|
+
Version: 2.0.1
|
|
4
|
+
Summary: Python SDK for Digifact FEL Guatemala e-invoicing API
|
|
5
|
+
Author-email: AALONZOLU <noreply@github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: digifact,fel,guatemala,factura,e-invoicing,sat
|
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
9
|
+
Classifier: Intended Audience :: Developers
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: requests>=2.28
|
|
19
|
+
Provides-Extra: dev
|
|
20
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
21
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
22
|
+
Requires-Dist: pytest-timeout; extra == "dev"
|
|
23
|
+
Requires-Dist: python-dotenv; extra == "dev"
|
|
24
|
+
|
|
25
|
+
# Digifact FEL Guatemala — Python SDK
|
|
26
|
+
|
|
27
|
+
Python SDK for the [Digifact](https://www.digifact.com.gt/) FEL (Factura Electrónica en Línea) Guatemala e-invoicing API.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install digifact-sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or from source:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install -e sdk/python/
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Quick start
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
from digifact_sdk import DigifactClient
|
|
45
|
+
|
|
46
|
+
client = DigifactClient(
|
|
47
|
+
taxid="12345678",
|
|
48
|
+
username="FELUSER",
|
|
49
|
+
password="secret",
|
|
50
|
+
environment="test", # or "production"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# FACT CF — consumer final, IVA calculated automatically
|
|
54
|
+
result = client.invoice(
|
|
55
|
+
buyer="CF",
|
|
56
|
+
items=[{"description": "Consultoría", "qty": 1, "price": 100.00}]
|
|
57
|
+
)
|
|
58
|
+
print(result.auth_number)
|
|
59
|
+
|
|
60
|
+
# FACT to NIT — buyer name fetched from SAT automatically
|
|
61
|
+
result = client.invoice(
|
|
62
|
+
buyer="12345678",
|
|
63
|
+
items=[
|
|
64
|
+
{"description": "Laptop", "qty": 1, "price": 5000.00, "type": "Bien"},
|
|
65
|
+
{"description": "Soporte anual", "qty": 1, "price": 500.00},
|
|
66
|
+
]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
# FACT to CUI buyer
|
|
70
|
+
result = client.invoice(
|
|
71
|
+
buyer={"taxid": "3730617490101", "type": "CUI", "name": "Juan Pérez"},
|
|
72
|
+
items=[{"description": "Producto", "qty": 2, "price": 50.00}]
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# FCAM (Factura Cambiaria)
|
|
76
|
+
result = client.invoice(
|
|
77
|
+
buyer="12345678",
|
|
78
|
+
items=[{"description": "Servicio", "qty": 1, "price": 500.00}],
|
|
79
|
+
doc_type="FCAM",
|
|
80
|
+
payment_terms=[{"date": "2026-04-18", "amount": 500.00}]
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Credit note (NCRE)
|
|
84
|
+
result = client.credit_note(
|
|
85
|
+
buyer="12345678",
|
|
86
|
+
items=[{"description": "Devolución", "qty": 1, "price": 100.00}],
|
|
87
|
+
origin={
|
|
88
|
+
"auth_number": "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
|
|
89
|
+
"date": "2026-03-18",
|
|
90
|
+
"series": "XXXXXXXX",
|
|
91
|
+
"number": "123456",
|
|
92
|
+
},
|
|
93
|
+
reason="Producto defectuoso"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Debit note (NDEB)
|
|
97
|
+
result = client.debit_note(
|
|
98
|
+
buyer="12345678",
|
|
99
|
+
items=[{"description": "Cargo adicional", "qty": 1, "price": 50.00}],
|
|
100
|
+
origin={...},
|
|
101
|
+
reason="Cargo por entrega express"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Cancel a DTE
|
|
105
|
+
result = client.cancel(
|
|
106
|
+
auth_number="XXXXXXXX-...",
|
|
107
|
+
receiver_id="CF",
|
|
108
|
+
issue_datetime="2026-03-18 21:40:14",
|
|
109
|
+
reason="Error en monto"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Total credit note
|
|
113
|
+
result = client.credit_note_total(
|
|
114
|
+
auth_number="XXXXXXXX-...",
|
|
115
|
+
issue_datetime="2026-03-18 21:40:14",
|
|
116
|
+
reason="Nota de crédito total"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# NIT lookup
|
|
120
|
+
info = client.lookup_nit("12345678")
|
|
121
|
+
print(info["name"])
|
|
122
|
+
|
|
123
|
+
# Retrieve DTE
|
|
124
|
+
doc = client.get_dte("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Document types
|
|
128
|
+
|
|
129
|
+
| Type | Description | IVA |
|
|
130
|
+
|------|-------------|-----|
|
|
131
|
+
| `FACT` | Standard invoice | Yes |
|
|
132
|
+
| `FCAM` | Factura Cambiaria (installments) | Yes |
|
|
133
|
+
| `NDEB` | Debit note | Yes |
|
|
134
|
+
| `NCRE` | Credit note | Yes |
|
|
135
|
+
| `NABN` | Nota de Abono | No |
|
|
136
|
+
| `FESP` | Factura Especial | Yes |
|
|
137
|
+
| `RDON` | Recibo por Donación | No |
|
|
138
|
+
| `FPEQ` | Factura Pequeño Contribuyente | No |
|
|
139
|
+
| `RECI` | Recibo universitario | No |
|
|
140
|
+
| `CCA` | Cobro por Cuenta Ajena | Yes |
|
|
141
|
+
|
|
142
|
+
## IVA calculation
|
|
143
|
+
|
|
144
|
+
Prices are IVA-inclusive (what the customer pays):
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
line_total = qty × price
|
|
148
|
+
taxable_amount = line_total / 1.12
|
|
149
|
+
iva_amount = line_total − taxable_amount
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
All money values are formatted as strings with 6 decimal places.
|
|
153
|
+
|
|
154
|
+
## Item dict keys
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
{
|
|
158
|
+
"description": str, # required
|
|
159
|
+
"price": float | Decimal, # required — unit price, IVA-inclusive
|
|
160
|
+
"qty": float | Decimal, # optional, default 1
|
|
161
|
+
"type": str, # optional: "Servicio" (default) | "Bien"
|
|
162
|
+
"unit_of_measure": str, # optional, default "UNI"
|
|
163
|
+
"discount": float | None, # optional — line discount amount
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Running tests
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Unit tests (no credentials needed)
|
|
171
|
+
python -m pytest tests/ -v
|
|
172
|
+
|
|
173
|
+
# Integration tests
|
|
174
|
+
export DIGIFACT_TAXID=12345678
|
|
175
|
+
export DIGIFACT_USERNAME=FELUSER
|
|
176
|
+
export DIGIFACT_PASSWORD=your_password
|
|
177
|
+
python -m pytest tests/ -v
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Environment variables
|
|
181
|
+
|
|
182
|
+
| Variable | Description |
|
|
183
|
+
|----------|-------------|
|
|
184
|
+
| `DIGIFACT_TAXID` | Fiscal ID (e.g. `12345678`) |
|
|
185
|
+
| `DIGIFACT_USERNAME` | Username (e.g. `FELUSER`) |
|
|
186
|
+
| `DIGIFACT_PASSWORD` | Account password |
|
|
187
|
+
|
|
188
|
+
## Error handling
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
from digifact_sdk import (
|
|
192
|
+
DigifactError, # base
|
|
193
|
+
DigifactAuthError, # auth failure
|
|
194
|
+
DigifactApiError, # HTTP / API error
|
|
195
|
+
DigifactValidationError, # SAT rejection
|
|
196
|
+
DigifactNitNotFoundError, # NIT not found
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
try:
|
|
200
|
+
result = client.invoice("CF", [...])
|
|
201
|
+
except DigifactValidationError as exc:
|
|
202
|
+
print(f"SAT rejected: {exc}")
|
|
203
|
+
print(f"Code: {exc.code}")
|
|
204
|
+
print(f"Raw: {exc.raw}")
|
|
205
|
+
except DigifactError as exc:
|
|
206
|
+
print(f"SDK error: {exc}")
|
|
207
|
+
```
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
digifact_sdk/__init__.py,sha256=P_rGntB3SvBSk5lrwARtjajCig0cbZeccLQVDoy_n5s,459
|
|
2
|
+
digifact_sdk/builder.py,sha256=z8ALSyniR0fHN_bAsPCv_VvnS424GfOYU9pK3lnDbgo,27980
|
|
3
|
+
digifact_sdk/client.py,sha256=a5q9m0_QZNjU2b8yzk312xVS3lopE3o9eBFUAyM5BN8,24560
|
|
4
|
+
digifact_sdk/exceptions.py,sha256=5TYB70O13McAlA1GjpcpQZ36SZVO8AQytdvJkg-WRzY,2659
|
|
5
|
+
digifact_sdk/tax.py,sha256=fYw-5tt-Iblt5g6rfGhTrterBuCzek7jGHtTQyGoiNE,4581
|
|
6
|
+
digifact_sdk-2.0.1.dist-info/METADATA,sha256=5JzDDco0cHBEmHdeTL1wjZPmGHptWEe5Gm9RHe7U-lY,5473
|
|
7
|
+
digifact_sdk-2.0.1.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
|
|
8
|
+
digifact_sdk-2.0.1.dist-info/top_level.txt,sha256=AkYqgzigsWPcxc8Rft51PtPMcr4NEi6daW2fXNpsBZE,13
|
|
9
|
+
digifact_sdk-2.0.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
digifact_sdk
|