Fiscalisation Device Integration Library - Simple and Pythonic API for ZIMRA fiscal device operations
Project description
FiscGuy
The Modern Python Library for ZIMRA Fiscal Device Integration
FiscGuy gives Django applications a simple, Pythonic interface for every fiscal operation required by the Zimbabwe Revenue Authority — receipt submission, fiscal day management, certificate handling, and more. Built on Django REST Framework, it drops into any Django project in minutes.
Installation • Quick Start • API Reference • REST Endpoints • Docs • Contributing
Features
- Six core API functions —
open_day,close_day,submit_receipt,get_status,get_configuration,get_taxes - Full fiscal day lifecycle — open, manage counters, close with ZIMRA-compliant hash and signature
- Receipt types — Fiscal Invoice, Credit Note, Debit Note with correct counter tracking
- Online FDMS submission — receipts are validated, signed, and submitted directly to FDMS
- Certificate management — CSR generation, device registration, certificate renewal via
init_device - Multi-currency — USD and ZWG support with per-currency counter tracking
- Multiple payment methods — Cash, Card, Mobile Wallet, Bank Transfer, Coupon, Credit, Other
- Buyer management — optional buyer TIN and registration data on receipts
- Cursor pagination — efficient receipt listing for large datasets
- Protected key storage — device private keys are encrypted at rest
- Operational hardening — certificate material is redacted in Django admin and temporary PEM files are cleaned up after use
- Typed exceptions — every error condition has its own exception class
- 90%+ test coverage — mocked ZIMRA and crypto, fast CI
Requirements
- Python 3.11, 3.12, or 3.13
- Django 4.2+
- Django REST Framework 3.14+
Installation
pip install fiscguy
From source
git clone https://github.com/digitaltouchcode/fisc.git
cd fisc
pip install -e ".[dev]"
Quick Start
1. Add to Django settings
# settings.py
INSTALLED_APPS = [
# ...
"fiscguy",
"rest_framework",
]
2. Run migrations
python manage.py migrate
3. Initialise your device
python manage.py init_device
This interactive command collects your device credentials, generates a CSR, registers the device with ZIMRA, and fetches taxes and configuration automatically.
4. Include URLs
# urls.py
from django.urls import path, include
urlpatterns = [
path("fiscguy/", include("fiscguy.urls")),
]
5. Submit your first receipt
from fiscguy import open_day, submit_receipt, close_day
open_day()
receipt = submit_receipt({
"receipt_type": "fiscalinvoice",
"currency": "USD",
"total_amount": "115.00",
"payment_terms": "Cash",
"lines": [
{
"product": "Consulting Service",
"hs_code": "99001000",
"tax_id": 517,
"quantity": "1",
"unit_price": "115.00",
"line_total": "115.00",
"tax_amount": "15.00",
}
],
})
close_day()
REST Endpoints
When URLs are included, FiscGuy exposes the following endpoints:
| Method | Endpoint | Description |
|---|---|---|
POST |
/fiscguy/open-day/ |
Open a new fiscal day |
POST |
/fiscguy/close-day/ |
Close the current fiscal day |
GET |
/fiscguy/get-status/ |
Get device and fiscal day status |
POST |
/fiscguy/get-ping/ |
Ping FDMS to report device is online |
GET |
/fiscguy/receipts/ |
List receipts (cursor paginated) |
POST |
/fiscguy/receipts/ |
Submit a new receipt |
GET |
/fiscguy/receipts/{id}/ |
Retrieve a receipt by ID |
GET |
/fiscguy/configuration/ |
Get taxpayer configuration |
POST |
/fiscguy/sync-config/ |
Manually sync configuration from FDMS |
GET |
/fiscguy/taxes/ |
List all tax types |
POST |
/fiscguy/issue-certificate/ |
Renew device certificate |
* |
/fiscguy/buyer/ |
Buyer CRUD (ModelViewSet) |
Close-Day Status Flow
Closing a fiscal day has two states to track:
- Local database state -
open,close_pending,close_failed,closed - FDMS state - values such as
FiscalDayOpen,FiscalDayCloseInitiated,FiscalDayClosed
FiscGuy does not mark the fiscal day closed locally on the first close request. When FDMS
accepts the request with FiscalDayCloseInitiated, the library keeps the local day in
close_pending, starts background status polling, and only marks the day closed after FDMS
confirms the close.
Typical user-facing messages are:
Close request submitted. FDMS is processing the fiscal day close.Closing fiscal day... waiting for FDMS confirmation.Fiscal day closed successfully.Fiscal day close failed in FDMS.
For frontend integrations, call POST /fiscguy/close-day/ once, then poll
GET /fiscguy/get-status/ until the fiscal day moves from close_pending to closed or
close_failed.
HS Code Mapping
FiscGuy supports hs_code on receipt lines and passes it through to FDMS as
receiptLineHSCode.
Firms should map their product and service catalogues to the correct FDMS-compatible HS codes before going live. In practice, this means:
- Physical goods should use the applicable tariff / HS classification for that item
- Services and intangible supplies should use the appropriate ZIMRA service classifications where applicable
- HS codes should be maintained as product master data, not typed ad hoc at the point of sale
Recommended approach:
- Add
hs_codeto each product or service in your own catalogue - Copy that code into each receipt line when submitting receipts
- Reuse the original receipt line HS code for credit notes and product-linked debit notes where possible
Current behavior:
fiscalinvoicelines accepths_codein the payload and send it to FDMS asreceiptLineHSCodecreditnotelines can inheriths_codefrom the referenced original receipt line when no explicit linehs_codeis provideddebitnotelines can inheriths_codefrom the referenced original receipt line, or fall back to the appropriate ZIMRA service code when the debit line is a service/intangible adjustment
Example receipt line:
{
"product": "Consulting Service",
"hs_code": "99001000",
"tax_id": 517,
"quantity": "1",
"unit_price": "115.00",
"line_total": "115.00",
"tax_amount": "15.00"
}
Use GET /fiscguy/taxes/ to fetch the active device tax table first, then submit the
matching tax_id on each receipt line. Do not rely on tax-name strings in production payloads.
Security
FiscGuy includes baseline protections for certificate and signing material:
- Device private keys are encrypted at rest in the
Certstable - Raw certificate and private-key fields are not exposed through the default Django admin registration
- Temporary PEM files used for mutual TLS are written with restricted permissions and cleaned up after use
- Dependency versions are maintained against known vulnerability advisories
For production deployments, you should still review application-level authentication, admin access, database encryption policy, backup handling, and key-management requirements for your environment.
Pagination
Receipt listing supports cursor-based pagination:
GET /fiscguy/receipts/?page_size=20
Default page size: 10. Maximum: 100.
Error Handling
All operations raise typed exceptions. Import them from fiscguy.exceptions:
from fiscguy.exceptions import (
ReceiptSubmissionError,
CloseDayError,
FiscalDayError,
ConfigurationError,
CertificateError,
DevicePingError,
StatusError,
)
try:
close_day()
except CloseDayError as e:
print(f"Close day failed: {e}")
| Exception | Raised when |
|---|---|
ReceiptSubmissionError |
Receipt processing or FDMS submission fails |
CloseDayError |
FDMS rejects the close day request |
FiscalDayError |
Fiscal day cannot be opened or is already open |
ConfigurationError |
Configuration is missing or sync fails |
CertificateError |
Certificate issuance or renewal fails |
DevicePingError |
Ping to FDMS fails |
StatusError |
Status fetch from FDMS fails |
DeviceRegistrationError |
Device registration with ZIMRA fails |
CryptoError |
RSA signing or hashing fails |
Models
FiscGuy adds the following tables to your database:
| Model | Description |
|---|---|
Device |
Fiscal device registration details |
Configuration |
Taxpayer configuration synced from FDMS |
Certs |
Device certificate and private key |
Taxes |
Tax types synced from FDMS on day open |
FiscalDay |
Daily fiscal period with receipt counter |
FiscalCounter |
Running totals per tax / payment method |
Receipt |
Submitted receipts with hash, signature, QR code |
ReceiptLine |
Individual line items on a receipt |
Buyer |
Optional buyer registration data |
Access them directly:
from fiscguy.models import Device, Receipt, FiscalDay, Taxes
device = Device.objects.first()
open_days = FiscalDay.objects.filter(is_open=True)
receipts = Receipt.objects.select_related("buyer").prefetch_related("lines")
Management Commands
init_device
Interactive device setup for first-time provisioning:
python manage.py init_device
The command will:
- Prompt for
org_name,activation_key,device_id,device_model_name,device_model_version,device_serial_number - Ask whether to use production or testing FDMS
- Generate an RSA key pair and CSR
- Register the device with ZIMRA to obtain a signed certificate
- Fetch and persist configuration and taxes
Testing
# Run all tests
pytest
# With coverage report
pytest --cov=fiscguy --cov-report=html
# Run a specific test file
pytest fiscguy/tests/test_views.py
# Run a specific test
pytest fiscguy/tests/test_closing_day_service.py::TestBuildSaleByTax
All tests mock ZIMRA API calls and crypto operations — no network access required.
Dependency audit:
pip-audit -r requirements.txt
Documentation
Full documentation lives in the docs/ folder:
| Document | Description |
|---|---|
docs/installation.md |
Detailed installation and setup guide |
docs/receipt-types.md |
Fiscal Invoice, Credit Note, Debit Note rules |
docs/fiscal-counters.md |
How counters work and how they are calculated |
docs/closing-day.md |
Closing day hash string and signature spec |
docs/certificate-management.md |
Certificate lifecycle and renewal |
docs/error-reference.md |
All exceptions and what causes them |
docs/changelog.md |
Version history |
docs/contributing.md |
Contributing guidelines |
Contributing
Contributions are welcome. Please read docs/contributing.md first.
# Set up dev environment
git clone https://github.com/digitaltouchcode/fisc.git
cd fisc
pip install -e ".[dev]"
pre-commit install
# Before submitting a PR
black fiscguy
isort fiscguy
flake8 fiscguy
pytest
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fiscguy-0.1.8.tar.gz.
File metadata
- Download URL: fiscguy-0.1.8.tar.gz
- Upload date:
- Size: 59.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f6194d4b5285eda78853c696eead42928cae2def4a9eda5015a8f87dcd21cf1f
|
|
| MD5 |
669304ed2997a310ad9e5f449269897f
|
|
| BLAKE2b-256 |
8be14e957c502e0bab7a0db6224cce70aae706f55dd66cc93f8990ab24daeafb
|
Provenance
The following attestation bundles were made for fiscguy-0.1.8.tar.gz:
Publisher:
release.yml on DigitalTouchCode/fisc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fiscguy-0.1.8.tar.gz -
Subject digest:
f6194d4b5285eda78853c696eead42928cae2def4a9eda5015a8f87dcd21cf1f - Sigstore transparency entry: 1435067580
- Sigstore integration time:
-
Permalink:
DigitalTouchCode/fisc@405a680cf47cd078f6e067c3b6cee2651bc30285 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/DigitalTouchCode
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@405a680cf47cd078f6e067c3b6cee2651bc30285 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fiscguy-0.1.8-py3-none-any.whl.
File metadata
- Download URL: fiscguy-0.1.8-py3-none-any.whl
- Upload date:
- Size: 71.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
56612628039a969a3168eebfd0d061651003203c89d33d4fa65dcb18f1630c7d
|
|
| MD5 |
b05619452c69c53ffa1039ebf4e892bf
|
|
| BLAKE2b-256 |
f00e49557391a11805dda2c33c2483b00c01a2497ae35ee2b1200dde2f51b129
|
Provenance
The following attestation bundles were made for fiscguy-0.1.8-py3-none-any.whl:
Publisher:
release.yml on DigitalTouchCode/fisc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fiscguy-0.1.8-py3-none-any.whl -
Subject digest:
56612628039a969a3168eebfd0d061651003203c89d33d4fa65dcb18f1630c7d - Sigstore transparency entry: 1435067602
- Sigstore integration time:
-
Permalink:
DigitalTouchCode/fisc@405a680cf47cd078f6e067c3b6cee2651bc30285 -
Branch / Tag:
refs/tags/v0.1.8 - Owner: https://github.com/DigitalTouchCode
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@405a680cf47cd078f6e067c3b6cee2651bc30285 -
Trigger Event:
push
-
Statement type: