295 lines
12 KiB
Python
295 lines
12 KiB
Python
import gi
|
||
gi.require_version('Gtk', '3.0')
|
||
from gi.repository import Gtk, GObject
|
||
import os
|
||
from mods.files import gender_ui_str, icon_dir, open_patient_win_file, new_patient_win_file, edit_patient_win_file, choose_patient_win_file
|
||
from mods.utils import ConditionalFilter, show_msg, gender_dict, doc_type_dict, enable_widget, disable_widget
|
||
from mods.db import db, Patient, PatientIndex
|
||
from mods.root import builder
|
||
from datetime import date
|
||
import re
|
||
import peewee
|
||
|
||
def store_patient_index(pat):
|
||
fio_list = [pat.last_name, pat.first_name]
|
||
if pat.middle_name:
|
||
fio_list.append(pat.middle_name)
|
||
PatientIndex.insert(
|
||
{
|
||
PatientIndex.rowid: pat.id,
|
||
PatientIndex.fio: ' '.join(fio_list)
|
||
}
|
||
).execute()
|
||
def update_patient_index(pat):
|
||
fio_list = [pat.last_name, pat.first_name]
|
||
if pat.middle_name:
|
||
fio_list.append(pat.middle_name)
|
||
PatientIndex.update(
|
||
{
|
||
PatientIndex.fio: ' '.join(fio_list)
|
||
}
|
||
).where(PatientIndex.rowid == pat.id).execute()
|
||
|
||
def search_patients(q):
|
||
q = re.sub(r'\s+', ' ', q).strip()
|
||
q = ' '.join([ f'{x}*' for x in q.split(' ')])
|
||
with db.atomic():
|
||
return (Patient.select()
|
||
.join(
|
||
PatientIndex,
|
||
on=(Patient.id == PatientIndex.rowid))
|
||
.where(PatientIndex.match(q))
|
||
.order_by(PatientIndex.bm25()))
|
||
def get_all_patients():
|
||
with db.atomic():
|
||
return Patient.select()
|
||
|
||
class PatientRow(Gtk.ListBoxRow):
|
||
@GObject.Property
|
||
def db_id(self):
|
||
return self._db_id
|
||
@db_id.setter
|
||
def db_id_setter(self, value):
|
||
self._db_id = value
|
||
@GObject.Property
|
||
def fio(self):
|
||
return self._fio
|
||
@fio.setter
|
||
def fio_setter(self, value):
|
||
self._fio = value
|
||
@GObject.Property
|
||
def birth_date(self):
|
||
return self._birth_date
|
||
@birth_date.setter
|
||
def birth_date_setter(self, value):
|
||
self._birth_date = value
|
||
|
||
def build_patient_row(patient):
|
||
b = Gtk.Builder()
|
||
b.add_from_string(gender_ui_str[patient.gender])
|
||
win = b.get_object('win')
|
||
box = b.get_object('patient_box')
|
||
icon = b.get_object('icon')
|
||
icon.set_from_file(os.path.join(icon_dir, f'{patient.gender}.png'))
|
||
fio = f'{" ".join([patient.last_name, patient.first_name, patient.middle_name])}'
|
||
b.get_object('fio').set_text(fio)
|
||
birth_date = patient.birth_date
|
||
b.get_object('birth_date').set_text(birth_date.strftime('%d.%m.%Y'))
|
||
win.remove(win.get_children()[0])
|
||
row = PatientRow()
|
||
row.props.db_id = patient.id
|
||
row.props.fio = fio
|
||
row.props.birth_date = birth_date
|
||
row.add(box)
|
||
return row
|
||
def get_patient_win_values(b):
|
||
l_name = b.get_object('last_name').get_text().replace(' ', '')
|
||
f_name = b.get_object('first_name').get_text().replace(' ', '')
|
||
m_name = b.get_object('middle_name').get_text().replace(' ', '')
|
||
if '' in (l_name, f_name):
|
||
show_msg('Не указаны имя или фамилия', 'Данные поля должны быть заполнены', level='warn')
|
||
return None
|
||
try:
|
||
birth_d = int(b.get_object('birth_day').get_text())
|
||
if birth_d < 1 or birth_d > 31:
|
||
return show_msg('Неверный день месяца', 'Укажите число в диапазоне 1-31', level='warn')
|
||
birth_m = int(b.get_object('birth_month').get_text())
|
||
if birth_m < 1 or birth_m > 12:
|
||
show_msg('Неверный номер месяца', 'Укажите число в диапазоне 1-12', level='warn')
|
||
return None
|
||
birth_y = int(b.get_object('birth_year').get_text())
|
||
except ValueError:
|
||
show_msg('Неверно указана дата рождения', 'Все поля даты должны быть заполнены', level='warn')
|
||
return None
|
||
gender = b.get_object('gender').get_active_id()
|
||
if not gender:
|
||
show_msg('Не выбран пол', level='warn')
|
||
return None
|
||
birth_date = date(birth_y, birth_m, birth_d)
|
||
doc_type = b.get_object('doc_type').get_active_id()
|
||
doc_serial = b.get_object('doc_serial').get_text()
|
||
doc_number = b.get_object('doc_number').get_text()
|
||
policy_number = b.get_object('policy_number').get_text()
|
||
policy_company = b.get_object('policy_company').get_text()
|
||
snils_number = b.get_object('snils_number').get_text()
|
||
notes_buffer = b.get_object('notes_buffer')
|
||
notes_start = notes_buffer.get_start_iter()
|
||
notes_end = notes_buffer.get_end_iter()
|
||
notes = notes_buffer.get_text(notes_start, notes_end, True)
|
||
return {
|
||
'last_name': l_name,
|
||
'first_name': f_name,
|
||
'middle_name': m_name,
|
||
'gender': gender,
|
||
'birth_date': birth_date,
|
||
'doc_type': doc_type,
|
||
'doc_serial': doc_serial,
|
||
'doc_number': doc_number,
|
||
'policy_number': policy_number,
|
||
'policy_company': policy_company,
|
||
'snils_number': snils_number,
|
||
'notes': notes
|
||
}
|
||
def set_patient_win_values(patient_id, b, edit=False):
|
||
with db.atomic():
|
||
pat = Patient.select().where(Patient.id == patient_id).get()
|
||
b.get_object('last_name').set_text(pat.last_name)
|
||
b.get_object('first_name').set_text(pat.first_name)
|
||
b.get_object('middle_name').set_text(pat.middle_name)
|
||
if not edit:
|
||
b.get_object('gender').set_text(gender_dict[pat.gender])
|
||
else:
|
||
b.get_object('gender').set_active_id(pat.gender)
|
||
if not edit:
|
||
b.get_object('birth_date').set_text(pat.birth_date.strftime('%d.%m.%Y'))
|
||
else:
|
||
b.get_object('birth_day').set_text(str(pat.birth_date.day))
|
||
b.get_object('birth_month').set_text(str(pat.birth_date.month))
|
||
b.get_object('birth_year').set_text(str(pat.birth_date.year))
|
||
if not edit:
|
||
b.get_object('doc_type').set_text(doc_type_dict[pat.doc_type] if pat.doc_type else '')
|
||
elif pat.doc_type:
|
||
b.get_object('doc_type').set_active_id(pat.doc_type)
|
||
b.get_object('doc_serial').set_text(pat.doc_serial)
|
||
b.get_object('doc_number').set_text(pat.doc_number)
|
||
b.get_object('policy_number').set_text(pat.policy_number)
|
||
b.get_object('policy_company').set_text(pat.policy_company)
|
||
b.get_object('snils_number').set_text(pat.snils_number)
|
||
b.get_object('notes_buffer').set_text(pat.notes)
|
||
|
||
def create_open_patient_win(patient_id):
|
||
b = Gtk.Builder()
|
||
patient_list = builder.get_object('patient_list')
|
||
class OpenPatientWinHandler:
|
||
def show_edit_patient_win(self, *a):
|
||
edit_patient_win = create_edit_patient_win(patient_id)
|
||
w.destroy()
|
||
edit_patient_win.show_all()
|
||
b.add_from_file(open_patient_win_file)
|
||
b.connect_signals(OpenPatientWinHandler())
|
||
w = b.get_object('open_patient_window')
|
||
# db_id = b.get_object('db_id')
|
||
# db_id.set_text(str(patient_id))
|
||
set_patient_win_values(patient_id, b)
|
||
return w
|
||
|
||
def create_edit_patient_win(patient_id):
|
||
b = Gtk.Builder()
|
||
patient_list = builder.get_object('patient_list')
|
||
class EditPatientWinHandler:
|
||
def edit_patient_win_close(self, *args):
|
||
w.destroy()
|
||
open_patient_win = create_open_patient_win(patient_id)
|
||
open_patient_win.show_all()
|
||
def only_digits(self, entry):
|
||
text = entry.get_text()
|
||
text = ''.join(filter(lambda x: x.isdigit(), text))
|
||
entry.set_text(text)
|
||
def save_patient(self, *args):
|
||
values = get_patient_win_values(b)
|
||
if not values:
|
||
return
|
||
with db.atomic():
|
||
try:
|
||
Patient.update(**values).where(Patient.id == patient_id).execute()
|
||
except peewee.IntegrityError:
|
||
return show_msg('Данный пациент уже существует', 'Другой пациент с указанными фамилией, именем\nи датой рождения уже есть с базе данных', level='warn')
|
||
patient = Patient.select().where(Patient.id == patient_id).get()
|
||
update_patient_index(patient)
|
||
cur_row = list(filter(lambda x: x.props.db_id == patient_id, patient_list.get_children()))[0]
|
||
patient_list.remove(cur_row)
|
||
row = build_patient_row(patient)
|
||
patient_list.add(row)
|
||
patient_list.select_row(row)
|
||
patient_list.show_all()
|
||
b.get_object('edit_patient_window').close()
|
||
b.add_from_file(edit_patient_win_file)
|
||
b.connect_signals(EditPatientWinHandler())
|
||
w = b.get_object('edit_patient_window')
|
||
set_patient_win_values(patient_id, b, edit=True)
|
||
return w
|
||
|
||
def create_new_patient_win():
|
||
b = Gtk.Builder()
|
||
patient_list = builder.get_object('patient_list')
|
||
class NewPatienWinHandler:
|
||
def only_digits(self, entry):
|
||
text = entry.get_text()
|
||
text = ''.join(filter(lambda x: x.isdigit(), text))
|
||
entry.set_text(text)
|
||
def save_patient(self, *args):
|
||
values = get_patient_win_values(b)
|
||
if not values:
|
||
return
|
||
with db.atomic():
|
||
try:
|
||
patient = Patient.create(**values)
|
||
except peewee.IntegrityError:
|
||
return show_msg('Данный пациент уже существует', 'Пациент с указанными фамилией, именем\nи датой рождения уже есть с базе данных', level='warn')
|
||
store_patient_index(patient)
|
||
row = build_patient_row(patient)
|
||
patient_list.add(row)
|
||
patient_list.select_row(row)
|
||
patient_list.show_all()
|
||
b.get_object('new_patient_window').close()
|
||
b.add_from_file(new_patient_win_file)
|
||
b.connect_signals(NewPatienWinHandler())
|
||
w = b.get_object('new_patient_window')
|
||
return w
|
||
|
||
def create_choose_patient_win(new_reception_b):
|
||
b = Gtk.Builder()
|
||
patient_cont = new_reception_b.get_object('patient')
|
||
save_button = new_reception_b.get_object('save_button')
|
||
patient_filter = ConditionalFilter(search_patients)
|
||
class ChoosePatientWinHandler:
|
||
def patient_filter_changed(self, filter_widget):
|
||
pl.unselect_all()
|
||
self.patient_list_unselected()
|
||
pl.invalidate_filter()
|
||
def patient_list_selected(self, *a):
|
||
enable_widget([accept_button])
|
||
def patient_list_unselected(self, *a):
|
||
disable_widget([accept_button])
|
||
def submit(self, button):
|
||
from mods.receptions import NewReceptionPatientLabel
|
||
row = pl.get_selected_row()
|
||
for c in patient_cont.get_children():
|
||
patient_cont.remove(c)
|
||
patient_label = NewReceptionPatientLabel()
|
||
patient_label.props.db_id = row.props.db_id
|
||
patient_label.set_markup(f'<span size="xx-large">{row.props.fio}</span>')
|
||
patient_cont.pack_start(patient_label, True, True, 0)
|
||
patient_cont.reorder_child(patient_label, 0)
|
||
patient_cont.show_all()
|
||
enable_widget([save_button])
|
||
w.destroy()
|
||
|
||
b.add_from_file(choose_patient_win_file)
|
||
b.connect_signals(ChoosePatientWinHandler())
|
||
accept_button = b.get_object('accept_button')
|
||
pl = b.get_object('patient_list')
|
||
pl.set_sort_func(patient_sort_func)
|
||
pl.set_filter_func(patient_filter_func_factory(patient_filter, b))
|
||
###
|
||
for p in get_all_patients():
|
||
pl.add(build_patient_row(p))
|
||
###
|
||
w = b.get_object('choose_patient_window')
|
||
return w
|
||
|
||
def patient_sort_func(row1, row2, *a):
|
||
text1 = row1.props.fio
|
||
text2 = row2.props.fio
|
||
return (text1 > text2) - (text1 < text2)
|
||
|
||
def patient_filter_func_factory(patient_filter, b):
|
||
def patient_filter_func(row):
|
||
fstr = b.get_object('patient_filter').get_text().strip()
|
||
if not fstr:
|
||
patient_filter.reset()
|
||
return True
|
||
return row.props.db_id in patient_filter.filter(fstr)
|
||
return patient_filter_func
|
||
|