Metadata-Version: 2.4
Name: fatoority
Version: 0.4.1
Summary: Python bindings for the fatoority library, providing ZATCA-compliant e-invoicing functionality.
Author: mqqz
License-Expression: MIT OR Apache-2.0
Project-URL: Homepage, https://docs.fatoority.com
Project-URL: Repository, https://github.com/mqqz/fatoority
Project-URL: Documentation, https://docs.fatoority.com
Project-URL: Issues, https://github.com/mqqz/fatoority/issues
Keywords: zatca,invoice,e-invoicing,sdk,ffi
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE-MIT
License-File: LICENSE-APACHE
License-File: THIRD_PARTY_NOTICES.md
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Dynamic: license-file

## Fatoority Python bindings

This package wraps Diplomat-generated native bindings with the public `fatoora`
Python API. Install with `pip install fatoority` and import as `fatoora`. See [Diplomat bindings](../../docs/development/diplomat.md).

### Development (uv)

```bash
uv venv
uv pip install .
```

### Build a wheel (uv)

```bash
uv build --wheel
```

### Wheels (CI)

- GitHub Actions uses `cibuildwheel` to produce platform wheels in `dist/` (wheel-only publishing).
- See `.github/workflows/python.yml` for the build matrix.

### Notes

- The build step compiles `fatoora-ffi` with `cargo build -p fatoora-ffi --release`.
- The shared library is bundled into the Python package.
- Building the native extension requires CMake and a C++20 compiler. Nanobind is
  pinned in the build dependencies. Reinstall the package after native changes.
- ZATCA API responses are exposed via opaque handles with getters (no JSON payloads).
- Errors are raised as typed exceptions mapped from FFI error codes (see `FfiErrorKind`). Each exception exposes `.code`, `.kind`, and `.details`, a dictionary containing structured validation issues or diagnostics. Unknown codes remain available on a generic `FfiError`.
- Reinstall the package after changes; the extension loads its bundled shared library.

### Examples

```bash
python examples/load_lib.py
python examples/invoice_basic.py
python examples/invoice_parse.py
```

### Tests

```bash
uv pip install -e .[dev]
SKIP_ZATCA_LIVE_API=1 uv run pytest tests
```

### High-level API

```python
from fatoora import InvoiceBuilder, InvoiceSubType, InvoiceTypeKind, VatCategory

builder = InvoiceBuilder.new(
    invoice_type=InvoiceTypeKind.TAX,
    invoice_subtype=InvoiceSubType.SIMPLIFIED,
)
builder.set_id("INV-1")
builder.set_uuid("123e4567-e89b-12d3-a456-426614174000")
builder.set_issue_datetime("2024-01-01T12:30:00Z")
builder.set_currency("SAR")
builder.set_previous_invoice_hash("hash")
builder.set_invoice_counter(1)
builder.set_payment_means_code("10")
builder.set_vat_category(VatCategory.STANDARD)
builder.set_seller(
    name="Acme Inc",
    country_code="SAU",
    city="Riyadh",
    street="King Fahd",
    building_number="1234",
    postal_code="12222",
    vat_id="399999999900003",
)
builder.add_line_item(
    description="Item",
    quantity="1.0",
    unit_code="PCE",
    unit_price="100.0",
    vat_rate="15.0",
    vat_category=VatCategory.STANDARD,
)
invoice = builder.build()
print(invoice.xml())
```

`set_issue_datetime` expects a ZATCA ISO UTC timestamp string (`YYYY-MM-DDTHH:MM:SSZ`).

### Local ZATCA validation

```python
from fatoora import Config, validate_zatca_invoice_from_str

with Config() as config:
    report = validate_zatca_invoice_from_str(
        config, xml, previous_invoice_hash=previous_hash_from_history,
    )
if not report["is_valid"]:
    print(report["stages"])
```

The report retains warnings and distinguishes rejection from incomplete coverage.
Missing predecessor context leaves the report incomplete. Execution failures raise
a typed exception with any partial report in `error.details["report"]`. Standard
invoices skip signature/QR checks in this SDK profile. Local integrity does not
establish issuer trust or remote acceptance. The wheel embeds runtime schemas
and native rules; Java, SDK files and a source checkout are unnecessary.
