Skip to main content

Fiscalisation Device Integration Library - Simple and Pythonic API for ZIMRA fiscal device operations

Project description

FiscGuy

Tests PyPI version Downloads Python Code style: black License

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.

InstallationQuick StartAPI ReferenceREST EndpointsDocsContributing


Features

  • Six core API functionsopen_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_code to 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:

  • fiscalinvoice lines accept hs_code in the payload and send it to FDMS as receiptLineHSCode
  • creditnote lines can inherit hs_code from the referenced original receipt line when no explicit line hs_code is provided
  • debitnote lines can inherit hs_code from 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 Certs table
  • 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:

  1. Prompt for org_name, activation_key, device_id, device_model_name, device_model_version, device_serial_number
  2. Ask whether to use production or testing FDMS
  3. Generate an RSA key pair and CSR
  4. Register the device with ZIMRA to obtain a signed certificate
  5. 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.


Developed by Casper Moyo

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

fiscguy-0.1.8.tar.gz (59.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fiscguy-0.1.8-py3-none-any.whl (71.1 kB view details)

Uploaded Python 3

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

Hashes for fiscguy-0.1.8.tar.gz
Algorithm Hash digest
SHA256 f6194d4b5285eda78853c696eead42928cae2def4a9eda5015a8f87dcd21cf1f
MD5 669304ed2997a310ad9e5f449269897f
BLAKE2b-256 8be14e957c502e0bab7a0db6224cce70aae706f55dd66cc93f8990ab24daeafb

See more details on using hashes here.

Provenance

The following attestation bundles were made for fiscguy-0.1.8.tar.gz:

Publisher: release.yml on DigitalTouchCode/fisc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for fiscguy-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 56612628039a969a3168eebfd0d061651003203c89d33d4fa65dcb18f1630c7d
MD5 b05619452c69c53ffa1039ebf4e892bf
BLAKE2b-256 f00e49557391a11805dda2c33c2483b00c01a2497ae35ee2b1200dde2f51b129

See more details on using hashes here.

Provenance

The following attestation bundles were made for fiscguy-0.1.8-py3-none-any.whl:

Publisher: release.yml on DigitalTouchCode/fisc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page