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