Metadata-Version: 2.4
Name: ofdclient
Version: 0.1.1
Summary: Python client for the Kazakhstan fiscal data operator middleware (Программный Фискализатор / FiscalizationService, SOAP + ЭЦП)
Project-URL: Homepage, https://github.com/DamirBakty/ofdclient
Project-URL: Repository, https://github.com/DamirBakty/ofdclient
Project-URL: Issues, https://github.com/DamirBakty/ofdclient/issues
Project-URL: Changelog, https://github.com/DamirBakty/ofdclient/blob/main/CHANGELOG.md
Author-email: Damir Baktygaliyev <damir050602@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Damir Baktygaliyev
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: cash-register,fiscal,fiscalization,kazakhstan,kkm,ncanode,ofd,ккм,офд
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial :: Point-Of-Sale
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: requests>=2.31
Requires-Dist: xmltodict>=0.13
Requires-Dist: zeep>=4.2
Description-Content-Type: text/markdown

# ofdclient

[![CI](https://github.com/DamirBakty/ofdclient/actions/workflows/ci.yml/badge.svg)](https://github.com/DamirBakty/ofdclient/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/ofdclient)](https://pypi.org/project/ofdclient/)
[![Python](https://img.shields.io/pypi/pyversions/ofdclient)](https://pypi.org/project/ofdclient/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

Python-клиент для казахстанского ОФД-middleware — «Программный Фискализатор» /
FiscalizationService 3.0.1 (SOAP, XML-запросы с ЭЦП НУЦ РК).

Библиотека не зависит от фреймворков: никакого Django или Celery внутри —
только типизированный клиент, модели данных и подключаемые сайнеры.

**English version: [README.en.md](README.en.md)**

## Документация

- [Руководство пользователя](docs/usage.md) — чеки, налоги, скидки, возвраты, смены, отчёты
- [Справочник API](docs/api.md) — все классы, методы и поля
- [Подпись ЭЦП](docs/signing.md) — NCANode, свой сервис подписи, свой сайнер
- [Коды ошибок](docs/errors.md) — ~150 кодов Фискализатора и их маппинг на исключения
- [Тестирование без ОФД](docs/testing.md) — FakeSigner, подмена транспорта
- [Интеграция с Django/Celery](examples/django_celery/) — готовый пример

## Возможности

- **Полное покрытие API Фискализатора 3.0.1**:

  | Метод клиента | SOAP-операция | Назначение |
  |---|---|---|
  | `sell(receipt)` | IncomeOperationRequest | чек продажи |
  | `refund(receipt, original)` | ReversingIncomeOperationRequest | возврат продажи |
  | `expense(receipt)` | OutgoingOperationRequest | чек покупки/расхода |
  | `expense_refund(receipt, original)` | ReversingOutgoingOperationRequest | возврат покупки |
  | `deposit(amount)` | ServiceIncomeOperationRequest | внесение наличных |
  | `withdraw(amount)` | ServiceOutgoingOperationRequest | изъятие наличных |
  | `state()` | GetKKMState | состояние ККМ |
  | `close_shift()` | CloseCurrentWorkSession | закрытие смены + Z-отчёт |
  | `x_report()` | GetXReport | X-отчёт |
  | `z_report_copy(n)` | GetZReportCopy | копия Z-отчёта смены |
  | `document_copy(id)` | GetDocumentCopy | копия документа |

- **Подключаемые сайнеры ЭЦП**: [NCANode](https://ncanode.kz), любой совместимый
  REST-сервис подписи, `FakeSigner` для тестов или своя реализация
  (один метод `sign(xml) -> str`).
- **~150 кодов ошибок** сервиса замаплены на иерархию типизированных исключений.
- **Идемпотентность** через `ClientSystemGUID`: повтор запроса не создаёт
  дубликат чека.
- **Авто-восстановление после кода 220** («смена закрыта по правилу 24 часов»):
  с `auto_close_shift=True` клиент сам закроет смену и повторит операцию.
- Полностью типизирована (PEP 561), тестируется без реального ОФД.

## Установка

```bash
pip install ofdclient
```

## Быстрый старт

```python
from decimal import Decimal

from ofdclient import (
    Customer, Item, NCANodeSigner, OFDClient, Payment, Receipt, Tax,
)

# NCANode — опенсорсный сервис подписи ЭЦП НУЦ РК (см. docs/signing.md)
signer = NCANodeSigner(
    "http://localhost:14579",
    key="<p12-ключ в base64>",
    password="пароль от ключа",
)

client = OFDClient(
    wsdl_url="https://fiscal.example.kz/FiscalizationService?wsdl",
    kkm_code="123456",          # код кассы (KKMCashDeskCode)
    cashier="cashier-1",        # идентификатор кассира (ContextCashier)
    signer=signer,
    auto_close_shift=True,      # автозакрытие смены при коде 220
)

receipt = Receipt(
    items=[
        Item(
            name="Кофе",
            price=Decimal("1500"),
            quantity=2,
            measure_unit_code="796",   # штука
            taxes=[Tax.vat(16)],       # НДС 16%, сумма считается автоматически
        ),
    ],
    payments=[Payment.card(Decimal("3000"))],
    customer=Customer(email="buyer@example.kz", phone="+77001234567"),
)

bill = client.sell(receipt)
print(bill.fiscal_sign)      # фискальный признак (FiscalisationSystemGUID)
print(bill.bill_content)     # печатная форма чека
print(bill.qr_code)          # QR-код (bytes)
```

Возврат ссылается на исходный чек — сохраняйте фискальные данные после продажи:

```python
from ofdclient import OriginalDocument

original = OriginalDocument(
    fiscal_sign=bill.fiscal_sign,
    date_time=bill.registration_datetime,
    amount=bill.amount,
    kkm_code="123456",
)
client.refund(refund_receipt, original)
```

Больше сценариев — оплата наличными со сдачей, скидки, обработка ошибок,
смены и отчёты — в [руководстве пользователя](docs/usage.md).

## Разработка

```bash
uv sync --group dev
uv run pytest
uv run ruff check src tests
uv run mypy
```

Тесты не требуют реального ОФД: SOAP-транспорт и сайнер подменяются фейками
(см. [docs/testing.md](docs/testing.md)).

## Лицензия

[MIT](LICENSE)
