eldoc/app.py

522 lines
21 KiB
Python
Raw Normal View History

2019-10-26 21:13:07 +03:00
import gi
import os
gi.require_version('Gtk', '3.0')
2019-11-08 21:18:38 +03:00
from gi.repository import Gtk, GObject, Gdk
from mods.db import store_patient_index, update_patient_index, search_patients, db, Patient, Reception, Catalog, List
2019-11-12 19:30:17 +03:00
from mods.settings import s_get_reception_list, s_set_reception_list
2019-11-12 21:39:26 +03:00
from mods.catalogs import add_catalog, search_catalogs
2019-12-01 16:22:43 +03:00
from mods.lists import create_open_list_win
from mods.files import list_row_ui_str
2019-12-01 16:22:43 +03:00
from mods.utils import show_msg, ConditionalFilter
2019-11-12 19:30:17 +03:00
from datetime import date, datetime, timedelta
import peewee
2019-11-12 21:39:26 +03:00
import re
2019-10-26 21:13:07 +03:00
gender_dict = {
'male': 'Мужской',
'female': 'Женский'
}
doc_type_dict = {
'passport': 'Паспорт',
'birth_cert': 'Св.о рождении',
'foreign_passport': 'Паспорт иностранца'
}
# Variables
2019-10-26 21:13:07 +03:00
resource_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'res')
ui_dir = os.path.join(resource_dir, 'ui')
icon_dir = os.path.join(resource_dir, 'icons')
main_win_file = os.path.join(ui_dir, 'main_win.glade')
new_patient_win_file = os.path.join(ui_dir, 'new_patient_win.glade')
open_patient_win_file = os.path.join(ui_dir, 'open_patient_win.glade')
edit_patient_win_file = os.path.join(ui_dir, 'edit_patient_win.glade')
male_patient_row_file = os.path.join(ui_dir, 'male_patient_row.glade')
2019-11-12 19:30:17 +03:00
reception_list_settings_win_file = os.path.join(ui_dir, 'reception_list_settings.glade')
female_patient_row_file = os.path.join(ui_dir, 'female_patient_row.glade')
2019-11-12 21:39:26 +03:00
new_catalog_win_file = os.path.join(ui_dir, 'new_catalog_win.glade')
2019-11-08 21:18:38 +03:00
reception_row_file = os.path.join(ui_dir, 'reception_row.glade')
with open(reception_row_file, 'r') as f:
reception_row_ui_str = f.read()
2019-11-12 19:30:17 +03:00
catalog_row_file = os.path.join(ui_dir, 'catalog_list_row.glade')
with open(catalog_row_file, 'r') as f:
catalog_row_ui_str = f.read()
gender_ui_str = {}
with open(male_patient_row_file, 'r') as f:
gender_ui_str['male'] = f.read()
with open(female_patient_row_file, 'r') as f:
gender_ui_str['female'] = f.read()
############
builder = Gtk.Builder()
2019-11-08 21:18:38 +03:00
def get_reception_timelist(rec_date):
2019-11-12 19:30:17 +03:00
s = s_get_reception_list()
dstart = datetime(rec_date.year, rec_date.month, rec_date.day, s.day_start[0], s.day_start[1])
dend = datetime(rec_date.year, rec_date.month, rec_date.day, s.day_end[0], s.day_end[1])
2019-11-08 21:18:38 +03:00
work_day_minutes_total = (dend.hour - dstart.hour) * 60 + dend.minute - dstart.minute
2019-11-12 19:30:17 +03:00
shift_minutes_range = range(0, work_day_minutes_total, s.interval)
return [dstart + timedelta(minutes=x) for x in shift_minutes_range]
2019-11-08 21:18:38 +03:00
2019-11-12 21:39:26 +03:00
patient_filter = ConditionalFilter(search_patients)
catalog_filter = ConditionalFilter(search_catalogs)
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
2019-11-08 21:18:38 +03:00
class ReceptionRow(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 datetime(self):
return self._datetime
@datetime.setter
def datetime_setter(self, value):
self._datetime = value
@GObject.Property
def scheduled(self):
return self._scheduled
@scheduled.setter
def scheduled_setter(self, value):
self._scheduled = value
2019-11-12 19:30:17 +03:00
class CatalogRow(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
2019-11-12 21:39:26 +03:00
@GObject.Property
def name(self):
return self._name
@name.setter
def name_setter(self, value):
self._name = value
class ListRow(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 name(self):
return self._name
@name.setter
def name_setter(self, value):
self._name = value
2019-11-12 19:30:17 +03:00
class MainWinHandler:
def main_win_close(self, *args):
Gtk.main_quit()
2019-11-12 19:30:17 +03:00
def set_reception_list_today(self, *a):
cal = builder.get_object('reception_cal')
d = datetime.now()
cal.select_month(d.month - 1, d.year)
cal.select_day(d.day)
redraw_reception_list(d)
def change_reception_list_day(self, *a):
cal = builder.get_object('reception_cal')
cal_date = cal.get_date()
d = datetime(cal_date.year, cal_date.month + 1, cal_date.day)
redraw_reception_list(d)
def show_reception_list_settings_win(self, button):
reception_list_settings_win = create_reception_list_settings_win()
reception_list_settings_win.show_all()
def show_new_patient_win(self, button):
new_patient_win = create_new_patient_win()
new_patient_win.show_all()
def show_open_patient_win(self, button):
pl = builder.get_object('patient_list')
row = pl.get_selected_row()
open_patient_win = create_open_patient_win(row.props.db_id)
open_patient_win.show_all()
def show_open_list_win(self, button):
ll = builder.get_object('list_list')
row = ll.get_selected_row()
open_list_win = create_open_list_win(row.props.db_id)
open_list_win.show_all()
2019-11-12 21:39:26 +03:00
def show_new_catalog_win(self, button):
new_catalog_win = create_new_catalog_win()
new_catalog_win.show_all()
def patient_list_selected(self, *a):
button = builder.get_object('patient_open_button')
button.set_sensitive(True)
def patient_list_unselected(self, *a):
button = builder.get_object('patient_open_button')
button.set_sensitive(False)
def patient_filter_changed(self, filter_widget):
pl = builder.get_object('patient_list')
pl.unselect_all()
self.patient_list_unselected()
pl.invalidate_filter()
def list_list_selected(self, *a):
open_button = builder.get_object('list_open_button')
open_button.set_sensitive(True)
def catalog_list_selected(self, *a):
open_button = builder.get_object('catalog_open_button')
rename_button = builder.get_object('catalog_rename_button')
open_button.set_sensitive(True)
rename_button.set_sensitive(True)
def catalog_list_unselected(self, *a):
open_button = builder.get_object('catalog_open_button')
rename_button = builder.get_object('catalog_rename_button')
open_button.set_sensitive(False)
rename_button.set_sensitive(False)
2019-11-12 21:39:26 +03:00
def catalog_filter_changed(self, filter_widget):
cl = builder.get_object('catalog_list')
cl.unselect_all()
self.catalog_list_unselected()
2019-11-12 21:39:26 +03:00
cl.invalidate_filter()
def build_list_row(list_o):
b = Gtk.Builder()
b.add_from_string(list_row_ui_str)
win = b.get_object('win')
box = b.get_object('list_box')
b.get_object('name').set_text(list_o.name)
row = ListRow()
row.props.db_id = list_o.id
row.name = list_o.name
win.remove(win.get_children()[0])
row.add(box)
return row
2019-11-12 19:30:17 +03:00
def build_catalog_row(catalog):
b = Gtk.Builder()
b.add_from_string(catalog_row_ui_str)
win = b.get_object('win')
box = b.get_object('catalog_box')
b.get_object('name').set_text(catalog.name)
row = CatalogRow()
row.props.db_id = catalog.id
2019-11-12 21:39:26 +03:00
row.name = catalog.name
2019-11-12 19:30:17 +03:00
win.remove(win.get_children()[0])
row.add(box)
return row
2019-11-08 21:18:38 +03:00
def build_reception_row(reception_datetime):
b = Gtk.Builder()
b.add_from_string(reception_row_ui_str)
win = b.get_object('win')
box = b.get_object('reception_box')
b.get_object('hour').set_text(reception_datetime.strftime('%H'))
b.get_object('minute').set_text(reception_datetime.strftime('%M'))
with db.atomic():
reception = Reception.select().where(Reception.time == reception_datetime)
2019-11-08 21:18:38 +03:00
row = ReceptionRow()
if len(reception):
row.props.scheduled = True
2019-11-12 19:30:17 +03:00
row.props.db_id = reception.id
2019-11-08 21:18:38 +03:00
reception_cont = b.get_object('reception_cont')
reception_cont.props.border_width = 2
reception_cont.override_background_color(Gtk.StateFlags(0), Gdk.RGBA(red=0.5, green=0.7, blue=0.5, alpha=1.0))
reception_patient = Gtk.Label()
reception_patient.set_text(' '.join([reception.patient.last_name, reception.patient.first_name, reception.patient.middle_name]))
reception_cont.add(reception_patient)
else:
row.props.scheduled = False
win.remove(win.get_children()[0])
row.props.datetime = reception_datetime
row.add(box)
return row
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 patient_sort_func(row1, row2, *a):
text1 = row1.props.fio
text2 = row2.props.fio
return (text1 > text2) - (text1 < text2)
def patient_filter_func(row):
fstr = builder.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)
def list_sort_func(row1, row2, *a):
text1 = row1.props.name
text2 = row2.props.name
return (text1 > text2) - (text1 < text2)
2019-11-12 21:39:26 +03:00
def catalog_sort_func(row1, row2, *a):
text1 = row1.props.name
text2 = row2.props.name
return (text1 > text2) - (text1 < text2)
def catalog_filter_func(row):
fstr = builder.get_object('catalog_filter').get_text().strip()
if not fstr:
catalog_filter.reset()
return True
return row.props.db_id in catalog_filter.filter(fstr)
2019-10-26 21:13:07 +03:00
2019-11-08 21:18:38 +03:00
def redraw_reception_list(selected_date):
reception_timelist = get_reception_timelist(selected_date)
reception_list = builder.get_object('reception_list')
2019-11-12 19:30:17 +03:00
for c in reception_list.get_children():
reception_list.remove(c)
2019-11-08 21:18:38 +03:00
for d in reception_timelist:
reception_list.add(build_reception_row(d))
2019-11-12 19:30:17 +03:00
reception_list.show_all()
2019-11-08 21:18:38 +03:00
builder.add_from_file(main_win_file)
builder.connect_signals(MainWinHandler())
2019-11-08 21:18:38 +03:00
#####
redraw_reception_list(datetime.now())
#####
patient_list = builder.get_object('patient_list')
patient_list.set_sort_func(patient_sort_func)
patient_list.set_filter_func(patient_filter_func)
with db.atomic():
for p in Patient.select():
patient_list.add(build_patient_row(p))
2019-11-12 19:30:17 +03:00
#####
list_list = builder.get_object('list_list')
list_list.set_sort_func(list_sort_func)
with db.atomic():
for l in List.select():
list_list.add(build_list_row(l))
#####
2019-11-12 19:30:17 +03:00
catalog_list = builder.get_object('catalog_list')
2019-11-12 21:39:26 +03:00
catalog_list.set_sort_func(catalog_sort_func)
catalog_list.set_filter_func(catalog_filter_func)
with db.atomic():
for c in Catalog.select():
2019-11-12 19:30:17 +03:00
catalog_list.add(build_catalog_row(c))
2019-12-01 16:22:43 +03:00
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
}
2019-11-12 19:30:17 +03:00
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()
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))
2019-11-12 19:30:17 +03:00
set_patient_win_values(patient_id, b)
return w
def create_edit_patient_win(patient_id):
b = Gtk.Builder()
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')
2019-11-12 19:30:17 +03:00
set_patient_win_values(patient_id, b, edit=True)
return w
def create_new_patient_win():
b = Gtk.Builder()
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
2019-10-26 21:13:07 +03:00
2019-11-12 19:30:17 +03:00
def create_reception_list_settings_win():
b = Gtk.Builder()
class ReceptionListSettingsHandler:
def save_settings(self, *a):
start_hour = int(b.get_object('start_hour').get_value())
start_minute = int(b.get_object('start_minute').get_value())
end_hour = int(b.get_object('end_hour').get_value())
end_minute = int(b.get_object('end_minute').get_value())
interval = int(b.get_object('interval').get_value())
s_set_reception_list([start_hour, start_minute], [end_hour, end_minute], interval)
redraw_reception_list(datetime.now())
b.get_object('reception_list_settings_win').close()
b.add_from_file(reception_list_settings_win_file)
b.connect_signals(ReceptionListSettingsHandler())
s = s_get_reception_list()
b.get_object('start_hour').set_value(s.day_start[0])
b.get_object('start_minute').set_value(s.day_start[1])
b.get_object('end_hour').set_value(s.day_end[0])
b.get_object('end_minute').set_value(s.day_end[1])
b.get_object('interval').set_value(s.interval)
w = b.get_object('reception_list_settings_win')
return w
2019-11-12 21:39:26 +03:00
def create_new_catalog_win():
b = Gtk.Builder()
class NewCatalogHandler:
def save_catalog(self, *a):
catname = re.sub(r'\s+', ' ', b.get_object('catalog_name').get_text()).strip()
if not len(catname):
return show_msg('Не указано имя справочника', 'Данное поле должно быть заполнено', level='warn')
try:
catalog = add_catalog(catname)
except peewee.IntegrityError:
return show_msg('Данный справочник уже существует', 'Справочник с указанным названием уже есть с базе данных', level='warn')
2019-11-12 21:39:26 +03:00
row = build_catalog_row(catalog)
catalog_list.add(row)
catalog_list.select_row(row)
catalog_list.show_all()
b.get_object('new_catalog_window').close()
b.add_from_file(new_catalog_win_file)
b.connect_signals(NewCatalogHandler())
w = b.get_object('new_catalog_window')
return w
2019-10-26 21:13:07 +03:00
main_win = builder.get_object('main_window')
main_win.show_all()
Gtk.main()