Каждый функционал в своём модуле и начало реализации приёмов
This commit is contained in:
parent
efdf7ebf13
commit
0e13795c4b
314
app.py
314
app.py
|
@ -2,48 +2,31 @@ import gi
|
|||
import os
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GObject, Gdk
|
||||
from mods.db import store_patient_index, update_patient_index, search_patients, db, Patient, Reception, Catalog, List
|
||||
from mods.db import db, Patient, Reception, Catalog, List
|
||||
from mods.settings import s_get_reception_list, s_set_reception_list
|
||||
from mods.catalogs import add_catalog, search_catalogs
|
||||
from mods.patients import build_patient_row, patient_sort_func, patient_filter_func_factory, create_new_patient_win, create_open_patient_win
|
||||
from mods.receptions import create_new_reception_win, build_reception_row
|
||||
from mods.lists import create_open_list_win
|
||||
from mods.files import list_row_ui_str
|
||||
from mods.utils import show_msg, ConditionalFilter
|
||||
from datetime import date, datetime, timedelta
|
||||
from mods.utils import show_msg, ConditionalFilter, enable_widget, disable_widget
|
||||
from datetime import datetime, timedelta
|
||||
import peewee
|
||||
import re
|
||||
|
||||
gender_dict = {
|
||||
'male': 'Мужской',
|
||||
'female': 'Женский'
|
||||
}
|
||||
doc_type_dict = {
|
||||
'passport': 'Паспорт',
|
||||
'birth_cert': 'Св.о рождении',
|
||||
'foreign_passport': 'Паспорт иностранца'
|
||||
}
|
||||
# Variables
|
||||
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')
|
||||
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')
|
||||
|
||||
new_catalog_win_file = os.path.join(ui_dir, 'new_catalog_win.glade')
|
||||
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()
|
||||
|
||||
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()
|
||||
|
@ -56,49 +39,9 @@ def get_reception_timelist(rec_date):
|
|||
shift_minutes_range = range(0, work_day_minutes_total, s.interval)
|
||||
return [dstart + timedelta(minutes=x) for x in shift_minutes_range]
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
class CatalogRow(Gtk.ListBoxRow):
|
||||
@GObject.Property
|
||||
def db_id(self):
|
||||
|
@ -143,13 +86,16 @@ class MainWinHandler:
|
|||
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_reception_win(self, button):
|
||||
new_reception_win = create_new_reception_win(builder)
|
||||
new_reception_win.show_all()
|
||||
def show_new_patient_win(self, button):
|
||||
new_patient_win = create_new_patient_win()
|
||||
new_patient_win = create_new_patient_win(patient_list)
|
||||
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 = create_open_patient_win(row.props.db_id, patient_list)
|
||||
open_patient_win.show_all()
|
||||
def show_open_list_win(self, button):
|
||||
ll = builder.get_object('list_list')
|
||||
|
@ -159,12 +105,23 @@ class MainWinHandler:
|
|||
def show_new_catalog_win(self, button):
|
||||
new_catalog_win = create_new_catalog_win()
|
||||
new_catalog_win.show_all()
|
||||
def reception_list_selected(self, *a):
|
||||
rl = builder.get_object('reception_list')
|
||||
new_button = builder.get_object('new_reception_button')
|
||||
edit_button = builder.get_object('edit_reception_button')
|
||||
row = rl.get_selected_row()
|
||||
if row.props.scheduled:
|
||||
enable_widget([edit_button])
|
||||
disable_widget([new_button])
|
||||
else:
|
||||
enable_widget([new_button])
|
||||
disable_widget([edit_button])
|
||||
def patient_list_selected(self, *a):
|
||||
button = builder.get_object('patient_open_button')
|
||||
button.set_sensitive(True)
|
||||
enable_widget([button])
|
||||
def patient_list_unselected(self, *a):
|
||||
button = builder.get_object('patient_open_button')
|
||||
button.set_sensitive(False)
|
||||
disable_widget([button])
|
||||
def patient_filter_changed(self, filter_widget):
|
||||
pl = builder.get_object('patient_list')
|
||||
pl.unselect_all()
|
||||
|
@ -172,17 +129,15 @@ class MainWinHandler:
|
|||
pl.invalidate_filter()
|
||||
def list_list_selected(self, *a):
|
||||
open_button = builder.get_object('list_open_button')
|
||||
open_button.set_sensitive(True)
|
||||
enable_widget([open_button])
|
||||
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)
|
||||
enable_widget([open_button, rename_button])
|
||||
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)
|
||||
disable_widget([open_button, rename_button])
|
||||
def catalog_filter_changed(self, filter_widget):
|
||||
cl = builder.get_object('catalog_list')
|
||||
cl.unselect_all()
|
||||
|
@ -215,60 +170,9 @@ def build_catalog_row(catalog):
|
|||
row.add(box)
|
||||
return row
|
||||
|
||||
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)
|
||||
row = ReceptionRow()
|
||||
if len(reception):
|
||||
row.props.scheduled = True
|
||||
row.props.db_id = reception.id
|
||||
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
|
||||
|
@ -300,7 +204,7 @@ 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)
|
||||
patient_list.set_filter_func(patient_filter_func_factory(builder))
|
||||
with db.atomic():
|
||||
for p in Patient.select():
|
||||
patient_list.add(build_patient_row(p))
|
||||
|
@ -320,157 +224,7 @@ with db.atomic():
|
|||
|
||||
|
||||
|
||||
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()
|
||||
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()
|
||||
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()
|
||||
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_reception_list_settings_win():
|
||||
b = Gtk.Builder()
|
||||
|
|
31
mods/db.py
31
mods/db.py
|
@ -104,34 +104,3 @@ db.create_tables([
|
|||
ReceptionAnamnesis,
|
||||
Settings
|
||||
])
|
||||
|
||||
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 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()
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import os
|
||||
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')
|
||||
list_row_file = os.path.join(ui_dir, 'list_row.glade')
|
||||
with open(list_row_file, 'r') as f:
|
||||
list_row_ui_str = f.read()
|
||||
|
@ -12,3 +12,18 @@ with open(listrecord_row_file, 'r') as f:
|
|||
editable_row_file = os.path.join(ui_dir, 'editable_row.glade')
|
||||
with open(editable_row_file, 'r') as f:
|
||||
editable_row_ui_str = f.read()
|
||||
male_patient_row_file = os.path.join(ui_dir, 'male_patient_row.glade')
|
||||
female_patient_row_file = os.path.join(ui_dir, 'female_patient_row.glade')
|
||||
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()
|
||||
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()
|
||||
|
||||
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')
|
||||
new_reception_win_file = os.path.join(ui_dir, 'new_reception_win.glade')
|
||||
|
|
|
@ -0,0 +1,246 @@
|
|||
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
|
||||
from mods.utils import ConditionalFilter, show_msg, gender_dict, doc_type_dict
|
||||
from mods.db import db, Patient, PatientIndex
|
||||
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()))
|
||||
|
||||
patient_filter = ConditionalFilter(search_patients)
|
||||
|
||||
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, patient_list):
|
||||
b = Gtk.Builder()
|
||||
class OpenPatientWinHandler:
|
||||
def show_edit_patient_win(self, *a):
|
||||
edit_patient_win = create_edit_patient_win(patient_id, patient_list)
|
||||
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, patient_list):
|
||||
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')
|
||||
set_patient_win_values(patient_id, b, edit=True)
|
||||
return w
|
||||
|
||||
|
||||
def create_new_patient_win(patient_list):
|
||||
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
|
||||
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(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
|
|
@ -0,0 +1,60 @@
|
|||
import gi
|
||||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk, GObject, Gdk
|
||||
from mods.db import db, Reception
|
||||
from mods.files import new_reception_win_file, reception_row_ui_str
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
row = ReceptionRow()
|
||||
if len(reception):
|
||||
row.props.scheduled = True
|
||||
row.props.db_id = reception.id
|
||||
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 create_new_reception_win(root_builder):
|
||||
b = Gtk.Builder()
|
||||
class NewReceptionWinHandler:
|
||||
pass
|
||||
b.add_from_file(new_reception_win_file)
|
||||
b.connect_signals(NewReceptionWinHandler())
|
||||
w = b.get_object('new_reception_window')
|
||||
return w
|
|
@ -4,6 +4,16 @@ import gi
|
|||
gi.require_version('Gtk', '3.0')
|
||||
from gi.repository import Gtk
|
||||
|
||||
gender_dict = {
|
||||
'male': 'Мужской',
|
||||
'female': 'Женский'
|
||||
}
|
||||
doc_type_dict = {
|
||||
'passport': 'Паспорт',
|
||||
'birth_cert': 'Св.о рождении',
|
||||
'foreign_passport': 'Паспорт иностранца'
|
||||
}
|
||||
|
||||
def show_msg(text, sec_text='', level='info'):
|
||||
msg_win_file = os.path.join(ui_dir, f'{level}_win.glade')
|
||||
b = Gtk.Builder()
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkWindow" id="choose_patioent_window">
|
||||
<property name="width_request">600</property>
|
||||
<property name="height_request">500</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Выбор пациента</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="accept_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">object-select-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkViewport">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkListBox" id="patient_list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
|
@ -43,8 +43,9 @@
|
|||
<property name="can_focus">False</property>
|
||||
<property name="toolbar_style">both</property>
|
||||
<child>
|
||||
<object class="GtkToolButton">
|
||||
<object class="GtkToolButton" id="new_reception_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Создать</property>
|
||||
<property name="label" translatable="yes">Создать</property>
|
||||
|
@ -57,8 +58,9 @@
|
|||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToolButton">
|
||||
<object class="GtkToolButton" id="edit_reception_button">
|
||||
<property name="visible">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="tooltip_text" translatable="yes">Изменить</property>
|
||||
<property name="label" translatable="yes">Изменить</property>
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.1 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkWindow" id="new_reception_window">
|
||||
<property name="width_request">500</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<child type="titlebar">
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Новый приём</property>
|
||||
<property name="show_close_button">True</property>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="icon_name">document-save-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkAlignment">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="datetime">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="2"/>
|
||||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Дата и время</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<property name="label_xalign">0</property>
|
||||
<child>
|
||||
<object class="GtkAlignment">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="left_padding">12</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">5</property>
|
||||
<property name="margin_right">5</property>
|
||||
<property name="margin_top">5</property>
|
||||
<property name="margin_bottom">5</property>
|
||||
<child>
|
||||
<object class="GtkLabel" id="patient_fio">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<attributes>
|
||||
<attribute name="scale" value="2"/>
|
||||
</attributes>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
<property name="always_show_image">True</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-index</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="label">
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Пациент</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
Loading…
Reference in New Issue