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() def get_patient(patient_id): with db.atomic(): return Patient.get_by_id(patient_id) 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'{row.props.fio}') 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