npm package: @srsembek/kaspi-smart-pos-sdk
Description: SDK for Kaspi Smart POS API integration
Author: Arman Sarsembek
Latest version: 1.0.1

# Kaspi Smart POS SDK

SDK для интеграции с терминалами Kaspi Smart POS. Включает низкоуровневый HTTP-клиент, высокоуровневый сервис с автоматическим поллингом и интерактивный CLI-инструмент.

---

## Установка и сборка

```bash
npm install
npm run build   # компилирует TypeScript → dist/
```

---

## SmartPosClient (`src/client.ts`)

Низкоуровневый HTTP-клиент. Напрямую оборачивает методы REST API Kaspi Smart POS.

### Инициализация

```typescript
const SmartPosClient = require('./dist/client');
const client = new SmartPosClient('https://10.0.7.23:8080');
```

> SSL-сертификат терминала (самоподписанный, без IP в SAN) игнорируется автоматически.

### Методы

| Метод | Параметры | Возвращает | Описание |
|-------|-----------|------------|----------|
| `register(name)` | `name: string` | `Promise<TokenData>` | Регистрирует устройство, сохраняет токены в состояние клиента |
| `revokeToken()` | — | `Promise<TokenData>` | Обновляет токен доступа по `refreshToken` |
| `initiatePayment(amount, ownCheque?)` | `amount: number` | `Promise<PaymentData>` | Инициирует оплату, возвращает `processId` |
| `getStatus(processId)` | `processId: string` | `Promise<StatusData>` | Возвращает текущий статус транзакции |
| `actualizeStatus(processId)` | `processId: string` | `Promise<StatusData>` | Актуализирует статус на стороне сервера |
| `refund(txId, amount, method, ownCheque?)` | см. ниже | `Promise<RefundData>` | Инициирует возврат |
| `getDeviceInfo()` | — | `Promise<DeviceInfoData>` | Возвращает данные устройства, устанавливает `terminalId` |

### Типы статусов

**`PaymentStatus`**: `wait` · `success` · `fail` · `unknown`

**`SubStatus`**: `Initialize` · `WaitUser` · `WaitForQrConfirmation` · `ProcessingCard` · `WaitForPinCode` · `ProcessRefund` · `QrTransactionSuccess` · `QrTransactionFailure` · `CardTransactionSuccess` · `CardTransactionFailure` · `ProcessCancelled`

**`PaymentMethod`**: `qr` · `card` · `alaqan`

### Пример

```typescript
const client = new SmartPosClient('https://10.0.7.23:8080');

// Первая регистрация
await client.register('MyTerminal');

// Оплата
const payment = await client.initiatePayment(5000);
console.log(payment.processId); // "abc-123"

// Поллинг статуса
const status = await client.actualizeStatus(payment.processId);
console.log(status.status, status.subStatus);

// Возврат
await client.refund(status.transactionId, 5000, 'qr');
```

---

## PaymentService (`src/service.ts`)

Высокоуровневый сервис поверх `SmartPosClient`. Управляет жизненным циклом регистрации, хранит одну активную транзакцию и автоматически поллит статус каждые 2 секунды.

### Инициализация

```typescript
const PaymentService = require('./dist/service');
const service = new PaymentService('https://10.0.7.23:8080', 'MyTerminal');
await service.init();
```

### Логика регистрации

`init()` работает в двух режимах:

- **Первый запуск** — вызывает `client.register()`, сохраняет токены в `.kaspi-pos.json`
- **Повторный запуск** — загружает токены из `.kaspi-pos.json` и вызывает `client.revokeToken()` для обновления сессии

Для принудительной повторной регистрации удалите файл `.kaspi-pos.json`.

### Методы

| Метод | Параметры | Возвращает | Описание |
|-------|-----------|------------|----------|
| `init()` | — | `Promise<TokenData>` | Регистрация (первый раз) или обновление токена |
| `startPayment(amount, ownCheque?)` | `amount: number` | `Promise<PaymentData>` | Инициирует оплату и запускает поллинг. Бросает ошибку, если уже есть активная транзакция |
| `stopPayment()` | — | `void` | Останавливает поллинг и очищает текущую транзакцию |
| `getPayment()` | — | `PaymentData \| null` | Возвращает текущую активную транзакцию |
| `onStatusUpdate(cb)` | `cb: (status: StatusData) => void` | `void` | Регистрирует коллбэк на каждое обновление статуса |
| `refund(txId, amount, method, ownCheque?)` | см. client | `Promise<RefundData>` | Проксирует возврат через клиент |
| `getDeviceInfo()` | — | `Promise<DeviceInfoData>` | Проксирует получение информации об устройстве |

### Поллинг

- Вызывает `actualizeStatus` каждые **2 секунды**
- Автоматически останавливается при статусе `success` или `fail`
- Останавливается при ошибке 103 («транзакция уже в финальном статусе»)

### Пример

```typescript
const service = new PaymentService('https://10.0.7.23:8080', 'MyTerminal');

service.onStatusUpdate((status) => {
    console.log(`${status.status} / ${status.subStatus}`);
    if (status.status === 'success') {
        console.log('Оплата прошла. txId:', status.transactionId);
    }
});

await service.init();

const payment = await service.startPayment(5000);
console.log('processId:', payment.processId);
// поллинг запущен автоматически...
```

