mirror of
https://github.com/serty2005/rmser.git
synced 2026-02-04 19:02:33 -06:00
244 lines
6.8 KiB
Markdown
244 lines
6.8 KiB
Markdown
# RMSER Backend API Documentation (v2.0)
|
||
|
||
**Дата обновления:** Текущая
|
||
**Base URL:** `http://localhost:8080/api`
|
||
|
||
## 1. Типы данных (TypeScript Interfaces)
|
||
|
||
Используйте эти интерфейсы для строгой типизации на клиенте.
|
||
|
||
```typescript
|
||
// Базовые типы
|
||
type UUID = string;
|
||
|
||
// --- Каталог и Фасовки ---
|
||
|
||
export interface MeasureUnit {
|
||
id: UUID;
|
||
name: string; // "кг", "л", "шт", "порц"
|
||
code: string;
|
||
}
|
||
|
||
export interface ProductContainer {
|
||
id: UUID;
|
||
name: string; // "Коробка", "Пачка 200г"
|
||
count: number; // Коэффициент пересчета в базовые единицы (напр. 0.2 или 12.0)
|
||
}
|
||
|
||
export interface CatalogItem {
|
||
id: UUID;
|
||
name: string;
|
||
code: string;
|
||
measure_unit: string; // Название базовой единицы (из MainUnit)
|
||
containers: ProductContainer[]; // Доступные фасовки
|
||
}
|
||
|
||
// --- Матчинг (Обучение) ---
|
||
|
||
export interface MatchRequest {
|
||
raw_name: string; // Текст из чека
|
||
product_id: UUID; // ID товара iiko
|
||
quantity: number; // Количество (по умолчанию 1.0)
|
||
container_id?: UUID; // Опционально: ID фасовки, если выбрана
|
||
}
|
||
|
||
export interface SavedMatch {
|
||
raw_name: string;
|
||
product: CatalogItem; // Вложенный объект товара
|
||
quantity: number; // Сохраненный коэффициент/количество
|
||
container_id?: UUID;
|
||
container?: ProductContainer; // Вложенный объект фасовки (для отображения имени)
|
||
updated_at: string;
|
||
}
|
||
|
||
// --- Нераспознанное ---
|
||
|
||
export interface UnmatchedItem {
|
||
raw_name: string;
|
||
count: number; // Сколько раз встречалось в чеках
|
||
last_seen: string; // ISO Date
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Эндпоинты: OCR и Обучение
|
||
|
||
### `GET /ocr/catalog`
|
||
Получить полный справочник товаров для поиска.
|
||
Теперь включает **единицы измерения** и **фасовки**.
|
||
|
||
* **Response:** `200 OK`
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": "uuid-butter...",
|
||
"name": "Масло сливочное 82%",
|
||
"code": "00123",
|
||
"measure_unit": "кг",
|
||
"containers": [
|
||
{
|
||
"id": "uuid-pack...",
|
||
"name": "Пачка 180г",
|
||
"count": 0.180
|
||
},
|
||
{
|
||
"id": "uuid-box...",
|
||
"name": "Коробка (20 пачек)",
|
||
"count": 3.6
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": "uuid-milk...",
|
||
"name": "Молоко 3.2%",
|
||
"code": "00124",
|
||
"measure_unit": "л",
|
||
"containers": [] // Пустой массив, если фасовок нет
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### `GET /ocr/matches`
|
||
Получить список уже обученных позиций. Используется для отображения таблицы "Ранее сохраненные связи".
|
||
|
||
* **Response:** `200 OK`
|
||
|
||
```json
|
||
[
|
||
{
|
||
"raw_name": "Масло слив. 3 пачки",
|
||
"product_id": "uuid-butter...",
|
||
"product": {
|
||
"id": "uuid-butter...",
|
||
"name": "Масло сливочное 82%",
|
||
"measure_unit": "кг"
|
||
// ...остальные поля product
|
||
},
|
||
"quantity": 3,
|
||
"container_id": "uuid-pack...",
|
||
"container": {
|
||
"id": "uuid-pack...",
|
||
"name": "Пачка 180г",
|
||
"count": 0.180
|
||
},
|
||
"updated_at": "2023-10-27T10:00:00Z"
|
||
}
|
||
]
|
||
```
|
||
> **Логика отображения на фронте:**
|
||
> Если `container` пришел (не null) -> отображаем: `Quantity` x `Container.Name` (3 x Пачка 180г).
|
||
> Если `container` null -> отображаем: `Quantity` `Product.MeasureUnit` (0.54 кг).
|
||
|
||
---
|
||
|
||
### `POST /ocr/match`
|
||
Создать или обновить привязку.
|
||
|
||
* **Body:**
|
||
|
||
**Вариант 1: Базовая единица (без фасовки)**
|
||
Пользователь выбрал "Петрушка", ввел "0.5" (кг).
|
||
```json
|
||
{
|
||
"raw_name": "петрушка вес",
|
||
"product_id": "uuid-parsley...",
|
||
"quantity": 0.5
|
||
// container_id не передаем или null
|
||
}
|
||
```
|
||
|
||
**Вариант 2: С фасовкой**
|
||
Пользователь выбрал "Масло", выбрал фасовку "Коробка", ввел "2" (штуки).
|
||
```json
|
||
{
|
||
"raw_name": "масло коробка",
|
||
"product_id": "uuid-butter...",
|
||
"quantity": 2,
|
||
"container_id": "uuid-box..."
|
||
}
|
||
```
|
||
|
||
* **Response:** `200 OK` -> `{"status": "saved"}`
|
||
|
||
---
|
||
|
||
### `GET /ocr/unmatched`
|
||
Получить список частых нераспознанных товаров.
|
||
Используется для автодополнения (Suggest) в поле ввода "Текст из чека", чтобы пользователь не вводил название вручную.
|
||
|
||
* **Response:** `200 OK`
|
||
|
||
```json
|
||
[
|
||
{
|
||
"raw_name": "Хлеб Бородинский нар.",
|
||
"count": 12,
|
||
"last_seen": "2023-10-27T12:00:00Z"
|
||
},
|
||
{
|
||
"raw_name": "Пакет майка",
|
||
"count": 5,
|
||
"last_seen": "2023-10-26T09:00:00Z"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Эндпоинты: Накладные (Invoices)
|
||
|
||
### `POST /invoices/send`
|
||
Отправка накладной в iiko.
|
||
|
||
**Важно:** При формировании накладной на фронте, вы должны пересчитывать количество в базовые единицы, либо (в будущем) мы научим бэкенд принимать ID фасовки в `items`.
|
||
На данный момент API ожидает `amount` и `price` уже приведенными к единому знаменателю, либо iiko сама разберется, если мы передадим ContainerID (этот функционал в разработке на стороне `rms_client`, пока шлите базовые единицы).
|
||
|
||
```json
|
||
{
|
||
"document_number": "INV-100",
|
||
"date_incoming": "2023-10-27",
|
||
"supplier_id": "uuid...",
|
||
"store_id": "uuid...",
|
||
"items": [
|
||
{
|
||
"product_id": "uuid...",
|
||
"amount": 1.5, // 1.5 кг
|
||
"price": 100 // Цена за кг
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Эндпоинты: Аналитика
|
||
|
||
### `GET /recommendations`
|
||
Возвращает список проблем (товары без техкарт, без закупок и т.д.).
|
||
|
||
```json
|
||
[
|
||
{
|
||
"ID": "uuid...",
|
||
"Type": "UNUSED_IN_RECIPES",
|
||
"ProductID": "uuid...",
|
||
"ProductName": "Лист салата",
|
||
"Reason": "Товар не используется ни в одной техкарте",
|
||
"CreatedAt": "..."
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
## 5. System
|
||
|
||
### `GET /health`
|
||
Проверка статуса.
|
||
```json
|
||
{"status": "ok", "time": "..."}
|
||
``` |