| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed patient overview widgets.
2
3 copyright: authors
4 """
5 #============================================================
6 __author__ = "K.Hilbert"
7 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
8
9 import logging, sys
10
11
12 import wx
13
14
15 if __name__ == '__main__':
16 sys.path.insert(0, '../../')
17 from Gnumed.pycommon import gmTools
18 from Gnumed.pycommon import gmDispatcher
19 from Gnumed.pycommon import gmDateTime
20 from Gnumed.pycommon import gmNetworkTools
21
22 from Gnumed.business import gmPerson
23 from Gnumed.business import gmStaff
24 from Gnumed.business import gmDemographicRecord
25 from Gnumed.business import gmEMRStructItems
26 from Gnumed.business import gmFamilyHistory
27 from Gnumed.business import gmVaccination
28 from Gnumed.business import gmDocuments
29 from Gnumed.business import gmProviderInbox
30 from Gnumed.business import gmExternalCare
31 from Gnumed.business import gmAutoHints
32 from Gnumed.business import gmMedication
33
34 from Gnumed.wxpython import gmRegetMixin
35 from Gnumed.wxpython import gmDemographicsWidgets
36 from Gnumed.wxpython import gmContactWidgets
37 from Gnumed.wxpython import gmMedicationWidgets
38 from Gnumed.wxpython import gmEditArea
39 from Gnumed.wxpython import gmEMRStructWidgets
40 from Gnumed.wxpython import gmEncounterWidgets
41 from Gnumed.wxpython import gmFamilyHistoryWidgets
42 from Gnumed.wxpython import gmVaccWidgets
43 from Gnumed.wxpython import gmDocumentWidgets
44 from Gnumed.wxpython import gmGuiHelpers
45 from Gnumed.wxpython import gmPregWidgets
46 from Gnumed.wxpython import gmHabitWidgets
47 from Gnumed.wxpython import gmHospitalStayWidgets
48 from Gnumed.wxpython import gmProcedureWidgets
49
50
51 _log = logging.getLogger('gm.patient')
52 #============================================================
53 from Gnumed.wxGladeWidgets import wxgPatientOverviewPnl
54
55 -class cPatientOverviewPnl(wxgPatientOverviewPnl.wxgPatientOverviewPnl, gmRegetMixin.cRegetOnPaintMixin):
56
58 wxgPatientOverviewPnl.wxgPatientOverviewPnl.__init__(self, *args, **kwargs)
59 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
60
61 self.__init_ui()
62 self.__register_interests()
63
64 #--------------------------------------------------------
65 # internal API
66 #--------------------------------------------------------
68
69 #self._LCTRL_history.debug = u'LCTRL_history_sizing'
70
71 # left
72 self._LCTRL_identity.set_columns(columns = [''])
73 self._LCTRL_identity.item_tooltip_callback = self._calc_identity_item_tooltip
74 self._LCTRL_identity.activate_callback = self._on_identity_item_activated
75
76 self._LCTRL_contacts.set_columns(columns = [''])
77 self._LCTRL_contacts.item_tooltip_callback = self._calc_contacts_list_item_tooltip
78 self._LCTRL_contacts.activate_callback = self._on_contacts_item_activated
79
80 self._LCTRL_encounters.set_columns(columns = [''])
81 self._LCTRL_encounters.item_tooltip_callback = self._calc_encounters_list_item_tooltip
82 self._LCTRL_encounters.activate_callback = self._on_encounter_activated
83
84 # middle
85 self._LCTRL_meds.set_columns(columns = [''])
86 self._LCTRL_meds.item_tooltip_callback = self._calc_meds_list_item_tooltip
87 self._LCTRL_meds.activate_callback = self._on_meds_item_activated
88
89 self._LCTRL_problems.set_columns(columns = [''])
90 self._LCTRL_problems.item_tooltip_callback = self._calc_problem_list_item_tooltip
91 self._LCTRL_problems.activate_callback = self._on_problem_activated
92
93 self._LCTRL_history.set_columns(columns = [''])
94 self._LCTRL_history.item_tooltip_callback = self._calc_history_list_item_tooltip
95 self._LCTRL_history.activate_callback = self._on_history_item_activated
96
97 # right hand side
98 self._LCTRL_inbox.set_columns(columns = [''])
99 self._LCTRL_inbox.item_tooltip_callback = self._calc_inbox_item_tooltip
100 self._LCTRL_inbox.activate_callback = self._on_inbox_item_activated
101
102 self._LCTRL_results.set_columns(columns = [''])
103 self._LCTRL_results.item_tooltip_callback = self._calc_results_list_item_tooltip
104 self._LCTRL_results.activate_callback = self._on_result_activated
105
106 self._LCTRL_documents.set_columns(columns = [''])
107 self._LCTRL_documents.item_tooltip_callback = self._calc_documents_list_item_tooltip
108 self._LCTRL_documents.activate_callback = self._on_document_activated
109
110 #--------------------------------------------------------
112 self._LCTRL_identity.set_string_items()
113 self._LCTRL_contacts.set_string_items()
114 self._LCTRL_encounters.set_string_items()
115
116 self._LCTRL_problems.set_string_items()
117 self._LCTRL_meds.set_string_items()
118 self._LCTRL_history.set_string_items()
119
120 self._LCTRL_inbox.set_string_items()
121 self._LCTRL_results.set_string_items()
122 self._LCTRL_documents.set_string_items()
123
124 #-----------------------------------------------------
125 # event handling
126 #-----------------------------------------------------
128 # client internal signals
129 gmDispatcher.connect(signal = 'pre_patient_unselection', receiver = self._on_pre_patient_unselection)
130 gmDispatcher.connect(signal = 'post_patient_selection', receiver = self._on_post_patient_selection)
131
132 # generic database change signal
133 gmDispatcher.connect(signal = 'gm_table_mod', receiver = self._on_database_signal)
134
135 # database change signals
136 # no signal for external IDs yet
137 # no signal for address yet
138 ##gmDispatcher.connect(signal = u'current_encounter_modified', receiver = self._on_current_encounter_modified)
139 ##gmDispatcher.connect(signal = u'current_encounter_switched', receiver = self._on_current_encounter_switched)
140
141 # doesn't have pk_identity:
142 gmDispatcher.connect(signal = 'clin.reviewed_test_results_mod_db', receiver = self._on_post_patient_selection)
143
144 # synchronous signals
145 # self.__pat.register_before_switching_from_patient_callback(callback = self._before_switching_from_patient_callback)
146 # gmDispatcher.send(signal = u'register_pre_exit_callback', callback = self._pre_exit_callback)
147
148 #--------------------------------------------------------
150 # only empty out here, do NOT access the patient
151 # or else we will access the old patient while it
152 # may not be valid anymore ...
153 self.__reset_ui_content()
154
155 #--------------------------------------------------------
158
159 #--------------------------------------------------------
161
162 pat = gmPerson.gmCurrentPatient()
163 if not pat.connected:
164 return True
165
166 if kwds['pk_identity'] != pat.ID:
167 return True
168
169 if kwds['table'] == 'dem.identity':
170 if kwds['operation'] != 'UPDATE':
171 return True
172
173 if kwds['table'] in [
174 'blobs.doc_med',
175 'clin.episode',
176 'clin.health_issue',
177 'clin.suppressed_hint',
178 'clin.substance_intake',
179 'clin.hospital_stay',
180 'clin.procedure',
181 'clin.vaccination',
182 'clin.family_history',
183 'clin.test_result',
184 'clin.export_item',
185 'clin.external_care',
186 'dem.identity',
187 'dem.names',
188 'dem.lnk_identity2comm',
189 'dem.lnk_job2person',
190 'dem.message_inbox',
191 'ref.auto_hint'
192 ]:
193 self._schedule_data_reget()
194 return True
195
196 return True
197
198 #-----------------------------------------------------
199 # reget-on-paint mixin API
200 #-----------------------------------------------------
202 pat = gmPerson.gmCurrentPatient()
203 if not pat.connected:
204 self.__reset_ui_content()
205 return True
206
207 self.__refresh_identity(patient = pat)
208 self.__refresh_contacts(patient = pat)
209 self.__refresh_encounters(patient = pat)
210
211 self.__refresh_problems(patient = pat)
212 self.__refresh_meds(patient = pat)
213 self.__refresh_history(patient = pat)
214
215 self.__refresh_inbox(patient = pat)
216 self.__refresh_results(patient = pat)
217 self.__refresh_documents(patient = pat)
218
219 return True
220
221 #-----------------------------------------------------
222 # internal helpers
223 #-----------------------------------------------------
225
226 emr = patient.emr
227 most_recent = emr.get_most_recent_results_for_patient()
228 if len(most_recent) == 0:
229 self._LCTRL_results.set_string_items(items = [])
230 self._LCTRL_results.set_data(data = [])
231 return
232 most_recent = most_recent[0]
233
234 list_items = []
235 list_data = []
236 now = gmDateTime.pydt_now_here()
237
238 list_items.append(_('Most recent lab work: %s ago (%s)') % (
239 gmDateTime.format_interval_medically(now - most_recent['clin_when']),
240 gmDateTime.pydt_strftime(most_recent['clin_when'], format = '%Y %b %d')
241 ))
242 list_data.append(most_recent)
243
244 unsigned = emr.get_unsigned_results(order_by = "(trim(coalesce(abnormality_indicator), '') <> '') DESC NULLS LAST, unified_abbrev")
245 no_of_reds = 0
246 for result in unsigned:
247 if result['abnormality_indicator'] is not None:
248 if result['abnormality_indicator'].strip() != '':
249 no_of_reds += 1
250 list_items.append(_('%s %s%s%s (%s ago, %s)') % (
251 result['unified_abbrev'],
252 result['unified_val'],
253 gmTools.coalesce(result['val_unit'], '', ' %s'),
254 gmTools.coalesce(result['abnormality_indicator'], '', ' %s'),
255 gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - result['clin_when']),
256 gmTools.u_writing_hand
257 ))
258 list_data.append(result)
259
260 self._LCTRL_results.set_string_items(items = list_items)
261 self._LCTRL_results.set_data(data = list_data)
262
263 if no_of_reds > 0:
264 for idx in range(1, no_of_reds + 1):
265 self._LCTRL_results.SetItemTextColour(idx, wx.Colour('RED'))
266
267 #-----------------------------------------------------
270
271 #-----------------------------------------------------
273 # data = self._LCTRL_inbox.get_selected_item_data(only_one = True)
274 #
275 # if data is not None:
276 # # <ctrl> down ?
277 # if wx.GetKeyState(wx.WXK_CONTROL):
278 # if isinstance(data, gmProviderInbox.cInboxMessage):
279 # xxxxxxxxx
280 gmDispatcher.send(signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
281 return
282
283 #-----------------------------------------------------
284 #-----------------------------------------------------
286 list_items = []
287 list_data = []
288 highlight_list = []
289 line_idx = -1
290
291 overdue_messages = patient.overdue_messages
292 if len(overdue_messages) > 0:
293 highlight_list.extend(range(len(overdue_messages)))
294 for msg in overdue_messages:
295 line_idx += 1
296 list_items.append(_('overdue %s: %s') % (
297 gmDateTime.format_interval_medically(msg['interval_due']),
298 gmTools.coalesce(msg['comment'], '?')
299 ))
300 list_data.append(msg)
301
302 for msg in patient.get_messages(order_by = 'due_date NULLS LAST, importance DESC, received_when DESC'):
303 # already displayed above ?
304 if msg['is_overdue']:
305 continue
306 # not relevant anymore ?
307 if msg['is_expired']:
308 continue
309 line_idx += 1
310 if msg['due_date'] is None:
311 label = '%s%s' % (
312 msg['l10n_type'],
313 gmTools.coalesce(msg['comment'], '', ': %s')
314 )
315 else:
316 label = _('due in %s%s') % (
317 gmDateTime.format_interval_medically(msg['interval_due']),
318 gmTools.coalesce(msg['comment'], '', ': %s')
319 )
320 list_items.append(label)
321 list_data.append(msg)
322
323 pk_enc = patient.emr.active_encounter['pk_encounter']
324 for hint in patient._get_dynamic_hints(pk_encounter = pk_enc):
325 line_idx += 1
326 list_items.append(hint['title'])
327 list_data.append(hint)
328 if hint['highlight_as_priority']:
329 highlight_list.append(line_idx)
330
331 hints = patient.suppressed_hints
332 if len(hints) > 0:
333 list_items.append((_("suppr'd (%s):") % len(hints)) + ' ' + ','.join([h['title'][:7] + gmTools.u_ellipsis for h in hints]))
334 list_data.append(_('Suppressed hints:\n') + '\n'.join(['%s: %s' % (hints.index(h) + 1, h['title']) for h in hints]))
335
336 self._LCTRL_inbox.set_string_items(items = list_items)
337 self._LCTRL_inbox.set_data(data = list_data)
338
339 for idx in highlight_list:
340 self._LCTRL_inbox.SetItemTextColour(idx, wx.Colour('RED'))
341
342 #-----------------------------------------------------
344 if isinstance(data, gmProviderInbox.cInboxMessage):
345 return data.format()
346
347 if isinstance(data, gmAutoHints.cDynamicHint):
348 return '%s\n\n%s%s\n\n%s %s' % (
349 data['title'],
350 gmTools.wrap(data['hint'], width = 50),
351 gmTools.wrap(gmTools.coalesce(data['recommendation'], '', '\n\n%s'), width = 50),
352 gmTools.wrap(gmTools.coalesce(data['url'], '', '%s\n\n'), width = 50),
353 data['source']
354 )
355
356 if isinstance(data, type('')):
357 return data
358
359 return None
360
361 #-----------------------------------------------------
363
364 data = self._LCTRL_inbox.get_selected_item_data(only_one = True)
365
366 # if it is a dynamic hint open the URL for that
367 if isinstance(data, gmAutoHints.cDynamicHint):
368 if data['url'] is not None:
369 gmNetworkTools.open_url_in_browser(data['url'])
370 return
371
372 # holding down <CTRL> when double-clicking an inbox
373 # item indicates the desire to delete it
374 # <ctrl> down ?
375 if wx.GetKeyState(wx.WXK_CONTROL):
376 # better safe than sorry: can only delete real inbox items
377 if data is None:
378 return
379 if not isinstance(data, gmProviderInbox.cInboxMessage):
380 return
381 delete_it = gmGuiHelpers.gm_show_question (
382 question = _('Do you really want to\ndelete this inbox message ?'),
383 title = _('Deleting inbox message')
384 )
385 if not delete_it:
386 return
387 gmProviderInbox.delete_inbox_message(inbox_message = data['pk_inbox_message'])
388 return
389
390 if data is None:
391 gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin')
392 return
393
394 if not isinstance(data, gmProviderInbox.cInboxMessage):
395 gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin')
396 return
397
398 gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin', filter_by_active_patient = True)
399 return
400 #-----------------------------------------------------
401 #-----------------------------------------------------
403
404 list_items = []
405 list_data = []
406
407 # export area items
408 item_count = len(patient.export_area.items)
409 if item_count == 1:
410 list_items.append(_('Export area: 1 item'))
411 list_data.append('')
412 if item_count > 1:
413 list_items.append(_('Export area: %s items') % item_count)
414 list_data.append('')
415
416 doc_folder = patient.get_document_folder()
417
418 # unsigned docs first
419 docs = doc_folder.get_unsigned_documents()
420 no_of_unsigned = len(docs)
421 for doc in docs:
422 list_items.append('%s %s (%s)' % (
423 gmDateTime.pydt_strftime(doc['clin_when'], format = '%m/%Y', accuracy = gmDateTime.acc_months),
424 doc['l10n_type'],
425 gmTools.u_writing_hand
426 ))
427 list_data.append(doc)
428
429 # other, signed docs second
430 docs = doc_folder.get_documents(order_by = 'ORDER BY clin_when DESC', exclude_unsigned = True)
431 for doc in docs[:5]:
432 list_items.append('%s %s' % (
433 gmDateTime.pydt_strftime(doc['clin_when'], format = '%m/%Y', accuracy = gmDateTime.acc_months),
434 doc['l10n_type']
435 ))
436 list_data.append(doc)
437 if len(docs) > 5:
438 list_items.append(_('%s %s more not shown %s') % (
439 gmTools.u_ellipsis,
440 len(docs) - 5,
441 gmTools.u_ellipsis
442 ))
443 list_data.append('')
444
445 self._LCTRL_documents.set_string_items(items = list_items)
446 self._LCTRL_documents.set_data(data = list_data)
447
448 if no_of_unsigned > 0:
449 start_idx = 0
450 if item_count > 0:
451 start_idx = 1
452 end_idx = no_of_unsigned + start_idx
453 for idx in range(start_idx, end_idx):
454 self._LCTRL_documents.SetItemTextColour(idx, wx.Colour('RED'))
455 #-----------------------------------------------------
457 emr = gmPerson.gmCurrentPatient().emr
458
459 if isinstance(data, gmDocuments.cDocument):
460 return data.format()
461
462 return None
463 #-----------------------------------------------------
465 data = self._LCTRL_documents.get_selected_item_data(only_one = True)
466
467 if data is not None:
468 # <ctrl> down ?
469 if wx.GetKeyState(wx.WXK_CONTROL):
470 if isinstance(data, gmDocuments.cDocument):
471 if len(data.parts) > 0:
472 gmDocumentWidgets.display_document_part(parent = self, part = data.parts[0])
473 else:
474 gmDocumentWidgets.review_document(parent = self, document = data)
475 return
476
477 gmDispatcher.send(signal = 'display_widget', name = 'gmShowMedDocs')
478 return
479 #-----------------------------------------------------
480 #-----------------------------------------------------
482
483 emr = patient.emr
484
485 list_items = []
486 list_data = []
487
488 is_waiting = False
489 wlist = patient.get_waiting_list_entry()
490 if len(wlist) > 0:
491 is_waiting = True
492 list_items.append(_('Currently %s entries in waiting list') % len(wlist))
493 tt = []
494 for w in wlist:
495 tt.append('%s %s%s%s' % (
496 gmTools.u_triangular_bullet,
497 gmDateTime.format_interval_medically(w['waiting_time']),
498 gmTools.coalesce(w['waiting_zone'], '', ' in "%s"'),
499 gmTools.coalesce(w['comment'], '', ': %s')
500 ))
501 if len(tt) > 0:
502 tt = '\n'.join(tt)
503 else:
504 tt = None
505 list_data.append({'wlist': tt})
506
507 first = emr.get_first_encounter()
508 if first is not None:
509 list_items.append (
510 _('first (in GMd): %s, %s') % (
511 gmDateTime.pydt_strftime (
512 first['started'],
513 format = '%Y %b %d',
514 accuracy = gmDateTime.acc_days
515 ),
516 first['l10n_type']
517 )
518 )
519 list_data.append(first)
520
521 last = emr.get_last_but_one_encounter()
522 if last is not None:
523 list_items.append (
524 _('last: %s, %s') % (
525 gmDateTime.pydt_strftime (
526 last['started'],
527 format = '%Y %b %d',
528 accuracy = gmDateTime.acc_days
529 ),
530 last['l10n_type']
531 )
532 )
533 list_data.append(last)
534
535 encs = emr.get_encounter_stats_by_type()
536 for enc in encs:
537 item = ' %s x %s' % (enc['frequency'], enc['l10n_type'])
538 list_items.append(item)
539 list_data.append(item)
540
541 stays = emr.get_hospital_stay_stats_by_hospital()
542 for stay in stays:
543 item = ' %s x %s' % (
544 stay['frequency'],
545 stay['hospital']
546 )
547 list_items.append(item)
548 list_data.append({'stay': item})
549
550 self._LCTRL_encounters.set_string_items(items = list_items)
551 self._LCTRL_encounters.set_data(data = list_data)
552 if is_waiting:
553 self._LCTRL_encounters.SetItemTextColour(0, wx.Colour('RED'))
554
555 #-----------------------------------------------------
557 emr = gmPerson.gmCurrentPatient().emr
558
559 if isinstance(data, gmEMRStructItems.cEncounter):
560 return data.format (
561 with_vaccinations = False,
562 with_tests = False,
563 with_docs = False,
564 with_co_encountlet_hints = True,
565 with_rfe_aoe = True
566 )
567
568 if type(data) is dict:
569 key, val = list(data.items())[0]
570 if key == 'wlist':
571 return val
572 if key == 'stay':
573 return None
574
575 return data
576 #-----------------------------------------------------
578 data = self._LCTRL_encounters.get_selected_item_data(only_one = True)
579 if data is not None:
580 # <ctrl> down ?
581 if wx.GetKeyState(wx.WXK_CONTROL):
582 if isinstance(data, gmEMRStructItems.cEncounter):
583 gmEncounterWidgets.edit_encounter(parent = self, encounter = data)
584 return
585
586 if type(data) is dict:
587 key, val = list(data.items())[0]
588 if key == 'wlist':
589 gmDispatcher.send(signal = 'display_widget', name = 'gmWaitingListPlugin')
590 return
591 if key == 'stay':
592 wx.CallAfter(gmHospitalStayWidgets.manage_hospital_stays, parent = self)
593 return
594
595 wx.CallAfter(gmEncounterWidgets.manage_encounters, parent = self, ignore_OK_button = False)
596
597 #-----------------------------------------------------
598 #-----------------------------------------------------
600 emr = patient.emr
601
602 sort_key_list = []
603 date_format4sorting = '%Y %m %d %H %M %S'
604 now = gmDateTime.pydt_now_here()
605 data = {}
606
607 # undated entries
608 # pregnancy
609 edc = emr.EDC
610 if edc is not None:
611 sort_key = '99999 edc'
612 if emr.EDC_is_fishy:
613 label = _('EDC (!?!): %s') % gmDateTime.pydt_strftime(edc, format = '%Y %b %d')
614 tt = _(
615 'The Expected Date of Confinement is rather questionable.\n'
616 '\n'
617 'Please check patient age, patient gender, time until/since EDC.'
618 )
619 else:
620 label = _('EDC: %s') % gmDateTime.pydt_strftime(edc, format = '%Y %b %d')
621 tt = ''
622 sort_key_list.append(sort_key)
623 data[sort_key] = [label, tt]
624
625 # family history
626 fhxs = emr.get_family_history()
627 for fhx in fhxs:
628 sort_key = '99998 %s::%s' % (fhx['l10n_relation'], fhx['pk_family_history'])
629 sort_key_list.append(sort_key)
630 #gmDateTime.pydt_strftime(fhx['when_known_to_patient'], format = '%Y %m %d %H %M %S')
631 label = '%s%s: %s' % (fhx['l10n_relation'], gmTools.coalesce(fhx['age_noted'], '', ' (@ %s)'), fhx['condition'])
632 data[sort_key] = [label, fhx]
633 del fhxs
634
635 # dated entries
636 issues = [
637 i for i in emr.get_health_issues()
638 if ((i['clinically_relevant'] is False) or (i['is_active'] is False))
639 ]
640 for issue in issues:
641 last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
642 linked_encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
643 when_candidates = [issue['modified_when'], linked_encounter['last_affirmed']]
644 if last_encounter is not None:
645 when_candidates.append(last_encounter['last_affirmed'])
646 if (patient['dob'] is not None) and (issue['age_noted'] is not None):
647 when_candidates.append(patient['dob'] + issue['age_noted'])
648 if issue['is_active']:
649 # sort active issues by time of most recent clinical access, which
650 # means the most recent of:
651 # issue.modified_when
652 # last_encounter.last_affirmed
653 # linked_encounter.last_affirmed
654 # dob + age
655 relevant_date = max(when_candidates)
656 else:
657 # sort IN-active issues by best guess of real clinical start
658 # means either:
659 # - dob + age
660 # or the earliest of:
661 # - issue.modified_when
662 # - last_encounter.last_affirmed
663 # - linked_encounter.last_affirmed
664 if (patient['dob'] is not None) and (issue['age_noted'] is not None):
665 relevant_date = patient['dob'] + issue['age_noted']
666 else:
667 relevant_date = min(when_candidates)
668 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(relevant_date, format = date_format4sorting), issue['pk_health_issue'])
669 relevant_date_str = gmDateTime.pydt_strftime(relevant_date, format = '%Y %b')
670 if issue['age_noted'] is None:
671 encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
672 age = _(' (entered %s ago)') % gmDateTime.format_interval_medically(now - encounter['started'])
673 else:
674 age = ' (@ %s)' % gmDateTime.format_interval_medically(issue['age_noted'])
675 sort_key_list.append(sort_key)
676 data[sort_key] = ['%s %s%s' % (relevant_date_str, issue['description'], age), issue]
677 del issues
678
679 stays = emr.get_hospital_stays()
680 for stay in stays:
681 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(stay['admission'], format = date_format4sorting), stay['pk_hospital_stay'])
682 label = '%s %s: %s (%s)' % (
683 gmDateTime.pydt_strftime(stay['admission'], format = '%Y %b'),
684 stay['hospital'],
685 stay['episode'],
686 _('%s ago') % gmDateTime.format_interval_medically(now - stay['admission'])
687 )
688 sort_key_list.append(sort_key)
689 data[sort_key] = [label, stay]
690 del stays
691
692 procs = emr.get_performed_procedures()
693 for proc in procs:
694 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(proc['clin_when'], format = date_format4sorting), proc['pk_procedure'])
695 label = '%s%s %s (%s @ %s)' % (
696 gmDateTime.pydt_strftime(proc['clin_when'], format = '%Y %b'),
697 gmTools.bool2subst(proc['is_ongoing'], gmTools.u_ellipsis, '', ''),
698 proc['performed_procedure'],
699 _('%s ago') % gmDateTime.format_interval_medically(now - proc['clin_when']),
700 gmDateTime.format_interval_medically(proc['clin_when'] - patient['dob'])
701 )
702 sort_key_list.append(sort_key)
703 data[sort_key] = [label, proc]
704 del procs
705
706 vaccs = emr.get_latest_vaccinations()
707 for ind, tmp in vaccs.items():
708 no_of_shots, vacc = tmp
709 sort_key = '%s::%s::%s' % (gmDateTime.pydt_strftime(vacc['date_given'], format = date_format4sorting), vacc['pk_vaccination'], ind)
710 label = _('%s Vacc: %s (latest of %s: %s ago)') % (
711 gmDateTime.pydt_strftime(vacc['date_given'], format = '%Y %b'),
712 ind,
713 no_of_shots,
714 gmDateTime.format_interval_medically(now - vacc['date_given'])
715 )
716 sort_key_list.append(sort_key)
717 data[sort_key] = [label, vacc]
718 del vaccs
719
720 for abuse in [ a for a in emr.abused_substances if a['harmful_use_type'] == 3 ]:
721 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(abuse['last_checked_when'], format = date_format4sorting), abuse['substance'])
722 label = _('Hx of addiction: %s') % abuse['substance']
723 sort_key_list.append(sort_key)
724 data[sort_key] = [label, abuse]
725
726 sort_key_list.sort()
727 sort_key_list.reverse()
728 list_items = []
729 list_data = []
730 for key in sort_key_list:
731 label, item = data[key]
732 list_items.append(label)
733 list_data.append(item)
734
735 self._LCTRL_history.set_string_items(items = list_items)
736 self._LCTRL_history.set_data(data = list_data)
737
738 #-----------------------------------------------------
740
741 if isinstance(data, gmEMRStructItems.cHealthIssue):
742 return data.format (
743 patient = gmPerson.gmCurrentPatient(),
744 with_medications = False,
745 with_hospital_stays = False,
746 with_procedures = False,
747 with_family_history = False,
748 with_documents = False,
749 with_tests = False,
750 with_vaccinations = False
751 ).strip('\n')
752
753 if isinstance(data, gmMedication.cSubstanceIntakeEntry):
754 return data.format(single_line = False)
755
756 if isinstance(data, gmFamilyHistory.cFamilyHistory):
757 return data.format(include_episode = True, include_comment = True)
758
759 if isinstance(data, gmEMRStructItems.cHospitalStay):
760 return data.format()
761
762 if isinstance(data, gmEMRStructItems.cPerformedProcedure):
763 return data.format(include_episode = True, include_codes = False, include_address = True, include_comm = True)
764
765 if isinstance(data, gmVaccination.cVaccination):
766 return '\n'.join(data.format (
767 with_indications = True,
768 with_comment = True,
769 with_reaction = True,
770 date_format = '%Y %b %d'
771 ))
772
773 # EDC
774 if isinstance(data, str):
775 if data == '':
776 return None
777 return data
778
779 return None
780
781 #-----------------------------------------------------
783 data = self._LCTRL_history.get_selected_item_data(only_one = True)
784 if data is None:
785 return
786
787 if isinstance(data, str):
788 gmPregWidgets.calculate_edc(parent = self, patient = gmPerson.gmCurrentPatient())
789 return
790
791 # <ctrl> down ?
792 if wx.GetKeyState(wx.WXK_CONTROL):
793 if isinstance(data, gmEMRStructItems.cHealthIssue):
794 gmEMRStructWidgets.edit_health_issue(parent = self, issue = data)
795 return
796 if isinstance(data, gmFamilyHistory.cFamilyHistory):
797 FamilyHistoryWidgets.edit_family_history(parent = self, family_history = data)
798 return
799 if isinstance(data, gmEMRStructItems.cHospitalStay):
800 gmHospitalStayWidgets.edit_hospital_stay(parent = self, hospital_stay = data)
801 return
802 if isinstance(data, gmEMRStructItems.cPerformedProcedure):
803 gmProcedureWidgets.edit_procedure(parent = self, procedure = data)
804 return
805 if isinstance(data, gmVaccination.cVaccination):
806 gmVaccWidgets.edit_vaccination(parent = self, vaccination = data, single_entry = True)
807 return
808 return
809
810 if isinstance(data, gmEMRStructItems.cHealthIssue):
811 gmDispatcher.send(signal = 'display_widget', name = 'gmEMRBrowserPlugin')
812 return
813 if isinstance(data, gmFamilyHistory.cFamilyHistory):
814 FamilyHistoryWidgets.manage_family_history(parent = self)
815 return
816 if isinstance(data, gmEMRStructItems.cHospitalStay):
817 gmHospitalStayWidgets.manage_hospital_stays(parent = self)
818 return
819 if isinstance(data, gmEMRStructItems.cPerformedProcedure):
820 gmProcedureWidgets.manage_performed_procedures(parent = self)
821 return
822 if isinstance(data, gmVaccination.cVaccination):
823 gmVaccWidgets.manage_vaccinations(parent = self)
824 return
825
826 return
827 #-----------------------------------------------------
828 #-----------------------------------------------------
830
831 emr = patient.emr
832
833 list_items = []
834 data_items = []
835 first_red = False
836
837 # harmful substance use ?
838 abuses = emr.abused_substances
839 if len([ a for a in abuses if a['harmful_use_type'] in [1, 2] ]) > 0:
840 list_items.append(_('active substance abuse'))
841 data_items.append('\n'.join([ a.format(left_margin=0, date_format='%Y %b %d', single_line=True) for a in abuses ]))
842
843 # list by product or substance:
844 intakes = emr.get_current_medications(include_inactive = False, include_unapproved = True, order_by = 'substance')
845 multi_products_already_seen = []
846 for intake in intakes:
847 drug = intake.containing_drug
848 if len(drug['components']) == 1:
849 list_items.append(_('%s %s%s%s') % (
850 intake['substance'],
851 intake['amount'],
852 intake.formatted_units,
853 gmTools.coalesce(intake['schedule'], '', ': %s')
854 ))
855 data_items.append(intake)
856 else:
857 if intake['product'] in multi_products_already_seen:
858 continue
859 multi_products_already_seen.append(intake['product'])
860 list_items.append(_('%s %s%s') % (
861 intake['product'],
862 drug['l10n_preparation'],
863 gmTools.coalesce(intake['schedule'], '', ': %s')
864 ))
865 data_items.append(intake)
866
867 self._LCTRL_meds.set_string_items(items = list_items)
868 self._LCTRL_meds.set_data(data = data_items)
869
870 if first_red:
871 self._LCTRL_meds.SetItemTextColour(0, wx.Colour('RED'))
872
873 #-----------------------------------------------------
875 if isinstance(data, str):
876 return data
877 emr = gmPerson.gmCurrentPatient().emr
878 atcs = []
879 if data['atc_substance'] is not None:
880 atcs.append(data['atc_substance'])
881 # if data['atc_drug'] is not None:
882 # atcs.append(data['atc_drug'])
883 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (data['substance'],), drug = data['product'])
884 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (data['substance'],))
885 if allg is False:
886 allg = None
887 return data.format(single_line = False, allergy = allg, show_all_product_components = True)
888
889 #-----------------------------------------------------
891 data = self._LCTRL_meds.get_selected_item_data(only_one = True)
892
893 if data is None:
894 return
895
896 # if isinstance(data, str):
897 # gmHabitWidgets.manage_substance_abuse(parent = self, patient = gmPerson.gmCurrentPatient())
898 # return
899
900 # <ctrl> down ? -> edit
901 if wx.GetKeyState(wx.WXK_CONTROL):
902 wx.CallAfter(gmMedicationWidgets.edit_intake_of_substance, parent = self, substance = data)
903 return
904
905 gmDispatcher.send(signal = 'display_widget', name = 'gmCurrentSubstancesPlugin')
906
907 #-----------------------------------------------------
908 #-----------------------------------------------------
910 emr = patient.emr
911
912 list_items = []
913 list_data = []
914 is_in_hospital = False
915
916 stays = emr.get_hospital_stays(ongoing_only = True)
917 if len(stays) > 0:
918 list_items.append(_('** Currently hospitalized: %s **') % stays[0]['hospital'])
919 list_data.append(stays[0])
920 is_in_hospital = True
921
922 adrs = patient.get_addresses()
923 for adr in adrs:
924 list_items.append(adr.format(single_line = True, verbose = False, show_type = True))
925 list_data.append(adr)
926
927 comms = patient.get_comm_channels()
928 for comm in comms:
929 list_items.append('%s: %s%s' % (
930 comm['l10n_comm_type'],
931 comm['url'],
932 gmTools.coalesce(comm['comment'], '', ' (%s)')
933 ))
934 list_data.append(comm)
935
936 ident = patient.emergency_contact_in_database
937 if ident is not None:
938 list_items.append(_('emergency: %s') % ident['description_gender'])
939 list_data.append(ident)
940
941 if patient['emergency_contact'] is not None:
942 list_items.append(_('emergency: %s') % patient['emergency_contact'].split('\n')[0])
943 list_data.append(patient['emergency_contact'])
944
945 provider = patient.primary_provider
946 if provider is not None:
947 list_items.append(_('in-praxis: %s') % patient.primary_provider_identity.get_description_gender(with_nickname = False))
948 list_data.append(provider)
949
950 for item in emr.external_care_items:
951 list_items.append(_('care: %s%s@%s') % (
952 gmTools.coalesce(item['provider'], '', '%s, '),
953 item['unit'],
954 item['organization']
955 ))
956 list_data.append(item)
957
958 self._LCTRL_contacts.set_string_items(items = list_items)
959 self._LCTRL_contacts.set_data(data = list_data)
960 if is_in_hospital:
961 self._LCTRL_contacts.SetItemTextColour(0, wx.Colour('RED'))
962
963 #-----------------------------------------------------
965
966 if isinstance(data, gmEMRStructItems.cHospitalStay):
967 return data.format()
968
969 if isinstance(data, gmExternalCare.cExternalCareItem):
970 return '\n'.join(data.format (
971 with_health_issue = True,
972 with_address = True,
973 with_comms = True
974 ))
975
976 if isinstance(data, gmDemographicRecord.cPatientAddress):
977 return '\n'.join(data.format())
978
979 if isinstance(data, gmDemographicRecord.cCommChannel):
980 parts = []
981 if data['is_confidential']:
982 parts.append(_('*** CONFIDENTIAL ***'))
983 if data['comment'] is not None:
984 parts.append(data['comment'])
985 return '\n'.join(parts)
986
987 if isinstance(data, gmPerson.cPerson):
988 return '%s\n\n%s' % (
989 data['description_gender'],
990 '\n'.join([
991 '%s: %s%s' % (
992 c['l10n_comm_type'],
993 c['url'],
994 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), '', '')
995 )
996 for c in data.get_comm_channels()
997 ])
998 )
999
1000 if isinstance(data, str):
1001 return data
1002
1003 if isinstance(data, gmStaff.cStaff):
1004 ident = data.identity
1005 return '%s: %s\n\n%s%s' % (
1006 data['short_alias'],
1007 ident['description_gender'],
1008 '\n'.join([
1009 '%s: %s%s' % (
1010 c['l10n_comm_type'],
1011 c['url'],
1012 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), '', '')
1013 )
1014 for c in ident.get_comm_channels()
1015 ]),
1016 gmTools.coalesce(data['comment'], '', '\n\n%s')
1017 )
1018
1019 return None
1020
1021 #-----------------------------------------------------
1023 data = self._LCTRL_contacts.get_selected_item_data(only_one = True)
1024 if data is not None:
1025 # <ctrl> down ?
1026 if wx.GetKeyState(wx.WXK_CONTROL):
1027 if isinstance(data, gmEMRStructItems.cHospitalStay):
1028 gmHospitalStayWidgets.edit_hospital_stay(parent = self, hospital_stay = data)
1029 return
1030 if isinstance(data, gmDemographicRecord.cPatientAddress):
1031 pass
1032 if isinstance(data, gmDemographicRecord.cCommChannel):
1033 gmContactWidgets.edit_comm_channel(parent = self, comm_channel = data, channel_owner = gmPerson.gmCurrentPatient())
1034 return
1035 if isinstance(data, gmPerson.cPerson):
1036 pass
1037 if isinstance(data, gmStaff.cStaff):
1038 pass
1039
1040 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1041
1042 #-----------------------------------------------------
1043 #-----------------------------------------------------
1045 emr = patient.emr
1046
1047 problems = [
1048 p for p in emr.get_problems(include_closed_episodes = False, include_irrelevant_issues = False)
1049 if p['problem_active']
1050 ]
1051
1052 list_items = []
1053 list_data = []
1054 for problem in problems:
1055 if problem['type'] == 'issue':
1056 issue = emr.problem2issue(problem)
1057 last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
1058 if last_encounter is None:
1059 last = issue['modified_when'].strftime('%m/%Y')
1060 else:
1061 last = last_encounter['last_affirmed'].strftime('%m/%Y')
1062 list_items.append('%s: %s' % (problem['problem'], last))
1063 elif problem['type'] == 'episode':
1064 epi = emr.problem2episode(problem)
1065 last_encounter = emr.get_last_encounter(episode_id = epi['pk_episode'])
1066 if last_encounter is None:
1067 last = epi['episode_modified_when'].strftime('%m/%Y')
1068 else:
1069 last = last_encounter['last_affirmed'].strftime('%m/%Y')
1070 list_items.append('%s: %s' % (problem['problem'], last))
1071 list_data.append(problem)
1072
1073 care = emr.get_external_care_items(exclude_inactive = True)
1074 for item in care:
1075 # skip those already-shown(-or-not)
1076 if item['pk_health_issue'] is not None:
1077 continue
1078 list_items.append(_('extrnl: %s (%s@%s)') % (
1079 item['issue'],
1080 item['unit'],
1081 item['organization']
1082 ))
1083 list_data.append(item)
1084
1085 self._LCTRL_problems.set_string_items(items = list_items)
1086 self._LCTRL_problems.set_data(data = list_data)
1087
1088 #-----------------------------------------------------
1090
1091 if isinstance(data, gmExternalCare.cExternalCareItem):
1092 return '\n'.join(data.format (
1093 with_health_issue = True,
1094 with_address = True,
1095 with_comms = True
1096 ))
1097
1098 emr = gmPerson.gmCurrentPatient().emr
1099
1100 if data['type'] == 'issue':
1101 issue = emr.problem2issue(data)
1102 tt = issue.format (
1103 patient = gmPerson.gmCurrentPatient(),
1104 with_medications = False,
1105 with_hospital_stays = False,
1106 with_procedures = False,
1107 with_family_history = False,
1108 with_documents = False,
1109 with_tests = False,
1110 with_vaccinations = False
1111 ).strip('\n')
1112 return tt
1113
1114 if data['type'] == 'episode':
1115 epi = emr.problem2episode(data)
1116 tt = epi.format (
1117 patient = gmPerson.gmCurrentPatient(),
1118 with_encounters = False,
1119 with_hospital_stays = False,
1120 with_procedures = False,
1121 with_family_history = False,
1122 with_documents = False,
1123 with_tests = False,
1124 with_vaccinations = False,
1125 with_health_issue = True
1126 ).strip('\n')
1127 return tt
1128
1129 return None
1130
1131 #-----------------------------------------------------
1133 data = self._LCTRL_problems.get_selected_item_data(only_one = True)
1134 if data is not None:
1135 # <ctrl> down ?
1136 if wx.GetKeyState(wx.WXK_CONTROL):
1137 emr = gmPerson.gmCurrentPatient().emr
1138 if data['type'] == 'issue':
1139 gmEMRStructWidgets.edit_health_issue(parent = self, issue = emr.problem2issue(data))
1140 return
1141 if data['type'] == 'episode':
1142 gmEMRStructWidgets.edit_episode(parent = self, episode = emr.problem2episode(data))
1143 return
1144
1145 gmDispatcher.send(signal = 'display_widget', name = 'gmEMRBrowserPlugin')
1146
1147 #-----------------------------------------------------
1148 #-----------------------------------------------------
1150 # names (.comment -> tooltip)
1151 names = patient.get_names(exclude_active = True)
1152 items = [
1153 _('aka: %(last)s, %(first)s%(nick)s') % {
1154 'last': n['lastnames'],
1155 'first': n['firstnames'],
1156 'nick': gmTools.coalesce(n['preferred'], '', " '%s'")
1157 } for n in names
1158 ]
1159 data = names
1160
1161 # IDs (.issuer & .comment -> tooltip)
1162 ids = patient.external_ids
1163 for i in ids:
1164 items.append('%s: %s' % (i['name'], i['value']))
1165 data.append({'id': i})
1166
1167 # occupation
1168 jobs = patient.get_occupations()
1169 for j in jobs:
1170 items.append(_('job: %s (%s)') % (
1171 j['l10n_occupation'],
1172 j['modified_when'].strftime('%m/%Y')
1173 ))
1174 data.append({'job': j})
1175
1176 self._LCTRL_identity.set_string_items(items = items)
1177 self._LCTRL_identity.set_data(data = data)
1178
1179 #-----------------------------------------------------
1181 if isinstance(data, gmPerson.cPersonName):
1182 return data['comment']
1183 if isinstance(data, dict):
1184 key = list(data.keys())[0]
1185 val = data[key]
1186 if key == 'id':
1187 return _('issued by: %s%s') % (
1188 val['issuer'],
1189 gmTools.coalesce(val['comment'], '', '\n\n%s')
1190 )
1191 if key == 'job':
1192 tt = _('Last modified: %s') % val['modified_when'].strftime('%m/%Y')
1193 if val['activities'] is None:
1194 return tt
1195 return tt + ('\n\n' + _('Activities:\n\n%s') % val['activities'])
1196
1197 return None
1198
1199 #-----------------------------------------------------
1201 data = self._LCTRL_identity.get_selected_item_data(only_one = True)
1202 if data is None:
1203 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1204
1205 # <ctrl> down ?
1206 if not wx.GetKeyState(wx.WXK_CONTROL):
1207 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1208
1209 # <ctrl> down !
1210 if isinstance(data, gmPerson.cPersonName):
1211 ea = gmDemographicsWidgets.cPersonNameEAPnl(self, -1, name = data)
1212 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1213 dlg.SetTitle(_('Cloning name'))
1214 dlg.ShowModal()
1215 return
1216
1217 if isinstance(data, dict):
1218 key = list(data.keys())[0]
1219 val = data[key]
1220 if key == 'id':
1221 ea = gmDemographicsWidgets.cExternalIDEditAreaPnl(self, -1, external_id = val)
1222 ea.id_holder = gmPerson.gmCurrentPatient()
1223 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1224 dlg.SetTitle(_('Editing external ID'))
1225 dlg.ShowModal()
1226 return
1227 if key == 'job':
1228 gmDemographicsWidgets.edit_occupation()
1229 return
1230
1231 #============================================================
1232 # main
1233 #------------------------------------------------------------
1234 if __name__ == "__main__":
1235
1236 if len(sys.argv) < 2:
1237 sys.exit()
1238
1239 if sys.argv[1] != 'test':
1240 sys.exit()
1241
1242 # from Gnumed.pycommon import gmPG2
1243 # from Gnumed.pycommon import gmI18N
1244 # gmI18N.activate_locale()
1245 # gmI18N.install_domain()
1246
1247 #--------------------------------------------------------
1248 #test_org_unit_prw()
1249
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Feb 29 02:55:27 2020 | http://epydoc.sourceforge.net |