Wiki source code of Техническое Задание по calc-ref
Last modified by Mihail Opinca on 2026/08/16 09:12
Show last authors
| author | version | line-number | content |
|---|---|---|---|
| 1 | = Техническая документация — calc-ref = | ||
| 2 | |||
| 3 | == 1. Назначение == | ||
| 4 | |||
| 5 | Учёт импорта товаров, содержащих хладагенты, расчёт массы хладагента и CO2-эквивалента, контроль годовых квот и формирование отчётности для внутреннего использования. | ||
| 6 | |||
| 7 | == 2. Архитектура == | ||
| 8 | |||
| 9 | Монолит: один backend-процесс отдаёт и API, и собранный фронтенд. | ||
| 10 | |||
| 11 | {{code}} | ||
| 12 | Браузер | ||
| 13 | | HTTPS | ||
| 14 | v | ||
| 15 | nginx (calc-ref.online) -- proxy_pass --> gunicorn (127.0.0.1:5002) | ||
| 16 | | | ||
| 17 | Flask app (app.py) | ||
| 18 | +- /api/* -> JSON API | ||
| 19 | +- /* -> dist/ (Vue SPA, статика) | ||
| 20 | | | ||
| 21 | python-oracledb (Thick Mode) | ||
| 22 | | | ||
| 23 | Oracle DB (una.md:4024, схема DIPPFRUCT) | ||
| 24 | {{/code}} | ||
| 25 | |||
| 26 | * **Frontend**: Vue 3 (##<script setup>##), Vue Router, без Vuex/Pinia. Сборка — Vite. | ||
| 27 | * **Backend**: Flask 3, сессии на cookie, Oracle через ##python-oracledb## в **Thick Mode** (БД — Oracle 11g, для Thin Mode слишком старая). | ||
| 28 | * **БД**: Oracle, схема ##DIPPFRUCT##, таблицы с префиксом ##CR_*##. | ||
| 29 | * **Прод-инфраструктура**: systemd (gunicorn) + nginx (reverse proxy + TLS через Let's Encrypt/certbot). | ||
| 30 | |||
| 31 | == 3. Структура репозитория == | ||
| 32 | |||
| 33 | {{code}} | ||
| 34 | app.py, config.py - точка входа Flask, конфиг из .env | ||
| 35 | controllers/auth_controller.py - аутентификация (БД + fallback из .env) | ||
| 36 | models/ - доступ к данным, один файл на сущность | ||
| 37 | services/ - зарезервировано, пока пусто | ||
| 38 | migrate.py - вспомогательный скрипт миграций/данных | ||
| 39 | sql/ - DDL и миграции схемы (01...08) | ||
| 40 | src/ - Vue-приложение | ||
| 41 | dist/ - собранный фронтенд, генерируется npm run build | ||
| 42 | deploy/calc-ref.service - systemd-юнит (gunicorn) | ||
| 43 | deploy/push.sh - скрипт деплоя изменений на прод | ||
| 44 | docs/ - документация (этот раздел) | ||
| 45 | {{/code}} | ||
| 46 | |||
| 47 | == 4. Backend: модели == | ||
| 48 | |||
| 49 | |=Файл|=Отвечает за | ||
| 50 | |models/database.py|Инициализация Oracle Instant Client (Thick Mode), пул соединений | ||
| 51 | |models/user_model.py|Проверка логина/пароля (CR_USERS) | ||
| 52 | |models/refrigerant_model.py|Справочник хладагентов: код, GWP, REQUIRES_QUOTA | ||
| 53 | |models/product_model.py|Справочник товаров: связь с хладагентом, кг/ед., код ТНВЭД | ||
| 54 | |models/import_doc_model.py|Документы импорта и строки: CRUD, расчёт масс/CO2, проверка квот, отчёт | ||
| 55 | |models/quota_model.py|Годовые квоты по хладагентам (CR_QUOTAS) | ||
| 56 | |models/tax_rate_model.py|Ставки эконалога (CR_TAX_RATES), вводятся администратором вручную | ||
| 57 | |||
| 58 | Расчёт в документах импорта: ##TOTAL_KG = QUANTITY ? REFRIGERANT_KG##, ##CO2_KG = TOTAL_KG ? GWP##. Считается на backend при сохранении. | ||
| 59 | |||
| 60 | == 5. API == | ||
| 61 | |||
| 62 | Аутентификация — сессионная cookie. ##@require_auth## — нужен вход, ##@require_admin## — нужна роль admin. | ||
| 63 | |||
| 64 | |=Метод|=Путь|=Доступ|=Назначение | ||
| 65 | |POST|/api/auth/login|публичный|Вход по логину/паролю | ||
| 66 | |POST|/api/auth/logout|-|Выход | ||
| 67 | |GET|/api/auth/me|-|Текущий пользователь | ||
| 68 | |GET|/api/refrigerants|auth|Список хладагентов | ||
| 69 | |POST|/api/refrigerants|admin|Новый хладагент | ||
| 70 | |PUT|/api/refrigerants/<id>|admin|Правка хладагента | ||
| 71 | |POST|/api/refrigerants/<id>/toggle|admin|Вкл/выкл активность | ||
| 72 | |GET|/api/products|auth|Список товаров | ||
| 73 | |POST|/api/products|auth|Новый товар | ||
| 74 | |PUT|/api/products/<id>|auth|Правка товара | ||
| 75 | |POST|/api/products/<id>/toggle|auth|Вкл/выкл активность | ||
| 76 | |GET|/api/import-docs|auth|Список документов импорта | ||
| 77 | |GET|/api/import-docs/next-number|auth|Следующий свободный номер документа | ||
| 78 | |POST|/api/import-docs|auth|Создать документ (черновик) | ||
| 79 | |GET|/api/import-docs/<id>|auth|Документ + строки | ||
| 80 | |PUT|/api/import-docs/<id>|auth|Обновить документ и строки | ||
| 81 | |DELETE|/api/import-docs/<id>|auth|Удалить документ | ||
| 82 | |POST|/api/import-docs/<id>/status|auth|Смена статуса, проверка квот при POSTED | ||
| 83 | |GET|/api/quotas|auth|Квоты по году/хладагенту | ||
| 84 | |GET|/api/quotas/years|auth|Список годов с квотами | ||
| 85 | |POST|/api/quotas|auth|Новая квота | ||
| 86 | |PUT|/api/quotas/<id>|auth|Правка квоты | ||
| 87 | |DELETE|/api/quotas/<id>|auth|Удалить квоту | ||
| 88 | |GET|/api/report|auth|Отчёт по хладагентам с фильтрами | ||
| 89 | |GET|/api/report/excel|auth|Тот же отчёт, выгрузка в .xlsx | ||
| 90 | |GET|/*|публичный|Отдача SPA и статики фронтенда | ||
| 91 | |||
| 92 | == 6. База данных == | ||
| 93 | |||
| 94 | |=Таблица|=Ключевые поля|=Смысл | ||
| 95 | |CR_USERS|USERNAME, PASSWORD_HASH, ROLE|Сотрудники с доступом | ||
| 96 | |CR_REFRIGERANTS|CODE, GWP, REQUIRES_QUOTA|Справочник хладагентов | ||
| 97 | |CR_TAX_RATES|REFRIGERANT_ID, RATE, VALID_FROM/TO|Ставки эконалога | ||
| 98 | |CR_PRODUCTS|HAS_REFRIGERANT, REFRIGERANT_ID, REFRIGERANT_KG, TNVED_CODE|Справочник товаров | ||
| 99 | |CR_IMPORT_DOCS|DOC_DATE, DOC_NUMBER, SUPPLIER (NOT NULL), STATUS|Заголовки документов импорта | ||
| 100 | |CR_IMPORT_LINES|DOC_ID, PRODUCT_ID, ORIGIN_COUNTRY, QUANTITY, TOTAL_KG, CO2_KG|Строки документов | ||
| 101 | |CR_QUOTAS|YEAR, REFRIGERANT_ID, QUOTA_KG|Годовые квоты на ввоз | ||
| 102 | |||
| 103 | {{warning}} | ||
| 104 | CR_IMPORT_DOCS.SUPPLIER обязателен на уровне БД. Пустая строка трактуется Oracle как NULL и вызывает ORA-01400 — поэтому валидация стоит и на фронтенде, и на backend. | ||
| 105 | {{/warning}} | ||
| 106 | |||
| 107 | == 7. Аутентификация и роли == | ||
| 108 | |||
| 109 | Сессия хранится на сервере (Flask session cookie). Сперва проверка по Oracle (CR_USERS), при недоступности БД — fallback на пользователей из .env. Роли: **admin** (полный доступ) и **operator** (без справочника хладагентов). | ||
| 110 | |||
| 111 | == 8. Деплой == | ||
| 112 | |||
| 113 | 1. Backend: gunicorn под systemd, 2 воркера ? 4 потока, порт 127.0.0.1:5002. | ||
| 114 | 2. Oracle Instant Client (Thick Mode) в /opt/oracle/instantclient_19_19, путь зарегистрирован в ldconfig. | ||
| 115 | 3. nginx терминирует TLS (Let's Encrypt/certbot, автопродление), проксирует на gunicorn. | ||
| 116 | 4. Frontend собирается локально (##base: '/'##) и копируется вместе с backend-кодом. | ||
| 117 | 5. Обновление — скрипт ##deploy/push.sh##. |