start commit
This commit is contained in:
32
README.md
32
README.md
@@ -1,2 +1,32 @@
|
|||||||
# covid19dd
|
# 🧾 Скрипт генерации XML для плана диспансеризации
|
||||||
|
|
||||||
|
## 📋 Назначение
|
||||||
|
Скрипт автоматически формирует XML-файл плана диспансеризации по данным из CSV-файла (списка пациентов).
|
||||||
|
|
||||||
|
## ⚙️ Как работает
|
||||||
|
1. При запуске скрипт запрашивает **код МО** (6 цифр).
|
||||||
|
2. Скрипт ищет CSV-файл с таким же именем `<код>.csv`.
|
||||||
|
3. Запрашивает **номер пакета**.
|
||||||
|
4. Обрабатывает CSV, удаляет дубли по полису, исправляет формат даты и создаёт XML.
|
||||||
|
|
||||||
|
## 🧱 Формат входного CSV
|
||||||
|
Файл `UTF-8`, разделитель `;`:
|
||||||
|
|
||||||
|
```
|
||||||
|
Фамилия;Имя;Отчество;Дата_рождения;Номер_полиса;Пол
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📤 Результат
|
||||||
|
Файл XML вида:
|
||||||
|
```
|
||||||
|
D-M<код>-F35-2026-<номер>.xml
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🪵 Логирование
|
||||||
|
Логи записываются в `app.log`.
|
||||||
|
|
||||||
|
## 🚀 Запуск
|
||||||
|
```
|
||||||
|
python poterya_kodcsv_scheta.py
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
157
poterya_kodcsv_scheta.py
Normal file
157
poterya_kodcsv_scheta.py
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from xml.dom import minidom
|
||||||
|
from dataclasses import dataclass
|
||||||
|
import os
|
||||||
|
import csv
|
||||||
|
import logging
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
logger = logging.getLogger('application')
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
fh = logging.FileHandler('app.log', encoding='utf-8')
|
||||||
|
logger.addHandler(fh)
|
||||||
|
|
||||||
|
|
||||||
|
class DNaPlanGenerator:
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class DataNode:
|
||||||
|
fam: str = ''
|
||||||
|
im: str = ''
|
||||||
|
ot: str = ''
|
||||||
|
dr: str = ''
|
||||||
|
w: str = ''
|
||||||
|
npolis: str = ''
|
||||||
|
mes: str = ''
|
||||||
|
nzap: str = ''
|
||||||
|
mcode: str = ''
|
||||||
|
|
||||||
|
def to_dict(self) -> dict:
|
||||||
|
return {
|
||||||
|
'N_ZAP': self.nzap,
|
||||||
|
'FAM': self.fam,
|
||||||
|
'IM': self.im,
|
||||||
|
'OT': self.ot,
|
||||||
|
'W': self.w,
|
||||||
|
'DR': self.dr,
|
||||||
|
'NPOLIS': self.npolis,
|
||||||
|
'MDP': '0',
|
||||||
|
'SMOCOD': '35003',
|
||||||
|
'DISP_TYP': '6',
|
||||||
|
'MES': self.mes,
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, mo_code: str, year: int, month: int):
|
||||||
|
self.mo_code = mo_code
|
||||||
|
self.year = 2026
|
||||||
|
self.month = month
|
||||||
|
self.doc = minidom.Document()
|
||||||
|
self.root = self.doc.createElement('ZL_LIST')
|
||||||
|
self.xml_name = f'D-M{self.mo_code}-F35-2026-{month}'
|
||||||
|
self.root.appendChild(self.header())
|
||||||
|
self.doc.appendChild(self.root)
|
||||||
|
|
||||||
|
def header(self):
|
||||||
|
zglv_tag = self.doc.createElement('ZGLV')
|
||||||
|
|
||||||
|
fname_tag = self.doc.createElement('FILENAME')
|
||||||
|
fname_tag.appendChild(self.doc.createTextNode(self.xml_name))
|
||||||
|
|
||||||
|
data_tag = self.doc.createElement('DATA')
|
||||||
|
data_tag.appendChild(self.doc.createTextNode(
|
||||||
|
datetime.now().strftime('%Y-%m-%d')))
|
||||||
|
|
||||||
|
mo_tag = self.doc.createElement('CODE_MO')
|
||||||
|
mo_tag.appendChild(self.doc.createTextNode(self.mo_code))
|
||||||
|
|
||||||
|
year_tag = self.doc.createElement('YEAR')
|
||||||
|
year_tag.appendChild(self.doc.createTextNode(str(self.year)))
|
||||||
|
|
||||||
|
r_tag = self.doc.createElement('R')
|
||||||
|
r_tag.appendChild(self.doc.createTextNode(str(self.month)))
|
||||||
|
|
||||||
|
for item in (fname_tag, data_tag, mo_tag, year_tag, r_tag):
|
||||||
|
zglv_tag.appendChild(item)
|
||||||
|
|
||||||
|
return zglv_tag
|
||||||
|
|
||||||
|
def fill(self, data: List[dict]):
|
||||||
|
for node_data in data:
|
||||||
|
node = self.DataNode(**node_data)
|
||||||
|
zap_tag = self.doc.createElement('ZAP')
|
||||||
|
for tag_name, tag_value in node.to_dict().items():
|
||||||
|
t = self.doc.createElement(tag_name)
|
||||||
|
t.appendChild(self.doc.createTextNode(str(tag_value)))
|
||||||
|
zap_tag.appendChild(t)
|
||||||
|
self.root.appendChild(zap_tag)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
xml_path = os.path.join(os.getcwd(), f'{self.xml_name}.xml')
|
||||||
|
with open(xml_path, 'w', encoding='cp1251') as f:
|
||||||
|
f.write(self.doc.toprettyxml(indent='\t',
|
||||||
|
encoding='windows-1251').decode('cp1251'))
|
||||||
|
logger.info(f'Файл успешно создан: {xml_path}')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
mo_code = input('Введите код МО (6 цифр, например, 352530): ').strip()
|
||||||
|
|
||||||
|
if not (mo_code.isdigit() and len(mo_code) == 6):
|
||||||
|
print('Некорректный код МО. Нужно ввести ровно 6 цифр, например 352530.')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
number_package = input('Введите порядковый номер пакета: ')
|
||||||
|
year_now = datetime.now().year
|
||||||
|
|
||||||
|
csv_filename = f"{mo_code}.csv"
|
||||||
|
csv_path = os.path.join(os.getcwd(), csv_filename)
|
||||||
|
|
||||||
|
if not os.path.exists(csv_path):
|
||||||
|
print('Файл не найден!')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
data_list = []
|
||||||
|
seen_policies = set()
|
||||||
|
mes_counter = 1
|
||||||
|
|
||||||
|
with open(csv_path, encoding='utf-8') as f:
|
||||||
|
reader = csv.reader(f, delimiter=';')
|
||||||
|
for i, row in enumerate(reader, start=1):
|
||||||
|
try:
|
||||||
|
fam, im, ot, dr, npolis, w = row[:6]
|
||||||
|
|
||||||
|
if npolis in seen_policies:
|
||||||
|
continue
|
||||||
|
seen_policies.add(npolis)
|
||||||
|
|
||||||
|
try:
|
||||||
|
dr_obj = datetime.strptime(dr, '%d.%m.%Y')
|
||||||
|
dr_iso = dr_obj.strftime('%Y-%m-%d')
|
||||||
|
except ValueError:
|
||||||
|
logger.warning(f'Ошибка формата даты в строке {i}: {dr}')
|
||||||
|
dr_iso = dr
|
||||||
|
|
||||||
|
data_list.append({
|
||||||
|
'fam': fam,
|
||||||
|
'im': im,
|
||||||
|
'ot': ot,
|
||||||
|
'dr': dr_iso,
|
||||||
|
'w': w,
|
||||||
|
'npolis': npolis,
|
||||||
|
'mes': mes_counter,
|
||||||
|
'nzap': str(i),
|
||||||
|
'mcode': mo_code
|
||||||
|
})
|
||||||
|
|
||||||
|
mes_counter += 1
|
||||||
|
if mes_counter > 12:
|
||||||
|
mes_counter = 1
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f'Ошибка в строке {i}: {e}')
|
||||||
|
|
||||||
|
generator = DNaPlanGenerator(mo_code, year_now, int(number_package))
|
||||||
|
generator.fill(data_list)
|
||||||
|
generator.save()
|
||||||
|
|
||||||
|
print('✅ XML-файл успешно создан!')
|
||||||
Reference in New Issue
Block a user