Техническое Задание по calc-ref

Last modified by Mihail Opinca on 2026/08/16 09:12

Техническая документация — calc-ref

1. Назначение

Учёт импорта товаров, содержащих хладагенты, расчёт массы хладагента и CO2-эквивалента, контроль годовых квот и формирование отчётности для внутреннего использования.

2. Архитектура

Монолит: один backend-процесс отдаёт и API, и собранный фронтенд.

Браузер
  |  HTTPS
   v
nginx (calc-ref.online) -- proxy_pass --> gunicorn (127.0.0.1:5002)
                                             |
                                        Flask app (app.py)
                                       +- /api/*      -> JSON API
                                        +- /*          -> dist/ (Vue SPA, статика)
                                              |
                                        python-oracledb (Thick Mode)
                                              |
                                        Oracle DB (una.md:4024, схема DIPPFRUCT)
  • Frontend: Vue 3 (<script setup>), Vue Router, без Vuex/Pinia. Сборка — Vite.
  • Backend: Flask 3, сессии на cookie, Oracle через python-oracledb в Thick Mode (БД — Oracle 11g, для Thin Mode слишком старая).
  • БД: Oracle, схема DIPPFRUCT, таблицы с префиксом CR_*.
  • Прод-инфраструктура: systemd (gunicorn) + nginx (reverse proxy + TLS через Let's Encrypt/certbot).

3. Структура репозитория

app.py, config.py                  - точка входа Flask, конфиг из .env
controllers/auth_controller.py     - аутентификация (БД + fallback из .env)
models/                            - доступ к данным, один файл на сущность
services/                          - зарезервировано, пока пусто
migrate.py                         - вспомогательный скрипт миграций/данных
sql/                                - DDL и миграции схемы (01...08)
src/                                - Vue-приложение
dist/                               - собранный фронтенд, генерируется npm run build
deploy/calc-ref.service            - systemd-юнит (gunicorn)
deploy/push.sh                     - скрипт деплоя изменений на прод
docs/                               - документация (этот раздел)

4. Backend: модели

ФайлОтвечает за
models/database.pyИнициализация Oracle Instant Client (Thick Mode), пул соединений
models/user_model.pyПроверка логина/пароля (CR_USERS)
models/refrigerant_model.pyСправочник хладагентов: код, GWP, REQUIRES_QUOTA
models/product_model.pyСправочник товаров: связь с хладагентом, кг/ед., код ТНВЭД
models/import_doc_model.pyДокументы импорта и строки: CRUD, расчёт масс/CO2, проверка квот, отчёт
models/quota_model.pyГодовые квоты по хладагентам (CR_QUOTAS)
models/tax_rate_model.pyСтавки эконалога (CR_TAX_RATES), вводятся администратором вручную

Расчёт в документах импорта: TOTAL_KG = QUANTITY ? REFRIGERANT_KG, CO2_KG = TOTAL_KG ? GWP. Считается на backend при сохранении.

5. API

Аутентификация — сессионная cookie. @require_auth — нужен вход, @require_admin — нужна роль admin.

МетодПутьДоступНазначение
POST/api/auth/loginпубличныйВход по логину/паролю
POST/api/auth/logout-Выход
GET/api/auth/me-Текущий пользователь
GET/api/refrigerantsauthСписок хладагентов
POST/api/refrigerantsadminНовый хладагент
PUT/api/refrigerants/<id>adminПравка хладагента
POST/api/refrigerants/<id>/toggleadminВкл/выкл активность
GET/api/productsauthСписок товаров
POST/api/productsauthНовый товар
PUT/api/products/<id>authПравка товара
POST/api/products/<id>/toggleauthВкл/выкл активность
GET/api/import-docsauthСписок документов импорта
GET/api/import-docs/next-numberauthСледующий свободный номер документа
POST/api/import-docsauthСоздать документ (черновик)
GET/api/import-docs/<id>authДокумент + строки
PUT/api/import-docs/<id>authОбновить документ и строки
DELETE/api/import-docs/<id>authУдалить документ
POST/api/import-docs/<id>/statusauthСмена статуса, проверка квот при POSTED
GET/api/quotasauthКвоты по году/хладагенту
GET/api/quotas/yearsauthСписок годов с квотами
POST/api/quotasauthНовая квота
PUT/api/quotas/<id>authПравка квоты
DELETE/api/quotas/<id>authУдалить квоту
GET/api/reportauthОтчёт по хладагентам с фильтрами
GET/api/report/excelauthТот же отчёт, выгрузка в .xlsx
GET/*публичныйОтдача SPA и статики фронтенда

6. База данных

ТаблицаКлючевые поляСмысл
CR_USERSUSERNAME, PASSWORD_HASH, ROLEСотрудники с доступом
CR_REFRIGERANTSCODE, GWP, REQUIRES_QUOTAСправочник хладагентов
CR_TAX_RATESREFRIGERANT_ID, RATE, VALID_FROM/TOСтавки эконалога
CR_PRODUCTSHAS_REFRIGERANT, REFRIGERANT_ID, REFRIGERANT_KG, TNVED_CODEСправочник товаров
CR_IMPORT_DOCSDOC_DATE, DOC_NUMBER, SUPPLIER (NOT NULL), STATUSЗаголовки документов импорта
CR_IMPORT_LINESDOC_ID, PRODUCT_ID, ORIGIN_COUNTRY, QUANTITY, TOTAL_KG, CO2_KGСтроки документов
CR_QUOTASYEAR, REFRIGERANT_ID, QUOTA_KGГодовые квоты на ввоз
Warning

CR_IMPORT_DOCS.SUPPLIER обязателен на уровне БД. Пустая строка трактуется Oracle как NULL и вызывает ORA-01400 — поэтому валидация стоит и на фронтенде, и на backend.

7. Аутентификация и роли

Сессия хранится на сервере (Flask session cookie). Сперва проверка по Oracle (CR_USERS), при недоступности БД — fallback на пользователей из .env. Роли: admin (полный доступ) и operator (без справочника хладагентов).

8. Деплой

  1. Backend: gunicorn под systemd, 2 воркера ? 4 потока, порт 127.0.0.1:5002.
    2. Oracle Instant Client (Thick Mode) в /opt/oracle/instantclient_19_19, путь зарегистрирован в ldconfig.
    3. nginx терминирует TLS (Let's Encrypt/certbot, автопродление), проксирует на gunicorn.
    4. Frontend собирается локально (base: '/') и копируется вместе с backend-кодом.
    5. Обновление — скрипт deploy/push.sh.