206 lines
7.0 KiB
Markdown
206 lines
7.0 KiB
Markdown
# FNS Receipt Service
|
||
|
||
Express-сервис на Node.js 22 для создания чеков через ФНС и отправки ссылки на чек по email.
|
||
|
||
## Локальный запуск
|
||
|
||
```bash
|
||
npm install
|
||
cp .env.example .env
|
||
npm start
|
||
```
|
||
|
||
Сервис запустится на порту из `PORT` или на `4000` по умолчанию.
|
||
|
||
Админ-интерфейс доступен по адресу:
|
||
|
||
```http
|
||
GET /admin
|
||
```
|
||
|
||
Для входа используется значение `API_PASS`. Через интерфейс можно смотреть локальный журнал чеков, синхронизировать последние чеки из кабинета ФНС, создавать чек вручную, проверять ФНС/SMTP и менять параметры сервиса без отдельного фронтенд-фреймворка.
|
||
|
||
Swagger UI доступен по адресу:
|
||
|
||
```http
|
||
GET /swagger
|
||
```
|
||
|
||
OpenAPI JSON доступен по адресу:
|
||
|
||
```http
|
||
GET /openapi.json
|
||
```
|
||
|
||
## Docker
|
||
|
||
Сборка образа:
|
||
|
||
```bash
|
||
docker build -t fns-receipt-service .
|
||
```
|
||
|
||
Запуск контейнера:
|
||
|
||
```bash
|
||
docker run --env-file .env -p 3000:3000 fns-receipt-service
|
||
```
|
||
|
||
## Переменные окружения
|
||
|
||
Заполните эти переменные в Timeweb Cloud в разделе переменных окружения:
|
||
|
||
```env
|
||
INN=123456789012
|
||
PASSWORD=your_fns_password
|
||
APPNAME=Название проекта
|
||
ADMIN_EMAIL=admin@example.com
|
||
SMTP_HOST=smtp.example.com
|
||
SMTP_PORT=587
|
||
SMTP_SECURE=false
|
||
SMTP_USER=noreply@example.com
|
||
SMTP_PASS=email_app_password
|
||
SMTP_MAIL_FROM=noreply@example.com
|
||
API_PASS=strong_api_password
|
||
JWT_SECRET=long_random_jwt_secret
|
||
ADMIN_SESSION_HOURS=12
|
||
REDIS_HOST=127.0.0.1
|
||
REDIS_PORT=6379
|
||
REDIS_USER=default
|
||
REDIS_PASS=redis_password
|
||
REDIS_DB=0
|
||
REDIS_KEY_PREFIX=fns-receipt-service
|
||
REDIS_TIMEOUT_MS=5000
|
||
PORT=3000
|
||
HOST=0.0.0.0
|
||
FNS_TIMEOUT_MS=30000
|
||
SMTP_TIMEOUT_MS=15000
|
||
```
|
||
|
||
`API_PASS` используется как пароль входа в админ-панель и должен совпадать с `api_pass` в старых запросах к `POST /api/v1/create-receipt`. После входа UI получает JWT и дальше отправляет запросы с `Authorization: Bearer <token>`.
|
||
|
||
`JWT_SECRET` лучше задавать отдельно от `API_PASS`. Если `JWT_SECRET` не задан, сервис подпишет JWT через `API_PASS`, но для продакшена это менее удобно при ротации пароля.
|
||
|
||
Настройки, измененные через UI, сохраняются в `data/config.json` и перекрывают значения из `.env`. Сетевые параметры `PORT` и `HOST` применятся после перезапуска процесса.
|
||
|
||
Чеки сохраняются в Redis, если задан `REDIS_URL` или `REDIS_HOST`. Основной ключ:
|
||
|
||
```text
|
||
fns-receipt-service:receipts
|
||
```
|
||
|
||
Префикс можно изменить через `REDIS_KEY_PREFIX`. Если Redis не настроен или временно недоступен, сервис использует локальный fallback `data/receipts.json`.
|
||
|
||
## Timeweb Cloud
|
||
|
||
Что заполнить при Docker-деплое:
|
||
|
||
| Поле | Значение |
|
||
| --- | --- |
|
||
| Dockerfile | `Dockerfile` |
|
||
| Порт | `3000` |
|
||
| Путь до директории проекта | `/fns-receipt-service` |
|
||
| Путь проверки состояния | `/health` |
|
||
|
||
Команду запуска для Docker-деплоя отдельно указывать не нужно: она уже задана в `Dockerfile` как `CMD ["node", "/app/server.js"]`.
|
||
|
||
## API
|
||
|
||
Документация доступна в Swagger UI:
|
||
|
||
```http
|
||
GET /swagger
|
||
```
|
||
|
||
Авторизация API поддерживает два способа:
|
||
|
||
- `Authorization: Bearer <token>` после логина через `POST /api/v1/auth/login`
|
||
- `x-api-key: <API_PASS>` для серверных интеграций
|
||
|
||
Для совместимости `POST /api/v1/create-receipt` также принимает `api_pass` в JSON body.
|
||
|
||
Проверка состояния:
|
||
|
||
```http
|
||
GET /health
|
||
```
|
||
|
||
Получить JWT:
|
||
|
||
```http
|
||
POST /api/v1/auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"password": "strong_api_password"
|
||
}
|
||
```
|
||
|
||
Создание чека:
|
||
|
||
```http
|
||
POST /api/v1/create-receipt
|
||
Content-Type: application/json
|
||
X-Api-Key: strong_api_password
|
||
|
||
{
|
||
"email": "client@example.com",
|
||
"items": [
|
||
{
|
||
"id": "order-1",
|
||
"name": "Услуга",
|
||
"price": 1000,
|
||
"quantity": 1
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
Поле `email` обязательно: на этот адрес сервис отправит письмо со ссылкой на чек после успешного создания чека в ФНС.
|
||
|
||
Получить журнал чеков:
|
||
|
||
```http
|
||
GET /api/v1/receipts?limit=50&offset=0&status=created&clientType=individual&search=client@example.com
|
||
X-Api-Key: strong_api_password
|
||
```
|
||
|
||
Журнал можно фильтровать по периоду через `dateFrom` и `dateTo`:
|
||
|
||
```http
|
||
GET /api/v1/receipts?dateFrom=2026-06-01&dateTo=2026-06-30
|
||
X-Api-Key: strong_api_password
|
||
```
|
||
|
||
Экспортировать все чеки за период в CSV без пагинации:
|
||
|
||
```http
|
||
GET /api/v1/receipts/export?dateFrom=2026-06-01&dateTo=2026-06-30
|
||
X-Api-Key: strong_api_password
|
||
```
|
||
|
||
Получить один чек:
|
||
|
||
```http
|
||
GET /api/v1/receipts/{receiptId}
|
||
X-Api-Key: strong_api_password
|
||
```
|
||
|
||
Синхронизировать чеки из ФНС за месяц:
|
||
|
||
```http
|
||
POST /api/v1/receipts/sync
|
||
Content-Type: application/json
|
||
X-Api-Key: strong_api_password
|
||
|
||
{
|
||
"month": "2026-06"
|
||
}
|
||
```
|
||
|
||
Если чек создан в ФНС, но письмо клиенту не отправилось, API вернет `success: true`, `receiptCreated: true`, `emailSent: false`, `receiptId`, `printLink` и `technicalError`. Ошибка отправки сохранится в `error.json`.
|
||
|
||
Все успешно созданные чеки сохраняются в Redis, чтобы в UI была связь между чеком, email пользователя и позициями заказа. Синхронизация с ФНС выполняется за выбранный месяц, подтягивает страницы по 50 записей до конца месяца и помечает аннулированные чеки как `cancelled`. Аннулированные чеки показываются в списке, но не учитываются в количестве действующих чеков и итоговой сумме.
|
||
|
||
В UI и API по каждому чеку рассчитываются суммы `grossAmount` (грязными), `taxAmount` (налог) и `netAmount` (чистыми). Для физлиц используется ставка 4%, для юрлиц 6%.
|