---

## CLI (`src/cli.ts`)

Интерактивный инструмент командной строки для работы с терминалом напрямую из терминала.

### Запуск

```bash
node dist/cli.js --url https://10.0.7.23:8080 --name MyTerminal
```

При запуске автоматически выполняется регистрация (или обновление токена). После успешной инициализации открывается интерактивная консоль.

После запуска используйте:

- `help` — показать список всех команд
- `help <command>` — показать подробную справку по одной команде: аргументы, типы, возвращаемые поля и примеры

### Команды

| Команда | Аргументы | Что делает |
|---------|-----------|------------|
| `pay <amount:int>` | `amount:int` | Запускает оплату и включает поллинг статуса |
| `status` | — | Показывает текущую активную транзакцию из памяти CLI |
| `stop` | — | Останавливает локальный поллинг и очищает текущую транзакцию |
| `refund <transactionId:string> <amount:int> <method:qr\|card\|alaqan>` | `transactionId:string`, `amount:int`, `method:qr\|card\|alaqan` | Запускает возврат |
| `info` | — | Получает информацию об устройстве (`posNum`, `serialNum`, `terminalId`) |
| `help [command:string]` | `command:string` optional | Показывает общую или детальную справку |
| `quit` / `exit` | — | Выходит из CLI |

### Детали по командам

#### `pay <amount:int>`

Начинает оплату. `amount` должен быть положительным целым числом в тенге.

Что вы увидите:

- сразу после запуска: `processId:string`, `status:"wait"`
- позже в поллинге: `status`, `subStatus`, а при успехе также `transactionId:string`

Пример:

```text
pay 5000
```

#### `status`

Показывает текущий `processId` и `status` активной оплаты, которую сейчас отслеживает CLI. Команда читает локальное состояние `PaymentService` и не делает новый HTTP-запрос.

Пример:

```text
status
```

#### `stop`

Останавливает локальный поллинг и очищает текущую транзакцию в CLI. Эта команда не отменяет операцию на самом Smart POS.

Пример:

```text
stop
```

#### `refund <transactionId:string> <amount:int> <method:qr|card|alaqan>`

Начинает возврат для уже успешной транзакции.

Аргументы:

- `transactionId:string` — идентификатор исходной оплаты
- `amount:int` — сумма возврата в тенге
- `method:qr|card|alaqan` — исходный метод оплаты

Откуда брать `transactionId`:

- для `qr` и `alaqan` обычно используется `chequeInfo.orderNumber`
- для `card` обычно используется `chequeInfo.rrn`

Что вы увидите сразу после запуска:

- `processId:string`
- `status:"wait"`

Примеры:

```text
refund 504711333 5000 qr
refund 307208187011 5000 card
```

#### `info`

Запрашивает данные подключенного терминала.

Что возвращается:

- `posNum:string`
- `serialNum:string`
- `terminalId:string`

Пример:

```text
info
```

#### `help [command:string]`

Показывает список команд или подробную справку по конкретной команде.

Примеры:

```text
help
help pay
help refund
```

#### `quit` / `exit`

Завершает CLI-сессию.

### Пример сессии

```
$ node dist/cli.js --url https://10.0.7.23:8080 --name MyTerminal

Registering device "MyTerminal"... OK
Type "help" or "help <command>" for command details.

> pay 5000
Payment started. processId=abc-123 status=wait
Polling status every 2s...
[poll] status=wait subStatus=WaitUser
[poll] status=wait subStatus=WaitForQrConfirmation
[poll] status=success subStatus=QrTransactionSuccess
[done] Payment succeeded. transactionId=tx-456

> refund tx-456 5000 qr
Refund initiated. processId=ref-789 status=wait

> quit
```

> Обновления статуса выводятся асинхронно над строкой ввода, не прерывая набор команды.

---

## Структура проекта

```
kaspi-pos/
├── src/
│   ├── client.ts       # HTTP-клиент Smart POS API
│   ├── service.ts      # PaymentService с поллингом и хранением токенов
│   ├── cli.ts          # Интерактивный CLI
│   ├── types.ts        # TypeScript-типы
│   ├── constants.ts    # Коды ошибок и статусы
│   └── index.ts        # Точка входа SDK
├── dist/               # Скомпилированные JS-файлы
├── .kaspi-pos.json     # Токены устройства (создаётся автоматически, не коммитить)
├── tsconfig.json
└── package.json
```

## Коды ошибок

| Код | Описание |
|-----|----------|
| 100 | Нет интернета |
| 101 | Транзакция не найдена (processId неверный или истёк срок 24ч) |
| 102 | Метод оплаты не поддерживает актуализацию |
| 103 | Статус транзакции уже финальный, актуализация невозможна |
| 104 | Транзакция не найдена |
| 105 | Внутренняя ошибка сервиса |
| 106 | Оплата заблокирована |
| 107 | Предыдущая операция ещё не завершена |
| 108 | Ошибка при начале процесса оплаты/возврата |
| 401 | Ошибка авторизации / сессия истекла |
| 500 | Внутренняя ошибка Smart POS |