Помощь кассиру

Первый чек за пять минут

Включаем обмен на демо-кассе, отправляем документ и забираем результат.

Подготовка кассы

  1. Поставьте YaKassa версии 2.2.09.395 или новее. Для проб подойдёт демо-касса: её чеки не фискальные.
  2. Откройте смену на кассе.
  3. Откройте Настройки → Обмен. Включите Обмен по http: появится «Номер для обмена», это и есть токен. Для работы по локальной сети включите TCP сервер: в заголовке настройки указан порт, обычно 8090, а под ней адрес кассы.
  4. Проверьте индикаторы в правом верхнем углу: Обмен и TCP должны быть зелёными.
  5. Оставьте приложение на экране. В свёрнутом виде обмен останавливается.

Шаг 1. Отправить документ

У каждого чека свой id. Сгенерируйте GUID и не меняйте его, если придётся повторить запрос.

HTTP, через сервер
curl -X POST 'https://ofd.yaros.kg:8143/ofd-0.0.1/gate/receipt-v4' \
  -H 'token: <токен с экрана кассы>' \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "operation": "INCOME",
    "cashless": false,
    "products": [
      { "id": "1", "name": "Молоко", "price": 100.00, "quantity": 1,
        "vat_value": 0, "st_value": 0, "calcItemAttributeCode": "0" }
    ]
  }'

Ответ значит только «документ принят», чека ещё нет:

JSON
{ "id": "550e8400-e29b-41d4-a716-446655440000", "status": "OK", "info": "Документ принят" }

Шаг 2. Забрать результат

Спрашивайте статус раз в 1–2 секунды, пока он не перестанет быть PROCESSING.

HTTP, через сервер
curl -X POST 'https://ofd.yaros.kg:8143/ofd-0.0.1/gate/receipt-status-v4' \
  -H 'token: <токен с экрана кассы>' \
  -H 'Content-Type: application/json' \
  -d '{ "id": "550e8400-e29b-41d4-a716-446655440000" }'

Чек пробит, когда пришёл OK с реквизитами:

JSON
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "OK",
  "qr": "https://…/ticket?date=20261102T101500&type=3&…",
  "amount": 100.00,
  "cashless": false,
  "shiftNumber": "42",
  "receiptNumber": "17",
  "fdNumber": "3160",
  "fpd": "1359586714023",
  "gnsDate": "20261102T101500",
  "rnKKM": "0000000000000000",
  "fnKKM": "0000000000000000",
  "kkmID": "65f1234567890abcdef12345"
}

Сохраните fdNumber, qr и kkmID: они понадобятся для возврата, печати и поиска чека. Значения статусов разобраны в описании ответа.

Минимальный клиент

Один и тот же код работает с обоими каналами: разница только в адресе и токене.

Python
import time
import uuid
import requests


class YaKassa:
    def __init__(self, base_url, token=None):
        # HTTP: "https://ofd.yaros.kg:8143/ofd-0.0.1", token="<токен>"
        # TCP:  "http://192.168.0.50:8090", token=None
        self.base_url = base_url.rstrip("/")
        self.headers = {"Content-Type": "application/json"}
        if token:
            self.headers["token"] = token

    def _post(self, path, body):
        r = requests.post(self.base_url + path, json=body, headers=self.headers, timeout=30)
        data = r.json()
        if data.get("status") == "fail":           # формат ошибок TCP
            raise RuntimeError(data.get("message"))
        return data

    def receipt(self, doc, timeout_sec=300):
        accepted = self._post("/gate/receipt-v4", doc)
        if accepted.get("status") == "ERROR":
            raise RuntimeError(accepted.get("info"))

        deadline = time.monotonic() + timeout_sec
        while time.monotonic() < deadline:
            time.sleep(1.5)
            result = self._post("/gate/receipt-status-v4", {"id": doc["id"]})
            status = result.get("status")
            if status in ("OK", "PAID"):
                return result
            if status == "ERROR" and result.get("info") == "Request already working":
                continue                           # занята сессия, а не отказ по документу
            if status != "PROCESSING":
                raise RuntimeError(result.get("info") or status)
        raise TimeoutError("Нет результата. Не создавайте новый id: спросите статус позже по " + doc["id"])


doc = {
    "id": str(uuid.uuid4()),
    "operation": "INCOME",
    "cashless": False,
    "products": [{
        "id": "1", "name": "Молоко", "price": 100.00, "quantity": 2,
        "vat_value": 0, "st_value": 0, "calcItemAttributeCode": "0",
    }],
}

kassa = YaKassa("https://ofd.yaros.kg:8143/ofd-0.0.1", token="<токен>")
# kassa = YaKassa("http://192.168.0.50:8090")      # тот же код через TCP
result = kassa.receipt(doc)
print(result["status"], result.get("fdNumber"), result.get("qr"))

Смотрите также