feat: ребрендинг под dokogenPZI (основа из dokogen187)

This commit is contained in:
2026-08-03 23:45:18 +04:00
parent da4946cb59
commit f151cf1bfe
11 changed files with 37 additions and 37 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ from PyInstaller.utils.hooks import collect_data_files, collect_submodules
datas = [ datas = [
# Справочники (defense_tools.json, pd_actions.json, pd_items.json, pd_categories.json) # Справочники (defense_tools.json, pd_actions.json, pd_items.json, pd_categories.json)
('dokogen/dictionaries', 'dokogen/dictionaries'), ('dokogen/dictionaries', 'dokogen/dictionaries'),
# Пустой опросник 187-ФЗ (для «Справка → Пустой опросник») # Пустой опросник PZI (для «Справка → Пустой опросник»)
('dokogen/data', 'dokogen/data'), ('dokogen/data', 'dokogen/data'),
# Иконка приложения (для окна программы в exe) # Иконка приложения (для окна программы в exe)
('dokogen/icon.ico', 'dokogen'), ('dokogen/icon.ico', 'dokogen'),
+1 -1
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""DokoGen — Пакет генератора документов 187-ФЗ""" """DokoGen — Пакет генератора документов PZI"""
from .models import Company, CommissionMember, InformationSystem, PaperDocument from .models import Company, CommissionMember, InformationSystem, PaperDocument
from .declension import inflect_name, decline, company_name_decline, get_short_fio, get_initials from .declension import inflect_name, decline, company_name_decline, get_short_fio, get_initials
+8 -8
View File
@@ -5,7 +5,7 @@
рядом с программой (при сборке .exe — рядом с exe): рядом с программой (при сборке .exe — рядом с exe):
- Инструкция_пользователя.docx - Инструкция_пользователя.docx
- Инструкция_администратора.docx - Инструкция_администратора.docx
- Опросный_лист_187_ФЗ.xlsx (пустой шаблон) - Опросный_лист_PZI.xlsx (пустой шаблон)
""" """
import os import os
@@ -45,7 +45,7 @@ def variables_reference_path():
def survey_path(): def survey_path():
return os.path.join(docs_dir(), 'Опросный_лист_187_ФЗ.xlsx') return os.path.join(docs_dir(), 'Опросный_лист_PZI.xlsx')
def _h(doc, text, size=14): def _h(doc, text, size=14):
@@ -83,7 +83,7 @@ def _generate_variables_reference(path):
_p(doc, 'Список переменных для шаблонов Word. Переменная подставляется в текст ' _p(doc, 'Список переменных для шаблонов Word. Переменная подставляется в текст '
'как есть: {{имя_переменной}}. Циклы: <!-- loop:имя --> ... <!-- loop_end -->.') 'как есть: {{имя_переменной}}. Циклы: <!-- loop:имя --> ... <!-- loop_end -->.')
groups = {'A': 'Общие переменные', 'B': '187-ФЗ (персональные данные)'} groups = {'A': 'Общие переменные', 'B': 'PZI (персональные данные)'}
by_group = {'A': [], 'B': []} by_group = {'A': [], 'B': []}
for var, group, desc, _ in VARIABLE_DEFS: for var, group, desc, _ in VARIABLE_DEFS:
by_group.setdefault(group, []).append((var, desc)) by_group.setdefault(group, []).append((var, desc))
@@ -108,11 +108,11 @@ def _generate_variables_reference(path):
def _generate_user_manual(path): def _generate_user_manual(path):
"""Инструкция пользователя: программа, циклы, переменные, проверки.""" """Инструкция пользователя: программа, циклы, переменные, проверки."""
doc = docx.Document() doc = docx.Document()
_h(doc, 'ДоКоГеНеРаТоР — 187-ФЗ') _h(doc, 'ДоКоГеНеРаТоР — PZI')
_h(doc, 'Инструкция пользователя', 13) _h(doc, 'Инструкция пользователя', 13)
_h(doc, '1. Что это за программа', 12) _h(doc, '1. Что это за программа', 12)
_p(doc, 'Программа автоматически заполняет шаблоны документов по 187-ФЗ ' _p(doc, 'Программа автоматически заполняет шаблоны документов по PZI '
'(акты обследования, политики, инструкции, приказы и т.д.) данными ' '(акты обследования, политики, инструкции, приказы и т.д.) данными '
'об организации, информационных системах, комиссии и сотрудниках. ' 'об организации, информационных системах, комиссии и сотрудниках. '
'Данные можно ввести вручную на вкладках или импортировать из ' 'Данные можно ввести вручную на вкладках или импортировать из '
@@ -173,7 +173,7 @@ def _generate_user_manual(path):
def _generate_admin_manual(path): def _generate_admin_manual(path):
"""Инструкция администратора: словари, API-ключи, лимиты.""" """Инструкция администратора: словари, API-ключи, лимиты."""
doc = docx.Document() doc = docx.Document()
_h(doc, 'ДоКоГеНеРаТоР — 187-ФЗ') _h(doc, 'ДоКоГеНеРаТоР — PZI')
_h(doc, 'Инструкция администратора', 13) _h(doc, 'Инструкция администратора', 13)
_h(doc, '1. Файлы настроек рядом с программой', 12) _h(doc, '1. Файлы настроек рядом с программой', 12)
@@ -240,8 +240,8 @@ def _ensure_survey():
return target return target
# Ищем шаблон опросника: рядом с программой или встроенный # Ищем шаблон опросника: рядом с программой или встроенный
candidates = [ candidates = [
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'Опросный_лист_187_ФЗ.xlsx'), os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'Опросный_лист_PZI.xlsx'),
os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Опросный_лист_187_ФЗ.xlsx'), os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Опросный_лист_PZI.xlsx'),
] ]
for c in candidates: for c in candidates:
if os.path.exists(c): if os.path.exists(c):
+9 -9
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""DokoGen — Модуль импорта из Excel (опросный лист 187-ФЗ)""" """DokoGen — Модуль импорта из Excel (опросный лист PZI)"""
import re import re
import traceback import traceback
@@ -122,8 +122,8 @@ def clean_value(val):
return text return text
def import_187fz(filepath: str, log_fn: Optional[Callable] = None, settings_path: Optional[str] = None) -> dict: def import_pzifz(filepath: str, log_fn: Optional[Callable] = None, settings_path: Optional[str] = None) -> dict:
"""Импорт данных из опросного листа Excel (187-ФЗ). """Импорт данных из опросного листа Excel (PZI).
settings_path путь к JSON-файлу настроек импорта (что и откуда брать). settings_path путь к JSON-файлу настроек импорта (что и откуда брать).
Если None файл import_settings.json рядом с программой; если его нет Если None файл import_settings.json рядом с программой; если его нет
@@ -154,9 +154,9 @@ def import_187fz(filepath: str, log_fn: Optional[Callable] = None, settings_path
return data return data
try: try:
_import_187_common(wb, data, settings, log_fn) _import_pzi_common(wb, data, settings, log_fn)
_import_187_is_list(wb, data, settings, log_fn) _import_pzi_is_list(wb, data, settings, log_fn)
_import_187_employees(wb, data, settings, log_fn) _import_pzi_employees(wb, data, settings, log_fn)
except Exception as e: except Exception as e:
log_fn(f"❌ Ошибка при импорте: {e}") log_fn(f"❌ Ошибка при импорте: {e}")
log_fn(traceback.format_exc()) log_fn(traceback.format_exc())
@@ -179,7 +179,7 @@ def import_187fz(filepath: str, log_fn: Optional[Callable] = None, settings_path
return data return data
def _import_187_common(wb, data, settings, log_fn): def _import_pzi_common(wb, data, settings, log_fn):
"""Импорт общих сведений по словарю настроек. """Импорт общих сведений по словарю настроек.
Для каждого поля: сначала пробуем конкретную ячейку (cell), Для каждого поля: сначала пробуем конкретную ячейку (cell),
@@ -247,7 +247,7 @@ def _import_187_common(wb, data, settings, log_fn):
break break
def _import_187_is_list(wb, data, settings, log_fn): def _import_pzi_is_list(wb, data, settings, log_fn):
"""Импорт информационных систем из остальных листов.""" """Импорт информационных систем из остальных листов."""
exclude_kws = settings.get('is_sheet_exclude_keywords', ['общие сведения', 'сотрудники']) exclude_kws = settings.get('is_sheet_exclude_keywords', ['общие сведения', 'сотрудники'])
is_sheets = [] is_sheets = []
@@ -447,7 +447,7 @@ def _import_187_is_list(wb, data, settings, log_fn):
log_fn(f"\n✅ Всего импортировано ИС: {len(is_list)}") log_fn(f"\n✅ Всего импортировано ИС: {len(is_list)}")
def _import_187_employees(wb, data, settings, log_fn): def _import_pzi_employees(wb, data, settings, log_fn):
"""Импорт комиссии и сотрудников из листа «Сотрудники».""" """Импорт комиссии и сотрудников из листа «Сотрудники»."""
sheet_name = None sheet_name = None
sheet_kw = settings.get('employees_sheet_keyword', 'сотруд') sheet_kw = settings.get('employees_sheet_keyword', 'сотруд')
+2 -2
View File
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""DokoGen — Модели данных (только 187-ФЗ, только нужные поля)""" """DokoGen — Модели данных (только PZI, только нужные поля)"""
from dataclasses import dataclass, field, asdict from dataclasses import dataclass, field, asdict
from typing import List, Dict, Any from typing import List, Dict, Any
@@ -49,7 +49,7 @@ class PaperDocument:
@dataclass @dataclass
class Company: class Company:
"""Организация — основной объект (187-ФЗ)""" """Организация — основной объект (PZI)"""
# Полное название # Полное название
full_name: str = "" full_name: str = ""
company_name_1: str = "" # именительный company_name_1: str = "" # именительный
+8 -8
View File
@@ -31,7 +31,7 @@ class DokoGenApp:
def __init__(self, root: tk.Tk): def __init__(self, root: tk.Tk):
self.root = root self.root = root
root.title("ДоКоГеНеРаТоР — 187-ФЗ (КИИ)") root.title("ДоКоГеНеРаТоР — PZI")
root.geometry("1200x800") root.geometry("1200x800")
root.minsize(900, 600) root.minsize(900, 600)
self._set_app_icon() self._set_app_icon()
@@ -44,7 +44,7 @@ class DokoGenApp:
self._last_template_dir: str = "" self._last_template_dir: str = ""
self._autosave_path = os.path.join( self._autosave_path = os.path.join(
os.path.dirname(os.path.abspath(__file__)), os.path.dirname(os.path.abspath(__file__)),
'.autosave', 'autosave_187.json' '.autosave', 'autosave_pzifz.json'
) )
# Путь к файлу настроек импорта (словарь «что и откуда брать») # Путь к файлу настроек импорта (словарь «что и откуда брать»)
@@ -1757,7 +1757,7 @@ class DokoGenApp:
is_list=self.model.information_systems, is_list=self.model.information_systems,
doc_number=self.doc_number_var.get(), doc_number=self.doc_number_var.get(),
doc_date=self.doc_date_var.get(), doc_date=self.doc_date_var.get(),
direction='187fz', direction='pzifz',
) )
results = [] results = []
@@ -1846,7 +1846,7 @@ class DokoGenApp:
def import_from_survey(self): def import_from_survey(self):
path = filedialog.askopenfilename( path = filedialog.askopenfilename(
title="Выберите опросный лист (187-ФЗ)", title="Выберите опросный лист (PZI)",
filetypes=[("Excel", "*.xlsx *.xls")] filetypes=[("Excel", "*.xlsx *.xls")]
) )
if not path: if not path:
@@ -1856,8 +1856,8 @@ class DokoGenApp:
# Импорт в отдельном потоке # Импорт в отдельном потоке
def _run(): def _run():
try: try:
from .importer import import_187fz from .importer import import_pzifz
data = import_187fz(path, self.log, settings_path=self.import_settings_path) data = import_pzifz(path, self.log, settings_path=self.import_settings_path)
if data: if data:
self._apply_imported_data(data) self._apply_imported_data(data)
except ImportError: except ImportError:
@@ -2203,7 +2203,7 @@ class DokoGenApp:
def show_about(self): def show_about(self):
messagebox.showinfo("О программе", messagebox.showinfo("О программе",
"ДоКоГеНеРаТоР — 187-ФЗ\n" "ДоКоГеНеРаТоР — PZI\n"
"Версия 1.0\n" "Версия 1.0\n"
"Генератор документов из шаблонов") "Генератор документов из шаблонов")
@@ -2251,7 +2251,7 @@ class DokoGenApp:
def download_survey(self): def download_survey(self):
from .help_docs import ensure_docs, survey_path from .help_docs import ensure_docs, survey_path
ensure_docs() ensure_docs()
self._save_resource(survey_path(), "Опросный_лист_187_ФЗ.xlsx", "Сохранить пустой опросник") self._save_resource(survey_path(), "Опросный_лист_PZI.xlsx", "Сохранить пустой опросник")
def main(): def main():
+4 -4
View File
@@ -19,7 +19,7 @@ def _norm_name(s):
# ОПИСАНИЕ ПЕРЕМЕННЫХ # ОПИСАНИЕ ПЕРЕМЕННЫХ
# ============================================================ # ============================================================
# Формат: (имя_переменной, группа, описание, ключ_резолвера) # Формат: (имя_переменной, группа, описание, ключ_резолвера)
# Группы: A — общие, B — 187-ФЗ # Группы: A — общие, B — PZI
VARIABLE_DEFS = [ VARIABLE_DEFS = [
# === Полное название организации (6 падежей) === # === Полное название организации (6 падежей) ===
@@ -68,7 +68,7 @@ VARIABLE_DEFS = [
('{{document_date}}', 'A', 'Дата документа', 'doc_date'), ('{{document_date}}', 'A', 'Дата документа', 'doc_date'),
('{{document_number}}', 'A', 'Номер документа', 'doc_number'), ('{{document_number}}', 'A', 'Номер документа', 'doc_number'),
# === 187-ФЗ === # === PZI ===
('{{is_security_requirements}}', 'B', 'Требования уровня защищённости', 'security_reqs'), ('{{is_security_requirements}}', 'B', 'Требования уровня защищённости', 'security_reqs'),
('{{is_list}}', 'B', 'Список всех ИС (нумерованный)', 'is_list'), ('{{is_list}}', 'B', 'Список всех ИС (нумерованный)', 'is_list'),
('{{is_name}}', 'B', 'Наименование первой ИС', 'is:name'), ('{{is_name}}', 'B', 'Наименование первой ИС', 'is:name'),
@@ -138,7 +138,7 @@ def build_replacements(
is_list: List = None, is_list: List = None,
doc_number: str = "", doc_number: str = "",
doc_date: str = "", doc_date: str = "",
direction: str = "187fz", direction: str = "pzifz",
) -> Dict[str, str]: ) -> Dict[str, str]:
"""Строит полный словарь замен {{переменная}} → значение.""" """Строит полный словарь замен {{переменная}} → значение."""
if is_list is None: if is_list is None:
@@ -159,7 +159,7 @@ def build_replacements(
replacements = {} replacements = {}
for var_name, group, desc, source in VARIABLE_DEFS: for var_name, group, desc, source in VARIABLE_DEFS:
if direction == '187fz' and group not in ('A', 'B'): if direction == 'pzifz' and group not in ('A', 'B'):
continue continue
value = _resolve(source, ctx) value = _resolve(source, ctx)
replacements[var_name] = str(value) if value else '' replacements[var_name] = str(value) if value else ''
+1 -1
View File
@@ -399,7 +399,7 @@ def check_company_ai(company_data, api_key, model='deepseek-chat', base_url=None
if not api_key: if not api_key:
return None, "Не задан API-ключ ИИ (Файл → Настройки → API)" return None, "Не задан API-ключ ИИ (Файл → Настройки → API)"
system = ( system = (
"Ты — юрист по защите персональных данных (187-ФЗ). Проверь реквизиты организации. " "Ты — юрист по защите персональных данных (PZI). Проверь реквизиты организации. "
"Верни ТОЛЬКО JSON: " "Верни ТОЛЬКО JSON: "
'{"оценка": "ok|warning|error", ' '{"оценка": "ok|warning|error", '
'"замечания": ["..."], ' '"замечания": ["..."], '
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""DokoGen — Генератор документов 187-ФЗ """DokoGen — Генератор документов PZI
Точка входа: python main.py Точка входа: python main.py
""" """
import sys import sys
+2 -2
View File
@@ -87,7 +87,7 @@ def test_zip_loop_expansion():
is_list=company.information_systems, is_list=company.information_systems,
doc_number='001', doc_number='001',
doc_date='31.07.2026', doc_date='31.07.2026',
direction='187fz' direction='pzifz'
) )
loops = replacements.get('_loops', {}) loops = replacements.get('_loops', {})
@@ -135,7 +135,7 @@ def test_zip_loop_expansion():
is_list=company.information_systems, is_list=company.information_systems,
doc_number='001', doc_number='001',
doc_date='31.07.2026', doc_date='31.07.2026',
direction='187fz' direction='pzifz'
) )
try: try: