---
title: Несколько касс
description: Несколько касс Payme, Click, Paynet или Uzum на одном URL вебхука Django с PayTechUZ 0.5 — раздельный учёт, sandbox-кассы и проверка кассы.
source: https://pay-tech.uz/ru/docs/integrations/multiple-kassas
---

# Несколько касс

У бизнеса часто несколько мерчант-аккаунтов у одного провайдера: боевая и
sandbox-касса или отдельная касса на каждый бренд. Начиная с **0.5.0** каждый
вебхук Django обслуживает их все на одном URL. Старые настройки с одной кассой
работают без изменений.

## Как вызов находит свою кассу

Перечислите кассы в `KASSAS`. К какой кассе относится вызов, решают данные
самого провайдера:

| Шлюз | Вызов определяется по |
| --- | --- |
| Payme | ключу в заголовке Basic auth (`PAYME_KEY`) |
| Click | `service_id` в запросе, подписанному `SECRET_KEY` этой кассы |
| Paynet | `serviceId` в запросе, иначе по логину (`USERNAME`) |
| Uzum | логину Basic auth (`USERNAME`); запрос обязан указать `serviceId` этой кассы |

Вызов, не подошедший ни к одной кассе, отклоняется как неавторизованный.

## Настройки

```python
PAYTECHUZ = {
    'PAYME': {
        'KASSAS': {
            'shop':  {'PAYME_ID': '...', 'PAYME_KEY': '...'},
            'gifts': {'PAYME_ID': '...', 'PAYME_KEY': '...'},
        },
        'KASSA_FIELD': 'kassa',          # необязательно, см. ниже
        'ACCOUNT_MODEL': 'shop.models.Order',
        'ACCOUNT_FIELD': 'id',
        'AMOUNT_FIELD': 'amount',
        'ONE_TIME_PAYMENT': True,
    },
    'CLICK': {
        'KASSAS': {
            'shop': {'SERVICE_ID': '...', 'SECRET_KEY': '...'},
        },
        # ACCOUNT_MODEL и остальное как выше
    },
    'PAYNET': {
        'KASSAS': {
            'live': {'SERVICE_ID': '1001', 'USERNAME': '...', 'PASSWORD': '...'},
            'test': {'SERVICE_ID': '1003', 'USERNAME': '...', 'PASSWORD': '...',
                     'IS_SANDBOX': True},
        },
    },
    'UZUM': {
        'KASSAS': {
            'shop': {'SERVICE_ID': '...', 'USERNAME': '...', 'PASSWORD': '...',
                     'ALLOWED_IPS': ['...']},
        },
        'IP_HEADER': 'HTTP_X_REAL_IP',
        'BEHIND_CLOUDFLARE': True,
    },
}
```

View не меняется: тот же наследник `BasePaymeWebhookView` на том же URL
обслуживает все кассы. Внутри хука `self.kassa` — имя кассы, сделавшей вызов.

## Раздельный учёт

У каждой записи в таблице `payments` есть `kassa`, и каждый поиск ограничен
кассой, сделавшей вызов. Одна касса не видит, не проводит, не отменяет и не
включает в выписку транзакции другой, а один и тот же id транзакции провайдера
может быть по одному разу в каждой кассе. У записей до 0.5 `kassa = ''` —
именно это использует настройка с одной кассой.

## Какая касса может оплатить заказ

Укажите в `KASSA_FIELD` поле модели счёта, где хранится касса, через которую
его нужно оплачивать. Вызову из другой кассы отвечают, что счёт не найден.
Если значение в счетах отличается от ключа в `KASSAS`, кассе Paynet можно
задать `ACCOUNT_KASSA` — удобно, когда sandbox- и боевой сервис делят одни
счета.

Без `KASSA_FIELD` любая касса может оплатить любой счёт.

## Sandbox-кассы

Кассы Paynet и Uzum принимают `IS_SANDBOX: True`. Платежи сохраняются, но
вместо `successfully_payment` вызывается `sandbox_payment(params,
transaction)`, то есть ничего не доставляется. Счёт остаётся доступным для
оплаты тестером провайдера, а sandbox-записи не попадают в боевые выписки.

## Перевод существующей настройки на `KASSAS`

1. Обновитесь и примените миграции: `pip install "paytechuz[django]>=0.5"`,
   затем `python manage.py migrate`.
2. У существующих записей `kassa = ''`. Перед переходом на `KASSAS`
   запишите в `kassa` каждой записи её новое имя, иначе новая касса их не
   увидит (для возвратов, проверок и выписок).
3. Переключите настройки и задеплойте.

Откат на 0.4 на Django 5+ не требует обратной миграции: у колонки есть
значение по умолчанию в базе, старый код её не замечает.
