elfisa-pharmacy/docs/API.md
Magomed 5c439fe780 Apply client markup_percent from price API and fix truncated download logs.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-20 11:36:20 +03:00

8.8 KiB
Raw Permalink Blame History

API — Электронная Фармация

Документация по HTTP-запросам, которые использует десктоп-клиент.

Реализация: src/ElectronicPharmacy/Classes/ApiClient.cs, DataSender.cs, InvoiceSyncService.cs.


Базовый URL

{ApiBaseUrl}
Источник Приоритет
Настройки пользователя (Settings.ApiBaseUrl, окно Авторизация) 1
Переменная окружения ELF_API_BASE_URL 2
Значение по умолчанию http://195.34.241.84:9988

Таймаут: 30 секунд (ApiClient). Для отправки заказов (DataSender) таймаут не задан явно.

Формат: JSON, кодировка UTF-8.


Авторизация

Все запросы, кроме логина, требуют заголовок:

Authorization: Bearer {JWT}

Токен сохраняется в Settings.stringToken после успешного входа.


Эндпоинты

1. Вход

Метод POST
Путь /auth/login
Авторизация не требуется

Где в приложении: окно Авторизация (HF_Registration), загрузка прайса (HF_DownloadDataFromServer — если токен отсутствует).

Запрос:

{
  "username": "логин",
  "password": "пароль"
}

Ответ 200:

{
  "token": "jwt..."
}

Ошибка 401:

{
  "error": "описание ошибки"
}

2. Сводный прайс

Метод GET
Путь /api/supplier-prices/summary
Query supplier_id (опц.), region_id (опц.)

Где в приложении: меню Обмен → Загрузить, кнопка обновления прайса в главном окне (HF_DownloadDataFromServer).

Примеры:

GET /api/supplier-prices/summary
GET /api/supplier-prices/summary?region_id={RegionId}
GET /api/supplier-prices/summary?supplier_id={uuid}

Ответ 200:

{
  "markup_percent": 15.5,
  "summary": [
    {
      "supplier_price_id": "uuid",
      "guid_es": "uuid",
      "supplier_id": "uuid",
      "supplier_name": "Катрен",
      "drug_name": "Название препарата",
      "inn": "МНН",
      "cure_form": "таб.",
      "barcode": "...",
      "price": 123.45,
      "markup_percent": 15.5,
      "quantity": 10,
      "region_id": "...",
      "region_name": "...",
      "last_price_date": "2026-07-14T00:00:00Z",
      "match_method": "BARCODE",
      "match_confidence": 0.95,
      "trade_name": "...",
      "dosage": "...",
      "registry_price": 100.00,
      "instruction_guid": "...",
      "description": "...",
      "storing_condition": "...",
      "expiry_period": "12.2027",
      "producer_name": "...",
      "registry_date": "...",
      "es_code": 123456,
      "registry_status": "..."
    }
  ]
}

После ответа: данные записываются в локальную SQLite-таблицу PriceList (полная перезапись).

Класс: ApiClient.GetPriceSummaryAsync


3. Отправка заказа

Метод POST
Путь /api/buyer/orders
Content-Type application/json

Где в приложении:

  • меню Обмен → Отправить — все заказы со статусом НОВЫЙ (DataSender.Main);
  • страница Заказы, кнопка ОТПРАВИТЬ — один выбранный заказ (DataSender.SendSingleOrderAsync).

Запрос (один заказ = один POST):

{
  "location_id": "uuid точки из Settings.LocationId",
  "comment": "комментарий или null",
  "items": [
    {
      "supplier_price_id": "uuid позиции из прайса",
      "qty": 5
    }
  ]
}

Условия отправки:

  • в локальной БД заказ имеет статус НОВЫЙ;
  • у каждой позиции заполнен supplier_price_id;
  • qty > 0;
  • задан location_id в настройках.

При успехе: локально Orders.OrderStateОТПРАВЛЕН (только для отправленного заказа).

При ошибке: toast с HTTP-кодом и телом ответа сервера.

Класс: DataSender


4. Накладные и отказы

Метод GET
Путь /api/buyer/invoices

Где в приложении: кнопка Обновить с сервера на вкладках Накладные и Отказы (InvoiceSyncService).

Ответ 200: массив объектов

[
  {
    "InvoiceNumber": "12345",
    "InvoiceDate": "2026-07-14",
    "SupplierName": "Поставщик",
    "ConsigneeName": "Грузополучатель",
    "InvoiceSum": "10000.00",
    "RefuseSum": "500.00"
  }
]

После ответа: INSERT OR REPLACE в локальную таблицу Invoice.

Класс: ApiClient.GetInvoicesAsync


Сводная таблица

Действие в UI HTTP Эндпоинт Класс / метод
Авторизация POST /auth/login ApiClient.LoginAsync
Загрузить прайс GET /api/supplier-prices/summary ApiClient.GetPriceSummaryAsync
Отправить заказ(ы) POST /api/buyer/orders DataSender.SendOrderAsync
Обновить накладные / отказы GET /api/buyer/invoices ApiClient.GetInvoicesAsync

Обработка ошибок

Ситуация Поведение клиента
401 Unauthorized Сообщение об ошибке авторизации; для прайса токен сбрасывается в ApiClient
Таймаут (30 с) HttpRequestException с текстом о превышении времени ожидания
Прочие HTTP-ошибки Тело { "error": "..." } если сервер вернул JSON
Нет location_id Отправка заказов блокируется до заполнения в настройках
Нет токена Загрузка накладных и отправка заказов блокируются

Что не реализовано

  • PUT, PATCH, DELETE к API
  • Получение статуса заказа с сервера
  • Синхронизация справочников (поставщики, грузополучатели) через API
  • Автоматический re-login при истечении токена

Примеры curl

Логин:

curl -X POST "{ApiBaseUrl}/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"user","password":"pass"}'

Прайс:

curl "{ApiBaseUrl}/api/supplier-prices/summary" \
  -H "Authorization: Bearer {token}"

Отправка заказа:

curl -X POST "{ApiBaseUrl}/api/buyer/orders" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{"location_id":"...","comment":null,"items":[{"supplier_price_id":"...","qty":1}]}'

Накладные:

curl "{ApiBaseUrl}/api/buyer/invoices" \
  -H "Authorization: Bearer {token}"