/
Paff
/
declarant
Обзор
Документация
Войти
/
Paff
/
declarant
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
web/api_corrections.py
214 строк
8 KB
1pash1985-gif
feat: corrections feedback system (all 5 phases)
23 июл 2026, 16:22
23 июл 2026, 16:22
3fbd368
Код
Авторство
О чём код?
""" Декларант — API корректировок (CRUD). Endpoints: GET /api/corrections — список всех корректировок (history + synonyms + rules) POST /api/corrections — добавить корректировку DELETE /api/corrections/<id> — удалить из history по ID GET /api/corrections/synonyms — получить синонимы цветов POST /api/corrections/synonyms — добавить/обновить синоним DELETE /api/corrections/synonyms/<abbr> — удалить синоним GET /api/corrections/supplier-rules — правила поставщиков POST /api/corrections/supplier-rules — добавить/обновить правило POST /api/corrections/export-excel — экспорт в Excel POST /api/corrections/import-excel — импорт из Excel """ from __future__ import annotations import sys from pathlib import Path from flask import Blueprint, jsonify, request # Добавляем корень проекта в sys.path PROJECT_ROOT = Path(__file__).resolve().parent.parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from corrections import ( load_corrections, save_corrections, export_to_excel, import_from_excel, ) corrections_bp = Blueprint('corrections', __name__) @corrections_bp.route('/api/corrections', methods=['GET']) def get_corrections(): """Получить все корректировки.""" corr = load_corrections() return jsonify({ 'ok': True, 'history': corr.history, 'flower_synonyms': corr.flower_synonyms, 'supplier_rules': corr.supplier_rules, 'marking_aliases': corr.marking_aliases, 'marking_to_column': corr.marking_to_column, 'variety_to_family': corr.variety_to_family, 'stats': { 'history_count': len(corr.history), 'synonyms_count': len(corr.flower_synonyms), 'supplier_rules_count': len(corr.supplier_rules), 'marking_rules_count': len(corr.marking_to_column), 'family_rules_count': len(corr.variety_to_family), }, }) @corrections_bp.route('/api/corrections', methods=['POST']) def add_correction(): """Добавить корректировку в историю. Body JSON: source_file, supplier, type, field, original_value, corrected_value """ data = request.get_json(silent=True) or {} required = ['field', 'original_value', 'corrected_value'] for key in required: if not data.get(key): return jsonify({'error': f'Отсутствует поле: {key}'}), 400 corr = load_corrections() corr.add_correction( source_file=data.get('source_file', ''), supplier=data.get('supplier', ''), correction_type=data.get('type', 'recognition'), field_name=data['field'], original_value=data['original_value'], corrected_value=data['corrected_value'], ) # Если это synonym-type — автоматически обновляем flower_synonyms if data.get('type') == 'synonym' and data.get('field') == 'flower_synonym': corr.set_flower_synonym(data['original_value'], data['corrected_value']) save_corrections(corr) return jsonify({'ok': True, 'history_count': len(corr.history)}) @corrections_bp.route('/api/corrections/<correction_id>', methods=['DELETE']) def delete_correction(correction_id): """Удалить корректировку из history по ID.""" corr = load_corrections() original_len = len(corr.history) corr.history = [h for h in corr.history if h.get('id') != correction_id] if len(corr.history) == original_len: return jsonify({'error': 'Корректировка не найдена'}), 404 save_corrections(corr) return jsonify({'ok': True, 'history_count': len(corr.history)}) # --- Synonyms --- @corrections_bp.route('/api/corrections/synonyms', methods=['GET']) def get_synonyms(): """Получить синонимы цветов.""" corr = load_corrections() return jsonify({ 'ok': True, 'flower_synonyms': corr.flower_synonyms, 'variety_to_family': corr.variety_to_family, }) @corrections_bp.route('/api/corrections/synonyms', methods=['POST']) def add_synonym(): """Добавить/обновить синоним цветка. Body JSON: { abbreviation, full_name } """ data = request.get_json(silent=True) or {} abbr = (data.get('abbreviation') or '').strip() full = (data.get('full_name') or '').strip() if not abbr or not full: return jsonify({'error': 'Нужны abbreviation и full_name'}), 400 corr = load_corrections() corr.set_flower_synonym(abbr, full) save_corrections(corr) return jsonify({'ok': True, 'flower_synonyms': corr.flower_synonyms}) @corrections_bp.route('/api/corrections/synonyms/<abbr>', methods=['DELETE']) def delete_synonym(abbr): """Удалить синоним цветка.""" corr = load_corrections() key = abbr.strip().upper() if key not in corr.flower_synonyms: return jsonify({'error': 'Синоним не найден'}), 404 del corr.flower_synonyms[key] save_corrections(corr) return jsonify({'ok': True}) # --- Supplier rules --- @corrections_bp.route('/api/corrections/supplier-rules', methods=['GET']) def get_supplier_rules(): """Получить правила поставщиков.""" corr = load_corrections() return jsonify({'ok': True, 'supplier_rules': corr.supplier_rules}) @corrections_bp.route('/api/corrections/supplier-rules', methods=['POST']) def add_supplier_rule(): """Добавить/обновить правило поставщика. Body JSON: { supplier, country?, default_flower?, hs_code? } """ data = request.get_json(silent=True) or {} supplier = (data.get('supplier') or '').strip() if not supplier: return jsonify({'error': 'Нужен supplier'}), 400 kwargs = {} for key in ('country', 'default_flower', 'hs_code'): if data.get(key): kwargs[key] = data[key].strip() if not kwargs: return jsonify({'error': 'Нужно хотя бы одно правило (country/default_flower/hs_code)'}), 400 corr = load_corrections() corr.set_supplier_rule(supplier, **kwargs) save_corrections(corr) return jsonify({'ok': True, 'supplier_rules': corr.supplier_rules}) @corrections_bp.route('/api/corrections/supplier-rules/<supplier>', methods=['DELETE']) def delete_supplier_rule(supplier): """Удалить правило поставщика.""" corr = load_corrections() key = supplier.strip().upper() if key not in corr.supplier_rules: return jsonify({'error': 'Правило не найдено'}), 404 del corr.supplier_rules[key] save_corrections(corr) return jsonify({'ok': True}) # --- Excel export/import --- @corrections_bp.route('/api/corrections/export-excel', methods=['POST']) def do_export_excel(): """Экспортировать corrections в Excel.""" corr = load_corrections() path = export_to_excel(corr) return jsonify({'ok': True, 'path': path}) @corrections_bp.route('/api/corrections/import-excel', methods=['POST']) def do_import_excel(): """Импортировать corrections из Excel.""" from pathlib import Path as P default_xlsx = P(__file__).resolve().parent.parent / 'corrections.xlsx' if not default_xlsx.exists(): return jsonify({'error': 'Файл corrections.xlsx не найден'}), 404 corr = load_corrections() corr = import_from_excel(str(default_xlsx), corr) save_corrections(corr) return jsonify({'ok': True, 'stats': { 'history_count': len(corr.history), 'synonyms_count': len(corr.flower_synonyms), 'supplier_rules_count': len(corr.supplier_rules), }})