diff --git a/api/cases/__init__.py b/api/cases/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/cases/helpers.py b/api/cases/helpers.py new file mode 100644 index 0000000000..58700c57e3 --- /dev/null +++ b/api/cases/helpers.py @@ -0,0 +1,45 @@ +from utils import tree_directions_case as tree_directions +from anytree import Node, RenderTree + + +def get_case_direction_tree(num_dir): + root_dir = tree_directions.root_direction(num_dir) + if not root_dir or not root_dir[-1]: + return {} + num_root_dir = root_dir[-1][-3] + result = tree_directions.get_research_by_dir(num_root_dir) + num_iss = result[0][0] + + # отсортировать по подчинениям - построить бинарное дерево + tree_dir = tree_directions.hosp_tree_direction(num_iss) + final_tree = {} + + node_dir = Node({'order': '-1', 'direction': '', 'research_title': '', 'correct_level': True, 'color': '', 'cancel': False, 'issledovaniye': '', 'parent_iss': ''}) + for j in tree_dir: + research_title = j[12] if j[12] else j[9] + temp_s = {'order': '-1', 'direction': j[0], 'research_title': research_title, 'correct_level': True, 'color': '', 'cancel': j[14], 'issledovaniye': j[5], 'parent_iss': j[3]} + if not j[3]: + final_tree[j[5]] = Node(temp_s, parent=node_dir) + else: + final_tree[j[5]] = Node(temp_s, parent=final_tree.get(j[3])) + + data_sort = [] + count_level_second = 0 + correct_level = True + for row in RenderTree(node_dir): + order = int(len(row.pre) / 4) + if order == 2: + count_level_second += 1 + if count_level_second > 1: + correct_level = False + row.node.name['correct_level'] = correct_level + row.node.name['color'] = 'red' + if not correct_level and order > 2: + row.node.name['color'] = '#d35400' + row.node.name['correct_level'] = correct_level + + row.node.name['order'] = order + data_sort.append(row.node.name) + + data_sort.pop(0) + return data_sort diff --git a/api/cases/sql_func.py b/api/cases/sql_func.py new file mode 100644 index 0000000000..e8c4ea3afe --- /dev/null +++ b/api/cases/sql_func.py @@ -0,0 +1,241 @@ +from django.db import connection + +from laboratory.settings import TIME_ZONE +from utils.db import namedtuplefetchall + + +def get_research(title_podr, vertical_result_display): + """ + Возврат: id услуги, title-услуги + + """ + + with connection.cursor() as cursor: + cursor.execute( + """WITH + t_podr AS ( + SELECT id as podr_id, title as podr_title FROM public.podrazdeleniya_podrazdeleniya), + + t_research AS ( + SELECT id as research_id, title as research_title, vertical_result_display, podrazdeleniye_id + FROM public.directory_researches) + + SELECT research_id, research_title FROM t_research + LEFT JOIN t_podr + ON t_research.podrazdeleniye_id=t_podr.podr_id + WHERE podr_title = %(title_podr)s and vertical_result_display = %(vertical)s + ORDER BY research_id + """, + params={'title_podr': title_podr, 'vertical': vertical_result_display}, + ) + + row = cursor.fetchall() + return row + + +def get_iss(list_research_id, list_dirs): + """ + Возврат: id-iss + добавить: + """ + with connection.cursor() as cursor: + cursor.execute( + """ + SELECT id, research_id FROM public.directions_issledovaniya + WHERE napravleniye_id = ANY(ARRAY[%(num_dirs)s]) AND research_id = ANY(ARRAY[%(id_researches)s]) + AND time_confirmation IS NOT NULL + """, + params={'id_researches': list_research_id, 'num_dirs': list_dirs}, + ) + row = cursor.fetchall() + return row + + +def get_distinct_research(list_research_id, list_dirs, is_text_research=False): + """ + Возврат: уникальных research + добавить: + """ + with connection.cursor() as cursor: + cursor.execute( + """WITH + t_iss AS (SELECT id, research_id FROM public.directions_issledovaniya + WHERE CASE + WHEN %(is_text_research)s = TRUE THEN + napravleniye_id = ANY(ARRAY[%(num_dirs)s]) AND time_confirmation IS NOT NULL + WHEN %(is_text_research)s = FALSE THEN + napravleniye_id = ANY(ARRAY[%(num_dirs)s]) AND research_id = ANY(ARRAY[%(id_researches)s]) AND time_confirmation IS NOT NULL + END) + + SELECT DISTINCT ON (research_id) research_id FROM t_iss + + """, + params={'id_researches': list_research_id, 'num_dirs': list_dirs, 'is_text_research': is_text_research}, + ) + row = cursor.fetchall() + return row + + +def get_distinct_fraction(list_iss): + """ + Возвращает уникальные фракци(id, title, units), которые присутствуют во всех исследованиях + """ + with connection.cursor() as cursor: + cursor.execute( + """WITH + t_fraction AS (SELECT id as id_frac, title as title_frac FROM public.directory_fractions ORDER BY id) + + SELECT DISTINCT ON (fraction_id) fraction_id, title_frac, units FROM directions_result + LEFT JOIN t_fraction ON directions_result.fraction_id = t_fraction.id_frac + WHERE issledovaniye_id = ANY(ARRAY[%(id_iss)s]) + ORDER by fraction_id + """, + params={'id_iss': list_iss}, + ) + row = cursor.fetchall() + return row + + +def get_result_fraction(list_iss): + """ + Возвращает результат: дата, фракция, значение(value) + """ + with connection.cursor() as cursor: + cursor.execute( + """WITH + t_fraction AS (SELECT id as id_frac, title as title_frac FROM public.directory_fractions ORDER BY id), + + t_iss AS (SELECT id as iss_id, napravleniye_id, to_char(time_confirmation AT TIME ZONE %(tz)s, 'DD.MM.YY') as date_confirm + FROM public.directions_issledovaniya + WHERE id = ANY(ARRAY[%(id_iss)s]) AND time_confirmation IS NOT NULL) + + SELECT fraction_id, issledovaniye_id, title_frac, value, date_confirm, napravleniye_id FROM directions_result + LEFT JOIN t_fraction ON directions_result.fraction_id = t_fraction.id_frac + LEFT JOIN t_iss ON directions_result.issledovaniye_id = t_iss.iss_id + WHERE issledovaniye_id = ANY(ARRAY[%(id_iss)s]) + ORDER by napravleniye_id, date_confirm + """, + params={'id_iss': list_iss, 'tz': TIME_ZONE}, + ) + row = cursor.fetchall() + return row + + +def get_result_text_research(research_pk, listdirs, force_all_fields=False): + with connection.cursor() as cursor: + cursor.execute( + """ + WITH + t_research AS (SELECT id as research_id, title as research_title FROM directory_researches + WHERE id = %(id_research)s), + + t_groups AS (SELECT id as group_id, title as group_title, "order" as group_order + FROM public.directory_paraclinicinputgroups + WHERE research_id = %(id_research)s), + + t_fields AS (SELECT id as field_id, title, "order" as field_order, + directory_paraclinicinputfield.group_id, group_title, group_order + FROM public.directory_paraclinicinputfield + LEFT JOIN t_groups on directory_paraclinicinputfield.group_id = t_groups.group_id + WHERE (directory_paraclinicinputfield.group_id in (SELECT group_id from t_groups) and + ( + for_extract_card = true or + (%(force_all_fields)s = true and NOT (field_type = ANY(ARRAY[16,17])))) + ) or + (directory_paraclinicinputfield.group_id in (SELECT group_id from t_groups) and title ILIKE 'Заключение')), + + t_iss AS (SELECT directions_issledovaniya.id as iss_id, time_confirmation, + to_char(time_confirmation AT TIME ZONE %(tz)s, 'DD.MM.YY') as date_confirm, + napravleniye_id, t_research.research_title, ud.fio FROM directions_issledovaniya + LEFT JOIN t_research on t_research.research_id = directions_issledovaniya.research_id + LEFT JOIN users_doctorprofile ud ON + ud.id=directions_issledovaniya.doc_confirmation_id + WHERE directions_issledovaniya.research_id=%(id_research)s and napravleniye_id = ANY(ARRAY[%(id_dirs)s]) and time_confirmation is not Null) + + SELECT research_title, date_confirm, napravleniye_id, group_title, title, "value", t_iss.iss_id, t_iss.fio, field_type FROM directions_paraclinicresult + LEFT JOIN t_iss on directions_paraclinicresult.issledovaniye_id = t_iss.iss_id + LEFT JOIN t_fields on directions_paraclinicresult.field_id = t_fields.field_id + WHERE issledovaniye_id in (SELECT iss_id from t_iss) and + directions_paraclinicresult.field_id in (SELECT field_id from t_fields) + order by time_confirmation, group_order, field_order + + """, + params={'id_research': research_pk, 'id_dirs': listdirs, 'force_all_fields': force_all_fields, 'tz': TIME_ZONE}, + ) + row = cursor.fetchall() + return row + + +def get_result_value_iss(iss_pk, research_pk, titles_field): + with connection.cursor() as cursor: + cursor.execute( + """ + WITH + t_field AS (SELECT "id", title FROM directory_paraclinicinputfield + WHERE group_id in (SELECT "id" FROM directory_paraclinicinputgroups WHERE research_id=%(id_research)s) + AND title = ANY(ARRAY[%(titles_field)s])) + + SELECT field_id, issledovaniye_id, "value", title FROM public.directions_paraclinicresult + LEFT JOIN t_field ON directions_paraclinicresult.field_id = t_field.id + where field_id in (SELECT "id" FROM t_field) and issledovaniye_id = %(id_iss)s + + + """, + params={'id_iss': iss_pk, 'id_research': research_pk, 'titles_field': titles_field}, + ) + row = cursor.fetchall() + return row + + +def get_result_temperature_list(iss_pk_list, research_pk, titles_field): + with connection.cursor() as cursor: + cursor.execute( + """ + WITH + t_field AS (SELECT "id", title FROM directory_paraclinicinputfield + WHERE group_id in (SELECT "id" FROM directory_paraclinicinputgroups WHERE research_id=%(id_research)s) + AND title = ANY(ARRAY[%(titles_field)s])) + + SELECT field_id, issledovaniye_id, "value", title FROM public.directions_paraclinicresult + LEFT JOIN t_field ON directions_paraclinicresult.field_id = t_field.id + where field_id in (SELECT "id" FROM t_field) and issledovaniye_id = ANY(ARRAY[%(id_iss)s]) + ORDER by issledovaniye_id + + + """, + params={'id_iss': iss_pk_list, 'id_research': research_pk, 'titles_field': titles_field}, + ) + row = cursor.fetchall() + return row + + +def get_assignments_by_history(history_id: int): + with connection.cursor() as cursor: + cursor.execute( + """ + SELECT public.directions_napravleniya.id as napravlenie_id, public.directions_napravleniya.data_sozdaniya, + public.users_doctorprofile.fio as who_assigned, doc_list.fio as who_confirm, public.directions_napravleniya.total_confirmed, + public.directions_issledovaniya.time_confirmation, public.directory_researches.id as research_id, public.directory_researches.title as research_title + + FROM public.directions_issledovaniya + INNER JOIN public.directions_napravleniya + ON public.directions_issledovaniya.napravleniye_id = public.directions_napravleniya.id + INNER JOIN public.directory_researches + ON public.directions_issledovaniya.research_id = public.directory_researches.id + INNER JOIN public.users_doctorprofile + ON public.directions_napravleniya.doc_id = public.users_doctorprofile.id + LEFT JOIN (SELECT id, fio FROM public.users_doctorprofile) as doc_list + ON public.directions_issledovaniya.doc_confirmation_id = doc_list.id + + WHERE public.directions_napravleniya.parent_case_id = %(history_id)s + AND (is_paraclinic = true OR is_doc_refferal = true OR is_microbiology = true OR is_citology = true OR is_gistology = true OR + (is_paraclinic = False AND is_doc_refferal = False AND is_microbiology = False AND is_citology = False AND is_gistology = False + AND is_slave_hospital = False AND is_hospital = False AND is_case = False)) + AND public.directions_napravleniya.cancel != true + + ORDER BY public.directions_napravleniya.data_sozdaniya + """, + params={"history_id": history_id}, + ) + rows = namedtuplefetchall(cursor) + return rows diff --git a/api/cases/stationar_func.py b/api/cases/stationar_func.py new file mode 100644 index 0000000000..6a0e32319e --- /dev/null +++ b/api/cases/stationar_func.py @@ -0,0 +1,529 @@ +from collections import OrderedDict +from copy import deepcopy +from typing import List + +from directions.models import Issledovaniya, Napravleniya +from directory.models import Researches +from podrazdeleniya.models import Podrazdeleniya +from utils import tree_directions_case as tree_directions +from .sql_func import ( + get_research, + get_iss, + get_distinct_research, + get_distinct_fraction, + get_result_fraction, + get_result_text_research, + get_result_temperature_list, + get_assignments_by_history, +) +from api.dicom import search_dicom_study +from utils.dates import normalize_date +from anytree import Node, RenderTree + + +def hosp_get_data_direction(main_direction, site_type=-1, type_service='None', level=-1): + # Получить данные по разделу Стационарной карты + # hosp_site_type=-1 - не получать ничего. + # level уровень подчинения. Если вернуть только дочерние для текущего направления level=2 + result = tree_directions.get_research_by_dir(main_direction) + num_iss = result[0][0] + main_research = result[0][1] + + hosp_site_type = site_type + hosp_level = level + hosp_is_paraclinic, hosp_is_doc_refferal, hosp_is_lab, hosp_is_hosp, hosp_is_all, hosp_morfology = False, False, False, False, False, False + if type_service == 'is_paraclinic': + hosp_is_paraclinic = True + elif type_service == 'is_doc_refferal': + hosp_is_doc_refferal = True + elif type_service == 'is_lab': + hosp_is_lab = True + elif type_service == 'is_morfology': + hosp_morfology = True + if site_type == -1 and type_service == 'None': + hosp_is_all = True + + hosp_dirs = tree_directions.hospital_get_direction( + num_iss, main_research, hosp_site_type, hosp_is_paraclinic, hosp_is_doc_refferal, hosp_is_lab, hosp_is_hosp, hosp_level, hosp_is_all, hosp_morfology + ) + + data = [] + if hosp_dirs: + for i in hosp_dirs: + if hosp_is_all and i[21] == 9: + continue + data.append( + { + 'direction': i[0], + 'date_create': i[1], + 'time_create': i[2], + 'iss': i[5], + 'date_confirm': i[6], + 'time_confirm': i[7], + 'research_id': i[8], + 'research_title': i[9], + 'podrazdeleniye_id': i[13], + 'is_paraclinic': i[14], + 'is_doc_refferal': i[15], + 'is_stom': i[16], + 'is_hospital': i[17], + 'is_microbiology': i[18], + 'podrazdeleniye_title': i[19], + 'site_type': i[21], + 'research_short_title': i[23], + 'is_slave_hospital': i[24], + 'is_cancel': i[25], + "is_citology": i[26], + "is_gistology": i[27], + } + ) + + return data + + +def get_direction_attrs(direction, site_type=-1, type_service='None', level=-1): + # Возврат: [{pk:№, date_create:'', confirm:'', researches:[]}, {pk:№, date_create:'', confirm:'', researches:[]}] + data = [] + + main_direction = direction + type_serv = type_service + site_type_num = site_type + level_get = level + data_direction = hosp_get_data_direction(main_direction, site_type=site_type_num, type_service=type_serv, level=level_get) + dict_temp = {} + + for dir_attr in data_direction: + num_dir = dir_attr.get('direction') + if dict_temp.get(num_dir): + dict_by_dir = dict_temp.get(num_dir) + dict_by_dir['researches'] = [*dict_by_dir['researches'], dir_attr.get('research_title')] + dict_by_dir['researches_short'] = [*dict_by_dir['researches_short'], dir_attr.get('researches_short')] + dict_temp[num_dir] = dict_by_dir.copy() + else: + type_dir = 'directions' + confirm = bool(dir_attr.get('date_confirm')) + if dir_attr.get('is_slave_hospital'): + type_dir = 'stationar' + dict_temp[num_dir] = { + 'type': type_dir, + 'date_create': dir_attr.get('date_create'), + 'confirm': confirm, + 'researches': [dir_attr.get('research_title')], + 'researches_short': [dir_attr.get('research_short_title')], + 'podrazdeleniye': dir_attr.get('podrazdeleniye_title'), + } + + for k, v in dict_temp.items(): + dict_result = { + 'type': v['type'], + 'pk': k, + 'date_create': v['date_create'], + 'confirm': v['confirm'], + 'researches': v['researches'], + 'researches_short': v['researches_short'], + 'podrazdeleniye': v['podrazdeleniye'], + } + data.append(dict_result) + + return data + + +def hosp_get_hosp_direction(num_dir): + # возвращает дерево направлений-отделений, у к-рых тип улуги только is_hosp + # [{'direction': номер направления, 'research_title': значение}, {'direction': номер направления, 'research_title': значение}] + root_dir = tree_directions.root_direction(num_dir) + if not root_dir or not root_dir[-1]: + return {} + num_root_dir = root_dir[-1][-3] + result = tree_directions.get_research_by_dir(num_root_dir) + num_iss = result[0][0] + + # отсортировать по подчинениям - построить бинарное дерево + tree_dir = tree_directions.hosp_tree_direction(num_iss) + final_tree = {} + + node_dir = Node({'order': '-1', 'direction': '', 'research_title': '', 'correct_level': True, 'color': '', 'cancel': False, 'issledovaniye': '', 'parent_iss': ''}) + for j in tree_dir: + research_title = j[12] if j[12] else j[9] + temp_s = {'order': '-1', 'direction': j[0], 'research_title': research_title, 'correct_level': True, 'color': '', 'cancel': j[14], 'issledovaniye': j[5], 'parent_iss': j[3]} + if not j[3]: + final_tree[j[5]] = Node(temp_s, parent=node_dir) + else: + final_tree[j[5]] = Node(temp_s, parent=final_tree.get(j[3])) + + data_sort = [] + count_level_second = 0 + correct_level = True + for row in RenderTree(node_dir): + order = int(len(row.pre) / 4) + if order == 2: + count_level_second += 1 + if count_level_second > 1: + correct_level = False + row.node.name['correct_level'] = correct_level + row.node.name['color'] = 'red' + if not correct_level and order > 2: + row.node.name['color'] = '#d35400' + row.node.name['correct_level'] = correct_level + + row.node.name['order'] = order + data_sort.append(row.node.name) + + data_sort.pop(0) + return data_sort + + +def hosp_get_curent_hosp_dir(current_iss): + obj_iss = Issledovaniya.objects.get(pk=current_iss) + current_dir = obj_iss.napravleniye + if obj_iss.research.is_hospital: + return current_dir.pk + if current_dir.parent: + return current_dir.parent.napravleniye_id + + +def hosp_get_lab_iss(directions): + num_lab_dirs = directions + + num_lab_dirs = list(num_lab_dirs) + if len(num_lab_dirs) == 0: + return {} + + # Получить титл подразделений типа Лаборатория + departs_obj = Podrazdeleniya.objects.filter(p_type=2).order_by('title') + departs = OrderedDict() + result = OrderedDict() + + for i in departs_obj: + departs[i.pk] = i.title + # получить research_id по лаборатории и vertical_result_display = True + vertical = {} + vertical_result = [] + result[i.title] = {'vertical': {}, 'horizontal': {}} + horizontal_result = [] + vertical_research = get_research(i.title, True) + id_research_vertical = [i[0] for i in vertical_research] + if len(id_research_vertical) > 0: + # получить уникальные research_id по направления + get_research_id = get_distinct_research(id_research_vertical, num_lab_dirs, is_text_research=False) + research_distinct = [d[0] for d in get_research_id] + if research_distinct: + for id_research_vertical in research_distinct: + # получить исследования по направлениям и соответсвующим research_id + get_iss_id = get_iss(id_research_vertical, num_lab_dirs) + iss_id_vertical = [i[0] for i in get_iss_id] + + research_fraction_vertical = get_distinct_fraction(iss_id_vertical) + fraction_title = [] + fraction_title_units = [] + for f in research_fraction_vertical: + fraction_title.append(f[1]) + title_unit = f', {f[2]}' if f[2] else '' + fraction_title_units.append(f'{f[1]}{title_unit}') + fraction_template = [''] * len(fraction_title) # заготовка для value-резульлтатов + fraction_result = get_result_fraction(iss_id_vertical) + vertical_temp_results = {} + for f in fraction_result: + key = f'{f[4]} {str(f[5])}' + if key in vertical_temp_results.keys(): + position_element = fraction_title.index(f[2]) + tmp_list = vertical_temp_results.get(key) + tmp_list_vert = deepcopy(tmp_list) + tmp_list_vert[position_element] = f[3] + vertical_temp_results[key] = tmp_list_vert + else: + vertical_temp_results[key] = fraction_template + position_element = fraction_title.index(f[2]) + tmp_list = vertical_temp_results.get(key) + tmp_list_vert = deepcopy(tmp_list) + tmp_list_vert[position_element] = f[3] + vertical_temp_results[key] = tmp_list_vert + vertical['title_research'] = Researches.objects.get(pk=id_research_vertical).title + vertical['title_fracions'] = fraction_title_units + vertical['result'] = vertical_temp_results + vertical1 = deepcopy(vertical) + vertical_result.append(vertical1) + result[i.title]['vertical'] = vertical_result + + # получить research_id по лаборатории и vertical_result_display = False + horizontal = {} + horizontal_research = get_research(i.title, False) + id_research_horizontal = [i[0] for i in horizontal_research] + if len(id_research_horizontal) > 0: + # получить исследования по направлениям и соответсвующим research_id для horizontal + get_iss_id = get_iss(id_research_horizontal, num_lab_dirs) + iss_id_horizontal = [i[0] for i in get_iss_id] + # получить уникальные фракции по исследованиям для хоризонтал fraction_title: [], units: [] + if iss_id_horizontal: + fraction_horizontal = get_distinct_fraction(iss_id_horizontal) + fraction_title = [] + fraction_title_units = [] + for f in fraction_horizontal: + fraction_title.append(f[1]) + title_unit = f', {f[2]}' if f[2] else '' + fraction_title_units.append(f'{f[1]}{title_unit}') + + fraction_template = [''] * len(fraction_title) # заготовка для value-резульлтатов + fraction_result = get_result_fraction(iss_id_horizontal) + + temp_results = {} + for f in fraction_result: + key = f'{f[4]} {str(f[5])}' + if key in temp_results.keys(): + position_element = fraction_title.index(f[2]) + tmp_list = temp_results.get(key) + tmp_list2 = deepcopy(tmp_list) + tmp_list2[position_element] = f[3] + temp_results[key] = tmp_list2 + else: + temp_results[key] = fraction_template + position_element = fraction_title.index(f[2]) + tmp_list = temp_results.get(key) + tmp_list2 = deepcopy(tmp_list) + tmp_list2[position_element] = f[3] + temp_results[key] = tmp_list2 + + horizontal['title_fracions'] = fraction_title_units + horizontal['result'] = temp_results + horizontal_result.append(horizontal) + result[i.title]['horizontal'] = horizontal_result + result_filtered = {} + for k in result: + if result[k]['horizontal'] or result[k]['vertical']: + result_filtered[k] = result[k] + return result_filtered + + +def hosp_get_text(directions): + num_paraclinic_dirs = directions + num_paraclinic_dirs = list(num_paraclinic_dirs) + + return desc_to_data(num_paraclinic_dirs, force_all_fields=True) + + +def desc_to_data(num_dirs: List[int], force_all_fields: bool = False): + # [0] - заглушка для запроса. research c id =0 не бывает + get_research_id = get_distinct_research([0], num_dirs, is_text_research=True) if num_dirs else [] + result = [] + for research_base in get_research_id: + research = research_base[0] + field_result = get_result_text_research(research, num_dirs, force_all_fields) + last_group = None + last_date = None + data_in = [] + new_date_data = {} + for i in field_result: + date = f'{i[1]} {i[2]}' + link_dicom = search_dicom_study(i[2]) if not force_all_fields else None + group = i[3] + if not i[5]: + continue + fields = {'title_field': i[4], 'value': i[5], 'field_type': i[8]} + + if date != last_date: + if new_date_data: + data_in.append(new_date_data.copy()) + + new_date_data = dict() + new_date_data['date'] = date + new_date_data['link_dicom'] = link_dicom if link_dicom else '' + new_date_data['iss_id'] = i[6] + new_date_data['docConfirm'] = i[7] + new_date_data['data'] = [{'group_title': group, 'fields': [fields.copy()]}] + last_date = date + last_group = group + continue + + if group != last_group and date == last_date: + current_data = new_date_data.get('data') + current_data.append({'group_title': group, 'fields': [fields.copy()]}) + new_date_data['data'] = current_data.copy() + last_group = group + continue + + current_data = new_date_data.get('data') + get_last_group = current_data.pop() + last_fields = get_last_group.get('fields') + last_fields.append(fields) + get_last_group['fields'] = last_fields.copy() + current_data.append(get_last_group.copy()) + new_date_data['data'] = current_data.copy() + + data_in.append(new_date_data) + + temp_result = {} + temp_result['title_research'] = Researches.objects.get(pk=research).title + temp_result['result'] = data_in + result.append(temp_result) + + return result + + +def hosp_get_text_iss(directions): + v = [] + v.extend(hosp_get_text(directions)) + return v + + +def forbidden_edit_dir(num_dir): + """ + Проверяет подтверждена ли выписка, или переводной эпикриз. И возвращает True|False - для редактирвоания протколов + """ + # (если услуга имеет тип is_doc_refferal, или is_paraclinic) и направление не имеет parent услугу типа hosp вернуть False + obj_iss = Issledovaniya.objects.filter(napravleniye_id=num_dir).first() + if obj_iss.research.is_gistology: + return False + parent = Napravleniya.objects.get(pk=num_dir).parent + if not parent and (obj_iss.research.is_doc_refferal or obj_iss.research.is_paraclinic): + return False + + if parent: + parent_is_hospital = parent.research.is_hospital + if (obj_iss.research.is_doc_refferal or obj_iss.research.is_paraclinic) and not parent_is_hospital: + return False + + hosp_nums_obj = hosp_get_hosp_direction(num_dir) + hosp_last_num = hosp_nums_obj[-1].get('direction') if hosp_nums_obj else None + if not hosp_last_num: + return False + hosp_extract = hosp_get_data_direction(hosp_last_num, site_type=7, type_service='None', level=2) + if hosp_extract and hosp_extract[0].get('date_confirm'): + return True + + # if not hosp_extract or not hosp_extract[0].get('date_confirm'): + # # Проверить подтверждение переводного эпикриза + # # Получить hosp_dir для текужего направления + # current_iss = Issledovaniya.objects.get(napravleniye_id=num_dir) + # current_dir_hosp_dir = num_dir + # if not current_iss.research.is_hospital: + # current_dir_hosp_dir = hosp_get_curent_hosp_dir(current_iss.pk) + # # получить для текущего hosp_dir эпикриз с title - перевод..... + # epicrisis_data = hosp_get_data_direction(current_dir_hosp_dir, site_type=6, type_service='None', level=2) + # if epicrisis_data: + # result_check = check_transfer_epicrisis(epicrisis_data) + # return result_check['is_transfer'] + return False + + +def check_transfer_epicrisis(data): + for i in data: + if i.get("research_title").lower().find('перевод') != -1: + if i.get('date_confirm'): + return {'is_transfer': True, 'iss': i.get('iss'), 'research_id': i.get('research_id')} + return {'is_transfer': False, 'iss': None, 'research_id': None} + + +def get_temperature_list(hosp_num_dir): + """ + :param num_dir: + :return: + { + temperature: {data: [36.6, 36.7, 37.1 итд], xtext: ['21.01.20 13:30', '21.01.20 20:00', '22.01.20 12:10' итд],}, + systolic: {data[], xtext :[]}, diastolic: {data[], xtext :[]}, + pulse: {data[], xtext :[]} + } + """ + # tl - temperature list + tl_objs = hosp_get_data_direction(hosp_num_dir, site_type=9, type_service='None', level=2) + tl_iss = [i['iss'] for i in tl_objs] + research_id = None + for i in tl_objs: + research_id = i['research_id'] + break + if research_id is None: + return {} + final_data = {} + title_list = ['Температура', 'Пульс (уд/м)', 'Дата измерения', 'Время измерения', 'Систолическое давление (мм рт.с)', 'Диастолическое давление (мм рт.с)'] + a = get_result_temperature_list(tl_iss, research_id, title_list) + data = {} + for i in a: + value = i[2] + field = i[3] + if field.lower().find('дата') != -1: + value = normalize_date(value) + in_data = {field: value} + key = i[1] + if not data.get(key): + data.update({key: {}}) + t_data = data.get(key) + t_data.update(in_data) + data[key] = t_data + + for k, v in data.items(): + date_time = get_date_time_tl(v) + for title, value in v.items(): + if not value or value == '0': + continue + if not final_data.get(title): + final_data[title] = {'data': [], 'xtext': []} + t_final_data = final_data.get(title) + t_data = t_final_data['data'] + t_data.append(value) + t_xtext = t_final_data['xtext'] + t_xtext.append(date_time) + final_data[title] = {'data': t_data, 'xtext': t_xtext} + final_data.pop('Дата измерения', None) + final_data.pop('Время измерения', None) + for k, v in final_data.items(): + if 'температура' in k.lower() or 'давление' in k.lower() or 'пульс' in k.lower(): + number_data = list(map(force_to_number, v['data'])) + v['data'] = number_data + v['min_max'] = [min(number_data), max(number_data)] + final_data[k] = v + if 'Температура' in final_data: + final_data['Температура (°C)'] = final_data.pop('Температура') + return final_data + + +def get_date_time_tl(dict_data): + import re + + time = dict_data.get('Время измерения', 'Нет поля "Время измерения"') + date = dict_data.get('Дата измерения', 'Нет поля "Дата измерения"') + date = re.sub(r'.\d{4}', '', date) + return f'{date} {time}' + + +def force_to_number(val): + return float(''.join(c for c in val if c.isdigit() or c == '.') or 0) + + +def get_assignments(direction_id: int): + if direction_id is None: + return [] + results = [] + issledovanie_id = Issledovaniya.objects.get(napravleniye_id=direction_id).pk + assignments = get_assignments_by_history(issledovanie_id) + prev_directions_id = -1 + for i in assignments: + if prev_directions_id != i.napravlenie_id: + who_assigned = i.who_assigned.split(" ") + family_assigned = who_assigned[0] + name_assigned = who_assigned[1][0] + patronymic_assigned = "" + if len(who_assigned) > 2: + patronymic_assigned = who_assigned[2][0] + tmp_res = { + "direction_id": i.napravlenie_id, + "research_id": [i.research_id], + "research_title": [f"{i.research_title}; "], + "create_date": i.data_sozdaniya.strftime("%d.%m.%Y"), + "who_assigned": f"{family_assigned} {name_assigned}.{patronymic_assigned}.", + "time_confirmation": "", + "who_confirm": "", + } + if i.total_confirmed: + who_confirm = i.who_confirm.split(" ") + family_confirm = who_confirm[0] + name_confirm = who_confirm[1][0] + patronymic_confirm = "" + if len(who_confirm) > 2: + patronymic_confirm = who_confirm[2][0] + tmp_res["time_confirmation"] = i.time_confirmation.strftime("%d.%m.%Y %H:%M") + tmp_res["who_confirm"] = f"{family_confirm} {name_confirm}.{patronymic_confirm}." + results.append(tmp_res) + else: + results[-1]["research_id"].append(i.research_id) + results[-1]["research_title"].append(f"{i.research_title}; ") + prev_directions_id = i.napravlenie_id + return results diff --git a/api/cases/urls.py b/api/cases/urls.py new file mode 100644 index 0000000000..7767b1b9e9 --- /dev/null +++ b/api/cases/urls.py @@ -0,0 +1,11 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path('search', views.search), + path('hosp-services-by-type', views.hosp_services_by_type), + path('make-service', views.make_service), + path('directions-by-key', views.directions_by_key), + path('aggregate', views.aggregate), +] diff --git a/api/cases/views.py b/api/cases/views.py new file mode 100644 index 0000000000..cdb7d1ff48 --- /dev/null +++ b/api/cases/views.py @@ -0,0 +1,279 @@ +import simplejson as json +from django.contrib.auth.decorators import login_required +from django.http import JsonResponse + +from api.cases.helpers import get_case_direction_tree +from api.cases.stationar_func import ( + hosp_get_lab_iss, + hosp_get_text_iss, +) +from clients.models import Card +from directions.models import Issledovaniya, Napravleniya +from directory.models import HospitalService +from laboratory.decorators import group_required +from appconf.manager import SettingManager +from django.db.models import Q + +from laboratory.utils import strfdatetime +from pharmacotherapy.models import ProcedureList + + +@login_required +@group_required('Врач параклиники', 'Врач консультаций') +def search(request): + data = json.loads(request.body) + pk = int(data["q"]) + if pk >= 4600000000000: + pk -= 4600000000000 + pk //= 10 + result = {"ok": False, "message": "Не найдено", "data": {}} + original_direction = None + original_view = None + need_to_open_original = False + + for i in Issledovaniya.objects.filter(napravleniye__pk=pk, research__is_case=False): + direction: Napravleniya = i.napravleniye + if direction.parent_case: + if direction.parent_case.napravleniye_id: + if i.research.is_doc_refferal: + original_view = 'consultation' + elif i.research.is_paraclinic: + original_view = 'paraclinical' + elif i.research.podrazdeleniye and i.research.podrazdeleniye.p_type == 2: + original_view = 'laboratory' + elif i.research.is_microbiology: + original_view = 'morfology' + elif i.research.is_citology: + original_view = 'morfology' + elif i.research.is_gistology: + original_view = 'morfology' + if original_view: + original_direction = pk + need_to_open_original = True + pk = direction.parent_case.napravleniye_id + break + + tree_direction = get_case_direction_tree(pk) + i: Issledovaniya + for i in Issledovaniya.objects.filter(napravleniye__pk=pk, research__is_case=True): + direction: Napravleniya = i.napravleniye + card: Card = direction.client + result["ok"] = True + result["message"] = "" + if direction.cancel: + result["message"] = "Направление было отменено" + forbidden_edit = False # make true for closed case + child_issledovaniye, child_research_title, child_direction = '', '', '' + for iss in tree_direction: + if i.pk == iss['parent_iss']: + child_issledovaniye = iss['issledovaniye'] + iss_obj = Issledovaniya.objects.filter(pk=child_issledovaniye).first() + if iss_obj: + child_direction = iss_obj.napravleniye.pk + child_research_title = iss_obj.research.title + if not original_view: + if iss_obj.research.is_doc_refferal: + original_view = 'consultation' + elif iss_obj.research.is_paraclinic: + original_view = 'paraclinical' + elif iss_obj.research.podrazdeleniye and iss_obj.research.podrazdeleniye.p_type == 2: + original_view = 'laboratory' + elif iss_obj.research.is_microbiology: + original_view = 'morfology' + elif iss_obj.research.is_citology: + original_view = 'morfology' + elif iss_obj.research.is_gistology: + original_view = 'morfology' + break + + if not child_research_title or child_research_title == '-1': + first_child: Napravleniya = Napravleniya.objects.filter(parent_case=i).order_by('id').first() + if first_child: + child_direction = first_child.pk + iss: Issledovaniya = first_child.issledovaniya_set.first() + if iss: + child_issledovaniye = iss.pk + child_research_title = iss.research.title + + result["data"] = { + "direction": direction.pk, + "cancel": direction.cancel, + "fin_pk": direction.istochnik_f_id, + "iss": i.pk, + "parentIssledovaniye": direction.parent.pk if direction.parent else '-1', + "caseTitle": i.research.title, + "childResearch": None, + "forbiddenToEdit": forbidden_edit, + "originalDirection": { + 'id': original_direction or child_direction, + 'view': original_view, + 'open': need_to_open_original, + }, + "patient": { + "fioWithAge": card.individual.fio(full=True), + "card": card.number_with_type(), + "base": card.base_id, + "cardPk": card.pk, + "individualPk": card.individual_id, + }, + "tree": list( + map( + lambda dirc: { + **dirc, + "research_title": dirc["research_title"], + "isCurrent": int(dirc["direction"]) == pk, + "cancel": Napravleniya.objects.get(pk=dirc["direction"]).cancel, + "correct_level": dirc["correct_level"], + "color": dirc["color"], + "issledovaniye": dirc["issledovaniye"], + "order": dirc["order"], + }, + tree_direction, + ) + ), + "counts": { + 'laboratory': 0, + 'paraclinical': 0, + 'consultation': 0, + 'morfology': 0, + 'pharmacotherapy': 0, + 'all': 0, + }, + } + + if child_issledovaniye and child_direction and child_research_title: + result['data']['childResearch'] = { + "issledovaniye": child_issledovaniye, + "direction": child_direction, + "title": child_research_title, + } + + for i in Issledovaniya.objects.filter(napravleniye__pk=pk, research__is_case=True).distinct(): + result['data']['counts']["laboratory"] += Napravleniya.objects.filter(parent_case=i, issledovaniya__research__podrazdeleniye__p_type=2).distinct().count() + result['data']['counts']["paraclinical"] += Napravleniya.objects.filter(parent_case=i, issledovaniya__research__is_paraclinic=True).distinct().count() + result['data']['counts']["consultation"] += Napravleniya.objects.filter(parent_case=i, issledovaniya__research__is_doc_refferal=True).distinct().count() + result['data']['counts']["morfology"] += ( + Napravleniya.objects.filter(parent_case=i) + .filter(Q(issledovaniya__research__is_microbiology=True) | Q(issledovaniya__research__is_citology=True) | Q(issledovaniya__research__is_gistology=True)) + .distinct() + .count() + ) + result['data']['counts']["pharmacotherapy"] = ProcedureList.objects.filter(history=i.napravleniye, cancel=False, diary__issledovaniya__time_confirmation__isnull=False).count() + result['data']['counts']["all"] += Napravleniya.objects.filter(parent_case=i).count() + break + return JsonResponse(result) + + +@login_required +@group_required('Врач параклиники', 'Врач консультаций') +def hosp_services_by_type(request): + data = json.loads(request.body) + base_direction_pk = int(data["direction"] or 0) + r_type = data["r_type"] + result = [] + type_by_key = HospitalService.TYPES_BY_KEYS.get(r_type, -1) + for i in Issledovaniya.objects.filter(napravleniye__pk=base_direction_pk, research__is_case=True): + hosp_research = i.research + if int(data['hospResearch']) > -1: + hosp_research = int(data['hospResearch']) + for hs in HospitalService.objects.filter(site_type=type_by_key, main_research=hosp_research, hide=False): + result.append( + { + "pk": hs.pk, + "title": hs.slave_research.title, + "short_title": hs.slave_research.short_title, + "main_title": hs.main_research.title, + } + ) + return JsonResponse({"data": result}) + + +@login_required +@group_required('Врач параклиники', 'Врач консультаций') +def make_service(request): + data = json.loads(request.body) + main_direction = Napravleniya.objects.get(pk=data["main_direction"]) + parent_iss = Issledovaniya.objects.filter(napravleniye=main_direction, research__is_case=True).first() + service = HospitalService.objects.get(pk=data["service"]) + TADP = SettingManager.get("tadp", default='Температура', default_type='s') + if "Врач стационара" not in [str(x) for x in request.user.groups.all()] and TADP not in service.slave_research.title: + return JsonResponse({"pk": None}) + result = Napravleniya.gen_napravleniya_by_issledovaniya( + main_direction.client_id, + "", + None, + "", + None, + request.user.doctorprofile, + {-1: [service.slave_research_id]}, + {}, + False, + {}, + vich_code="", + count=1, + discount=0, + parent_iss=parent_iss.pk, + rmis_slot=None, + ) + pk = result["list_id"][0] + return JsonResponse({"pk": pk}) + + +@login_required +def directions_by_key(request): + data = json.loads(request.body) + pk = data["caseId"] + view = data["view"] + directions = Napravleniya.objects.filter(parent_case__napravleniye_id=pk) + + if view == 'laboratory': + directions = directions.filter(issledovaniya__research__podrazdeleniye__p_type=2) + elif view == 'morfology': + directions = directions.filter(Q(issledovaniya__research__is_microbiology=True) | Q(issledovaniya__research__is_citology=True) | Q(issledovaniya__research__is_gistology=True)) + elif view == 'paraclinical': + directions = directions.filter(issledovaniya__research__is_paraclinic=True) + elif view == 'consultation': + directions = directions.filter(issledovaniya__research__is_doc_refferal=True) + + directions = directions.distinct().order_by('id') + + return JsonResponse( + { + 'rows': [ + { + 'pk': x.pk, + 'confirm': x.total_confirmed, + 'date_create': strfdatetime(x.data_sozdaniya_local, "%d.%m.%Y"), + 'researches_short': [y.short_title for y in x.services], + 'researches': [y.title for y in x.services], + 'showResults': x.issledovaniya_set.all().filter(research__podrazdeleniye__p_type=2).exists(), + } + for x in directions + ] + } + ) + + +@login_required +def aggregate(request): + data = json.loads(request.body) + pk = data.get('caseDirection', -1) + view = data["view"] + directions = Napravleniya.objects.filter(parent_case__napravleniye_id=pk) + + if view == 'laboratory': + directions = directions.filter(issledovaniya__research__podrazdeleniye__p_type=2) + elif view == 'morfology': + directions = directions.filter(Q(issledovaniya__research__is_microbiology=True) | Q(issledovaniya__research__is_citology=True) | Q(issledovaniya__research__is_gistology=True)) + elif view == 'paraclinical': + directions = directions.filter(issledovaniya__research__is_paraclinic=True) + elif view == 'consultation': + directions = directions.filter(issledovaniya__research__is_doc_refferal=True) + + directions = directions.distinct().order_by('id') + + if view == 'laboratory': + result = hosp_get_lab_iss([x.pk for x in directions]) + else: + result = hosp_get_text_iss([x.pk for x in directions]) + return JsonResponse(result, safe=False) diff --git a/api/directions/sql_func.py b/api/directions/sql_func.py index 92ec4848fd..6c09ce96b1 100644 --- a/api/directions/sql_func.py +++ b/api/directions/sql_func.py @@ -21,6 +21,7 @@ def get_history_dir(d_s, d_e, card_id, who_create_dir, services, is_serv, iss_pk directory_researches.is_paraclinic, directory_researches.is_form, directory_researches.is_microbiology, + directory_researches.is_case, directory_researches.podrazdeleniye_id, directions_napravleniya.parent_id as dir_parent_id, directions_napravleniya.data_sozdaniya as dir_data_sozdaniya, @@ -106,7 +107,8 @@ def get_history_dir(d_s, d_e, card_id, who_create_dir, services, is_serv, iss_pk ud.patronymic, directions_napravleniya.visit_date, directions_napravleniya.time_microbiology_receive, - directions_napravleniya.time_gistology_receive + directions_napravleniya.time_gistology_receive, + is_case FROM t_iss_tubes LEFT JOIN t_recive ON t_iss_tubes.tubesregistration_id = t_recive.id_t_recive @@ -505,3 +507,27 @@ def get_directions_meta_info(directions): ) rows = namedtuplefetchall(cursor) return rows + + +def get_patient_open_case_data(card_pk, start_date, end_date): + with connection.cursor() as cursor: + cursor.execute( + """ + SELECT + directions_issledovaniya.id as iss_id, + directions_issledovaniya.napravleniye_id, + directions_issledovaniya.research_id, + dr.title, + dr.is_case, + to_char(dn.data_sozdaniya AT TIME ZONE %(tz)s, 'DD.MM.YYYY') as date_create + FROM directions_issledovaniya + LEFT JOIN directory_researches dr on directions_issledovaniya.research_id = dr.id + LEFT JOIN directions_napravleniya dn on directions_issledovaniya.napravleniye_id = dn.id + WHERE dn.client_id = %(card_pk)s and dr.is_case = true and directions_issledovaniya.time_confirmation is Null and + dn.data_sozdaniya AT TIME ZONE %(tz)s BETWEEN %(d_start)s AND %(d_end)s + ORDER BY directions_issledovaniya.napravleniye_id + """, + params={'card_pk': card_pk, 'tz': TIME_ZONE, 'd_start': start_date, 'd_end': end_date}, + ) + rows = namedtuplefetchall(cursor) + return rows diff --git a/api/directions/urls.py b/api/directions/urls.py index 4a686f7b53..9e7adcb8eb 100644 --- a/api/directions/urls.py +++ b/api/directions/urls.py @@ -64,4 +64,5 @@ path('meta-info', views.meta_info), path('resend-results', views.resend_results), path('need-order-redirection', views.need_order_redirection), + path('patient-open-case', views.patient_open_case), ] diff --git a/api/directions/views.py b/api/directions/views.py index dc2792893d..4cec30e353 100644 --- a/api/directions/views.py +++ b/api/directions/views.py @@ -93,6 +93,7 @@ get_directions_by_user, get_confirm_direction_by_hospital, get_directions_meta_info, + get_patient_open_case_data, ) from api.stationar.stationar_func import hosp_get_hosp_direction, hosp_get_text_iss from forms.forms_func import hosp_get_operation_data @@ -109,7 +110,6 @@ def directions_generate(request): if request.method == "POST": p = json.loads(request.body) card_pk = p.get("card_pk") - card = None if card_pk == -1: hospital: Hospitals = request.user.doctorprofile.get_hospital() if hospital.client: @@ -165,6 +165,8 @@ def directions_generate(request): hospital_department_override=p.get("hospital_department_override", -1), hospital_override=p.get("hospital_override", -1), price_category=p.get("priceCategory", -1), + case_id=p.get("caseId", -2), + case_by_direction=p.get("caseByDirection", -2), ) for _ in range(p.get("directions_count", 1)): rc = Napravleniya.gen_napravleniya_by_issledovaniya(*args, **kwargs) @@ -310,7 +312,7 @@ def directions_history(request): # status: 4 - выписано пользователем, 0 - только выписанные, 1 - Материал получен лабораторией. 2 - результат подтвержден, 3 - направления пациента, -1 - отменено, if req_status == 4: user_creater = request.user.doctorprofile.pk - if req_status in [0, 1, 2, 3, 5]: + if req_status in [0, 1, 2, 3, 5, 7]: patient_card = pk if req_status == 5: @@ -436,6 +438,7 @@ def directions_history(request): # is_slave_hospital, is_treatment, is_stom, is_doc_refferal, is_paraclinic, is_microbiology, parent_id, study_instance_uid, parent_slave_hosp_id, tube_number researches_pks = [] researches_titles = '' + child_researches_titles = '' last_dir, dir, status, date, cancel, pacs, has_hosp, has_descriptive = None, None, None, None, None, None, None, None maybe_onco, is_application, is_expertise, expertise_status, can_has_pacs = False, False, False, False, False @@ -459,6 +462,10 @@ def directions_history(request): continue elif type_service == 'is_lab' and (i[11] or i[14] or i[15] or i[16] or i[17] or i[18] or i[19]): continue + elif req_status == 7 and not i[36]: + continue + elif i[36] and req_status != 7: + continue if i[0] != last_dir: status = min(status_set) if len(lab) > 0: @@ -470,12 +477,12 @@ def directions_history(request): if aux_researches_obj.exists(): aux_researches = [{"pk": i.aux_research.pk, "title": i.aux_research.title} for i in aux_researches_obj] has_aux = True - if (req_status == 2 and status == 2) or (req_status in [3, 4] and status != -2) or (req_status == 1 and status == 1) or (req_status == 0 and status == 0): + if (req_status == 2 and status == 2) or (req_status in [3, 4, 7] and status != -2) or (req_status == 1 and status == 1) or (req_status == 0 and status == 0): final_result.append( { 'pk': dir, 'status': status, - 'researches': researches_titles, + 'researches': f"{researches_titles} {child_researches_titles}", "researches_pks": researches_pks, "aux_researches": aux_researches, "has_aux": has_aux, @@ -498,6 +505,7 @@ def directions_history(request): 'register_number': register_number, } ) + child_researches_titles = "" person_contract_pk = -1 person_contract_dirs = "" planed_doctor = "" @@ -533,11 +541,27 @@ def directions_history(request): has_hosp = True lab = set() + if i[36] and req_status == 7: + case_child_direction = Napravleniya.objects.values_list("pk", flat=True).filter(parent_case__id=i[2]) + case_childs = Issledovaniya.objects.filter(napravleniye_id__in=case_child_direction) + step = 0 + for csh in case_childs: + ch_title = csh.research.short_title if csh.research.short_title else csh.research.title + if step != 0: + child_researches_titles = f"{child_researches_titles}; {ch_title}" + else: + child_researches_titles = f"{ch_title}" + step += 1 + if researches_titles: researches_titles = f'{researches_titles} | {i[5]}' + elif child_researches_titles: + researches_titles = f'{child_researches_titles} - {i[5]}' else: researches_titles = i[5] + child_researches_titles = "" + status_val = 0 has_descriptive = False if i[8] or i[9] or i[33] or i[34] or i[35]: @@ -581,12 +605,12 @@ def directions_history(request): if aux_researches_obj.exists(): aux_researches = [{"pk": i.aux_research.pk, "title": i.aux_research.title} for i in aux_researches_obj] has_aux = True - if (req_status == 2 and status == 2) or (req_status in [3, 4] and status != -2) or (req_status == 1 and status == 1) or (req_status == 0 and status == 0): + if (req_status == 2 and status == 2) or (req_status in [3, 4, 7] and status != -2) or (req_status == 1 and status == 1) or (req_status == 0 and status == 0): final_result.append( { 'pk': dir, 'status': status, - 'researches': researches_titles, + 'researches': f"{researches_titles} {child_researches_titles}", "researches_pks": researches_pks, "aux_researches": aux_researches, "has_aux": has_aux, @@ -1442,6 +1466,7 @@ def directions_paraclinic_form(request): | Q(research__is_monitoring=True) | Q(research__is_expertise=True) | Q(research__is_aux=True) + | Q(research__is_case=True) ) ) .select_related('research', 'research__microbiology_tube', 'research__podrazdeleniye') @@ -4424,3 +4449,27 @@ def meta_info(request): index_num = res_direction.index(i['direction']) sort_result[index_num] = i return JsonResponse({"rows": sort_result}) + + +@login_required +def patient_open_case(request): + request_data = json.loads(request.body) + card_pk = request_data.get("card_pk", None) + data_case = [] + date_start = datetime.now() - timedelta(days=60) + date_end = datetime.now() + + if card_pk: + open_case = get_patient_open_case_data(card_pk, date_start, date_end) + data_case = [] + for o_case in open_case: + n = Napravleniya.objects.filter(parent_case_id=o_case.iss_id).first() + iss = Issledovaniya.objects.filter(napravleniye=n).first() + if iss: + title = iss.research.short_title if iss.research.short_title else iss.research.title + else: + title = "Случай пустой" + data_case.append({"id": o_case.iss_id, "label": f"{title} от {o_case.date_create}"}) + + data = {"data": data_case} + return JsonResponse(data) diff --git a/api/parse_file/views.py b/api/parse_file/views.py index 1db48f9fda..66e833fde4 100644 --- a/api/parse_file/views.py +++ b/api/parse_file/views.py @@ -207,7 +207,7 @@ def gen_commercial_offer(request): born_data = cells[born].split(" ")[0] age = -1 if born_data != "None": - age = age_for_year(born_data) + age = age_for_year(normalize_dots_date(born_data)) if "м" in cells[sex]: adds_harmfull = CONTROL_AGE_MEDEXAM.get("м") else: diff --git a/api/patients/views.py b/api/patients/views.py index 374cf1176c..eb6b8148c5 100644 --- a/api/patients/views.py +++ b/api/patients/views.py @@ -1533,7 +1533,7 @@ def load_anamnesis(request): request_data = json.loads(request.body) card = Card.objects.get(pk=request_data["card_pk"]) history = [] - for a in AnamnesisHistory.objects.filter(card=card).order_by('-pk'): + for a in AnamnesisHistory.objects.filter(card=card).order_by('-pk') if not request_data.get('skipHistory') else []: history.append( { "pk": a.pk, @@ -1549,6 +1549,9 @@ def load_anamnesis(request): "text": card.anamnesis_of_life, "history": history, } + if request_data.get('withPatient'): + data['patient'] = card.get_fio_w_card() + return JsonResponse(data) diff --git a/api/researches/views.py b/api/researches/views.py index 89498f7d83..48c86a7b2e 100644 --- a/api/researches/views.py +++ b/api/researches/views.py @@ -177,6 +177,7 @@ def get_researches(request, last_used=False): "treatment": r.is_treatment, "is_hospital": r.is_hospital, "is_form": r.is_form, + "is_case": r.is_case, "is_application": r.is_application, "stom": r.is_stom, "need_vich_code": r.need_vich_code, @@ -257,7 +258,6 @@ def get_researches(request, last_used=False): result = {"researches": deps, "cnts": cnts} else: result = json.loads(result) - if hasattr(request, 'plain_response') and request.plain_response: return result return JsonResponse(result) @@ -361,6 +361,8 @@ def researches_by_department(request): q = DResearches.objects.filter(is_monitoring=True).order_by("title") elif department_pk == -13: q = DResearches.objects.filter(is_expertise=True).order_by("title") + elif department_pk == -14: + q = DResearches.objects.filter(is_case=True).order_by("title") else: q = DResearches.objects.filter(podrazdeleniye__pk=department_pk).order_by("title") @@ -455,7 +457,7 @@ def researches_update(request): if tube == -1: tube = None stationar_slave = is_simple and -500 >= department_pk > -600 and main_service_pk != 1 - desc = stationar_slave or department_pk in [-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13] + desc = stationar_slave or department_pk in [-2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -16] if len(title) > 0 and (desc or Podrazdeleniya.objects.filter(pk=department_pk).exists()): department = None if desc else Podrazdeleniya.objects.filter(pk=department_pk)[0] res = None @@ -484,6 +486,7 @@ def researches_update(request): is_application=department_pk == -11, is_monitoring=department_pk == -12, is_expertise=department_pk == -13, + is_case=department_pk == -14, is_slave_hospital=stationar_slave, microbiology_tube_id=tube if department_pk == -6 else None, site_type_id=site_type, @@ -527,6 +530,7 @@ def researches_update(request): res.is_application = department_pk == -11 res.is_monitoring = department_pk == -12 res.is_expertise = department_pk == -13 + res.is_case = department_pk == -14 res.microbiology_tube_id = tube if department_pk == -6 else None res.paraclinic_info = info res.hide = hide diff --git a/api/urls.py b/api/urls.py index 6f362b41ee..d9b4676aa8 100644 --- a/api/urls.py +++ b/api/urls.py @@ -101,6 +101,7 @@ path('transfer-document/', include('api.transfer_document.urls')), path('edit-forms/', include('api.edit_forms.urls')), path('hospitals/', include('api.hospitals.urls')), + path('cases/', include('api.cases.urls')), path('get-prices', views.get_prices), path('get-price-data', views.get_price_data), path('update-price', views.update_price), diff --git a/api/views.py b/api/views.py index 14e0e05ede..3f94593953 100644 --- a/api/views.py +++ b/api/views.py @@ -513,7 +513,7 @@ def departments(request): data = { "departments": deps, "can_edit": can_edit, - "types": [*[{"pk": str(x[0]), "title": x[1]} for x in Podrazdeleniya.TYPES if x[0] not in [8, 12] and en.get(x[0], True)], *more_types], + "types": [*[{"pk": str(x[0]), "title": x[1]} for x in Podrazdeleniya.TYPES if x[0] not in [8, 12, 16] and en.get(x[0], True)], *more_types], } if hasattr(request, 'plain_response') and request.plain_response: return data @@ -748,6 +748,7 @@ def fill_settings(): ret["extended_departments"][Podrazdeleniya.MORFOLOGY].append( {"pk": Podrazdeleniya.MORFOLOGY + 3, "title": "Гистология", "type": Podrazdeleniya.MORFOLOGY, "extended": True, "e": Podrazdeleniya.MORFOLOGY} ) + try: connections.close_all() except Exception as e: @@ -784,7 +785,7 @@ def directive_from(request): data = [] hospital = request.user.doctorprofile.hospital for dep in ( - Podrazdeleniya.objects.filter(p_type__in=(Podrazdeleniya.DEPARTMENT, Podrazdeleniya.HOSP, Podrazdeleniya.PARACLINIC), hospital__in=(hospital, None)) + Podrazdeleniya.objects.filter(p_type__in=(Podrazdeleniya.DEPARTMENT, Podrazdeleniya.HOSP, Podrazdeleniya.PARACLINIC, Podrazdeleniya.CASE), hospital__in=(hospital, None)) .prefetch_related( Prefetch( 'doctorprofile_set', @@ -2657,7 +2658,7 @@ def update_price(request): current_price.title = request_data["title"] current_price.date_start = request_data["start"] current_price.date_end = request_data["end"] - if request_data.get("typePrice") == "Профосмотр": + if request_data.get("typePrice") == "Заказчик" or request_data.get("typePrice") == "Работодатель": current_price.company_id = request_data["company"] else: hospital = Hospitals.objects.filter(pk=int(request_data["company"])).first() diff --git a/appconf/manager.py b/appconf/manager.py index c8a7484bd1..e75d69a538 100644 --- a/appconf/manager.py +++ b/appconf/manager.py @@ -168,6 +168,8 @@ def l2_modules() -> dict: "price_customer", "price_externel_performer", "ftp", + "case", + "hide_show_count_param", ] }, "consults_module": SettingManager.get("consults_module", default='false', default_type='b'), @@ -214,6 +216,7 @@ def en(): 12: SettingManager.get("directions_params", default='false', default_type='b'), 13: SettingManager.l2("applications"), 14: SettingManager.l2("monitorings"), + 16: SettingManager.l2("case"), } cache.set(k, simplejson.dumps(result), 60 * 60 * 8) diff --git a/context_processors/utils.py b/context_processors/utils.py index 01ecfb2789..fadd87f06c 100644 --- a/context_processors/utils.py +++ b/context_processors/utils.py @@ -29,7 +29,7 @@ def menu(request): if request.user.is_authenticated and request.headers.get('X-Requested-With') != 'XMLHttpRequest': groups = [str(x) for x in request.user.groups.all()] if hasattr(request.user, 'groups') else [] - k = f'menu:{VERSION}:{get_md5(";".join(groups))}:{SettingManager.l2_modules_md5_of_values()}:6' + k = f'menu:{VERSION}:{get_md5(";".join(groups))}:{SettingManager.l2_modules_md5_of_values()}:7' data = cache.get(k) if not data: pages = [ @@ -117,6 +117,13 @@ def menu(request): "access": ["Врач параклиники", "Врач консультаций", "Свидетельство о смерти-доступ"], "module": "paraclinic_module", }, + { + "url": "/ui/case-control", + "title": "Случаи обслуживания", + "nt": False, + "access": ['Врач параклиники', 'Врач консультаций'], + "module": "l2_case", + }, {"url": '/ui/stationar', "title": "Стационар", "nt": False, "access": ["Врач стационара", "t, ad, p"], "module": "l2_hosp"}, { "url": '/ui/plan-operations', diff --git a/directions/admin.py b/directions/admin.py index c07b3bc416..d539210d9c 100644 --- a/directions/admin.py +++ b/directions/admin.py @@ -47,6 +47,7 @@ class NapravleniyaAdmin(admin.ModelAdmin): 'parent', 'parent_auto_gen', 'parent_slave_hosp', + 'parent_case', ) search_fields = ( 'pk', diff --git a/directions/models.py b/directions/models.py index 8511df80b1..d5e49845bf 100644 --- a/directions/models.py +++ b/directions/models.py @@ -500,6 +500,9 @@ class Napravleniya(models.Model): parent_slave_hosp = models.ForeignKey( 'Issledovaniya', related_name='parent_slave_hosp', help_text="Из стационарного протокола", db_index=True, blank=True, null=True, default=None, on_delete=models.SET_NULL ) + parent_case = models.ForeignKey( + 'Issledovaniya', related_name='parent_case', help_text="Случай основание", db_index=True, blank=True, null=True, default=None, on_delete=models.SET_NULL + ) rmis_slot_id = models.CharField(max_length=20, blank=True, null=True, default=None, help_text="РМИС слот") microbiology_n = models.CharField(max_length=10, blank=True, default='', help_text="Номер в микробиологической лаборатории") time_microbiology_receive = models.DateTimeField(null=True, blank=True, db_index=True, help_text='Дата/время приёма материала микробиологии') @@ -784,6 +787,13 @@ def data_sozdaniya_local(self): def visit_date_local(self): return localtime(self.visit_date) + @property + def services(self) -> List[directory.Researches]: + result = [] + for iss in self.issledovaniya_set.all().order_by('research__title'): + result.append(iss.research) + return result + def __str__(self): return "%d для пациента %s (врач %s, выписал %s, %s, %s, %s, par: [%s])" % ( self.pk, @@ -1043,6 +1053,7 @@ def gen_napravleniye( parent_id=None, parent_auto_gen_id=None, parent_slave_hosp_id=None, + parent_case_id=None, rmis_slot=None, direction_purpose="NONE", external_organization="NONE", @@ -1088,6 +1099,7 @@ def gen_napravleniye( parent_id=parent_id, parent_auto_gen_id=parent_auto_gen_id, parent_slave_hosp_id=parent_slave_hosp_id, + parent_case_id=parent_case_id, rmis_slot_id=rmis_slot, hospital=doc.hospital or Hospitals.get_default_hospital(), external_order=external_order, @@ -1279,12 +1291,22 @@ def gen_napravleniya_by_issledovaniya( external_order: Optional[RegisteredOrders] = None, services_by_additional_order_num=None, price_name=None, + case_id=-2, + case_by_direction=False, ): result = {"r": False, "list_id": [], "list_stationar_id": [], "messageLimit": ""} + if case_id > -1 and case_by_direction: + iss = Napravleniya.objects.get(pk=case_id).issledovaniya_set.all().first() + if iss: + case_id = iss.pk + else: + result["message"] = "Ошибка привязки к случаю" + return result if not Clients.Card.objects.filter(pk=client_id).exists(): result["message"] = "Карта в базе не зарегистрирована, попробуйте выполнить поиск заново" return result pk_reseerches = [] + issledovaniye_case_id = None for v in researches.values(): pk_reseerches.extend(v) card = Clients.Card.objects.get(pk=client_id) @@ -1512,6 +1534,41 @@ def gen_napravleniya_by_issledovaniya( result["message"] = "Данный мониторинг уже создан" return result + if case_id > -2: + if case_id == -1: + napravleniye_case = Napravleniya.gen_napravleniye( + client_id, + doc_current if not for_rmis else None, + finsource, + diagnos, + history_num, + doc_current, + ofname_id, + ofname, + for_rmis=for_rmis, + rmis_data=rmis_data, + parent_id=parent_iss, + parent_auto_gen_id=parent_auto_gen, + parent_slave_hosp_id=parent_slave_hosp, + rmis_slot=rmis_slot, + direction_purpose=direction_purpose, + external_organization=external_organization, + price_category=price_category, + hospital=hospital_override, + external_order=external_order, + price_name_id=price_name, + ) + research_case = directory.Researches.objects.filter(is_case=True, hide=False).first() + issledovaniye_case = Issledovaniya( + napravleniye=napravleniye_case, + research=research_case, + deferred=False + ) + issledovaniye_case.save() + issledovaniye_case_id = issledovaniye_case.pk + elif case_id > 0: + issledovaniye_case_id = case_id + if (dir_group > -1 and dir_group not in directions_for_researches.keys()) or (dir_group == dir_group_onlylab and dir_group not in directions_for_researches.keys()): directions_for_researches[dir_group] = Napravleniya.gen_napravleniye( client_id, @@ -1527,6 +1584,7 @@ def gen_napravleniya_by_issledovaniya( parent_id=parent_iss, parent_auto_gen_id=parent_auto_gen, parent_slave_hosp_id=parent_slave_hosp, + parent_case_id=issledovaniye_case_id, rmis_slot=rmis_slot, direction_purpose=direction_purpose, external_organization=external_organization, @@ -1557,6 +1615,7 @@ def gen_napravleniya_by_issledovaniya( parent_id=parent_iss, parent_auto_gen_id=parent_auto_gen, parent_slave_hosp_id=parent_slave_hosp, + parent_case_id=issledovaniye_case_id, rmis_slot=rmis_slot, direction_purpose=direction_purpose, external_organization=external_organization, diff --git a/directions/views.py b/directions/views.py index 1607b5abc5..b646fcf1af 100644 --- a/directions/views.py +++ b/directions/views.py @@ -566,6 +566,7 @@ def print_direction(c: Canvas, n, dir: Napravleniya, format_a6: bool = False): -9: 'Формы', -11: 'Заявления', -12: 'Мониторинги', + -14: 'Случай', }[rtp] # if rtp == -6: # has_micro = True diff --git a/directory/models.py b/directory/models.py index 4a74e91b69..d5b744f8c7 100644 --- a/directory/models.py +++ b/directory/models.py @@ -82,6 +82,7 @@ class ResearchSite(models.Model): (4, 'Микробиология'), (7, 'Формы'), (10, 'Мониторинги'), + (12, 'Случаи'), ) site_type = models.SmallIntegerField(choices=TYPES, help_text="Тип раздела", db_index=True) @@ -243,6 +244,7 @@ class Researches(models.Model): is_monitoring = models.BooleanField(default=False, blank=True, help_text="Это мониторинг", db_index=True) is_expertise = models.BooleanField(default=False, blank=True, help_text="Это экспертиза", db_index=True) is_aux = models.BooleanField(default=False, blank=True, help_text="Это вспомогательный", db_index=True) + is_case = models.BooleanField(default=False, blank=True, help_text="Это случай", db_index=True) site_type = models.ForeignKey(ResearchSite, default=None, null=True, blank=True, help_text='Место услуги', on_delete=models.SET_NULL, db_index=True) need_vich_code = models.BooleanField(default=False, blank=True, help_text="Необходимость указания кода вич в направлении") paraclinic_info = models.TextField(blank=True, default="", help_text="Если это параклиническое исследование - здесь указывается подготовка и кабинет") @@ -330,6 +332,7 @@ def filter_type(t): 14: dict(is_application=True), 15: dict(is_monitoring=True), 16: dict(is_expertise=True), + 17: dict(is_case=True), } return ts.get(t + 1, {}) @@ -357,6 +360,8 @@ def reversed_type(self): return -13 if self.is_microbiology or self.is_citology or self.is_gistology: return 2 - Podrazdeleniya.MORFOLOGY + if self.is_case: + return -14 return self.podrazdeleniye_id or -2 @property @@ -368,6 +373,7 @@ def desc(self): or self.is_paraclinic or self.is_microbiology or self.is_hospital + or self.is_case or self.is_citology or self.is_gistology or self.is_form diff --git a/integration_framework/utils.py b/integration_framework/utils.py index 0222da76b4..d14ab52783 100644 --- a/integration_framework/utils.py +++ b/integration_framework/utils.py @@ -226,7 +226,7 @@ def check_title_field(data, r): def get_json_labortory_data(pk): - result_protocol = get_laboratory_results_by_directions([pk]) + result_protocol = get_laboratory_results_by_directions(tuple([pk])) document = {} confirmed_at = "" date_reiceve = "" diff --git a/l2-frontend/src/App.vue b/l2-frontend/src/App.vue index d563f8eec2..215dd5e597 100644 --- a/l2-frontend/src/App.vue +++ b/l2-frontend/src/App.vue @@ -3,15 +3,18 @@
+ + +
1 ? baseTitleSplit[1] : baseTitleSplit[0]; if (newTitle) { diff --git a/l2-frontend/src/construct/ConstructEmployees.vue b/l2-frontend/src/construct/ConstructEmployees.vue index 434d3a9e65..87a4a9f7d7 100644 --- a/l2-frontend/src/construct/ConstructEmployees.vue +++ b/l2-frontend/src/construct/ConstructEmployees.vue @@ -1,121 +1,118 @@ @@ -44,6 +54,12 @@ const bottomStyle = computed(() => ({ top: topStyle.value.height })); .top { border-bottom: 1px solid #646d78; top: 0; + + &.scrollable { + overflow-x: auto; + overflow-y: visible; + white-space: nowrap; + } } .bottom { diff --git a/l2-frontend/src/layouts/TwoSidedLayout.vue b/l2-frontend/src/layouts/TwoSidedLayout.vue index 2d08697d9f..70944e6e4f 100644 --- a/l2-frontend/src/layouts/TwoSidedLayout.vue +++ b/l2-frontend/src/layouts/TwoSidedLayout.vue @@ -3,13 +3,16 @@
-
+
diff --git a/l2-frontend/src/pages/CaseControl/Content/index.vue b/l2-frontend/src/pages/CaseControl/Content/index.vue new file mode 100644 index 0000000000..e03823d6a8 --- /dev/null +++ b/l2-frontend/src/pages/CaseControl/Content/index.vue @@ -0,0 +1,109 @@ + + + + + + + diff --git a/l2-frontend/src/pages/CaseControl/Sidebar/AnamnesisView.vue b/l2-frontend/src/pages/CaseControl/Sidebar/AnamnesisView.vue new file mode 100644 index 0000000000..5c4f357473 --- /dev/null +++ b/l2-frontend/src/pages/CaseControl/Sidebar/AnamnesisView.vue @@ -0,0 +1,137 @@ + + +