| 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 list_items = []
226 list_data = []
227
228 emr = patient.emr
229 most_recent = emr.get_most_recent_results(no_of_results = 1)
230 if most_recent is None:
231 self._LCTRL_results.set_string_items(items = [])
232 self._LCTRL_results.set_data(data = [])
233 return
234
235 now = gmDateTime.pydt_now_here()
236 list_items.append(_('Latest: %s ago (%s %s%s%s%s)') % (
237 gmDateTime.format_interval_medically(now - most_recent['clin_when']),
238 most_recent['unified_abbrev'],
239 most_recent['unified_val'],
240 gmTools.coalesce(most_recent['val_unit'], '', ' %s'),
241 gmTools.coalesce(most_recent['abnormality_indicator'], '', ' %s'),
242 gmTools.bool2subst(most_recent['reviewed'], '', (' %s' % gmTools.u_writing_hand))
243 ))
244 list_data.append(most_recent)
245 most_recent_needs_red = False
246 if most_recent.is_considered_abnormal is True:
247 if most_recent['is_clinically_relevant']:
248 most_recent_needs_red = True
249
250 unsigned = emr.get_unsigned_results(order_by = "(trim(coalesce(abnormality_indicator), '') <> '') DESC NULLS LAST, unified_abbrev")
251 no_of_reds = 0
252 for result in unsigned:
253 if result['pk_test_result'] == most_recent['pk_test_result']:
254 continue
255 if result['abnormality_indicator'] is not None:
256 if result['abnormality_indicator'].strip() != '':
257 no_of_reds += 1
258 list_items.append(_('%s %s%s%s (%s ago, %s)') % (
259 result['unified_abbrev'],
260 result['unified_val'],
261 gmTools.coalesce(result['val_unit'], '', ' %s'),
262 gmTools.coalesce(result['abnormality_indicator'], '', ' %s'),
263 gmDateTime.format_interval_medically(gmDateTime.pydt_now_here() - result['clin_when']),
264 gmTools.u_writing_hand
265 ))
266 list_data.append(result)
267
268 self._LCTRL_results.set_string_items(items = list_items)
269 self._LCTRL_results.set_data(data = list_data)
270
271 if most_recent_needs_red:
272 self._LCTRL_results.SetItemTextColour(0, wx.Colour('RED'))
273 if no_of_reds > 0:
274 for idx in range(1, no_of_reds + 1):
275 self._LCTRL_results.SetItemTextColour(idx, wx.Colour('RED'))
276
277 #-----------------------------------------------------
280
281 #-----------------------------------------------------
283 # data = self._LCTRL_inbox.get_selected_item_data(only_one = True)
284 #
285 # if data is not None:
286 # # <ctrl> down ?
287 # if wx.GetKeyState(wx.WXK_CONTROL):
288 # if isinstance(data, gmProviderInbox.cInboxMessage):
289 # xxxxxxxxx
290 gmDispatcher.send(signal = 'display_widget', name = 'gmMeasurementsGridPlugin')
291 return
292
293 #-----------------------------------------------------
294 #-----------------------------------------------------
296 list_items = []
297 list_data = []
298 highlight_list = []
299 line_idx = -1
300
301 overdue_messages = patient.overdue_messages
302 if len(overdue_messages) > 0:
303 highlight_list.extend(range(len(overdue_messages)))
304 for msg in overdue_messages:
305 line_idx += 1
306 list_items.append(_('overdue %s: %s') % (
307 gmDateTime.format_interval_medically(msg['interval_due']),
308 gmTools.coalesce(msg['comment'], '?')
309 ))
310 list_data.append(msg)
311
312 for msg in patient.get_messages(order_by = 'due_date NULLS LAST, importance DESC, received_when DESC'):
313 # already displayed above ?
314 if msg['is_overdue']:
315 continue
316 # not relevant anymore ?
317 if msg['is_expired']:
318 continue
319 line_idx += 1
320 if msg['due_date'] is None:
321 label = '%s%s' % (
322 msg['l10n_type'],
323 gmTools.coalesce(msg['comment'], '', ': %s')
324 )
325 else:
326 label = _('due in %s%s') % (
327 gmDateTime.format_interval_medically(msg['interval_due']),
328 gmTools.coalesce(msg['comment'], '', ': %s')
329 )
330 list_items.append(label)
331 list_data.append(msg)
332
333 pk_enc = patient.emr.active_encounter['pk_encounter']
334 for hint in patient._get_dynamic_hints(pk_encounter = pk_enc):
335 line_idx += 1
336 list_items.append(hint['title'])
337 list_data.append(hint)
338 if hint['highlight_as_priority']:
339 highlight_list.append(line_idx)
340
341 hints = patient.suppressed_hints
342 if len(hints) > 0:
343 list_items.append((_("suppr'd (%s):") % len(hints)) + ' ' + ','.join([h['title'][:7] + gmTools.u_ellipsis for h in hints]))
344 list_data.append(_('Suppressed hints:\n') + '\n'.join(['%s: %s' % (hints.index(h) + 1, h['title']) for h in hints]))
345
346 self._LCTRL_inbox.set_string_items(items = list_items)
347 self._LCTRL_inbox.set_data(data = list_data)
348
349 for idx in highlight_list:
350 self._LCTRL_inbox.SetItemTextColour(idx, wx.Colour('RED'))
351
352 #-----------------------------------------------------
354 if isinstance(data, gmProviderInbox.cInboxMessage):
355 return data.format()
356
357 if isinstance(data, gmAutoHints.cDynamicHint):
358 return '%s\n\n%s%s\n\n%s %s' % (
359 data['title'],
360 gmTools.wrap(data['hint'], width = 50),
361 gmTools.wrap(gmTools.coalesce(data['recommendation'], '', '\n\n%s'), width = 50),
362 gmTools.wrap(gmTools.coalesce(data['url'], '', '%s\n\n'), width = 50),
363 data['source']
364 )
365
366 if isinstance(data, type('')):
367 return data
368
369 return None
370
371 #-----------------------------------------------------
373
374 data = self._LCTRL_inbox.get_selected_item_data(only_one = True)
375
376 # if it is a dynamic hint open the URL for that
377 if isinstance(data, gmAutoHints.cDynamicHint):
378 if data['url'] is not None:
379 gmNetworkTools.open_url_in_browser(data['url'])
380 return
381
382 # holding down <CTRL> when double-clicking an inbox
383 # item indicates the desire to delete it
384 # <ctrl> down ?
385 if wx.GetKeyState(wx.WXK_CONTROL):
386 # better safe than sorry: can only delete real inbox items
387 if data is None:
388 return
389 if not isinstance(data, gmProviderInbox.cInboxMessage):
390 return
391 delete_it = gmGuiHelpers.gm_show_question (
392 question = _('Do you really want to\ndelete this inbox message ?'),
393 title = _('Deleting inbox message')
394 )
395 if not delete_it:
396 return
397 gmProviderInbox.delete_inbox_message(inbox_message = data['pk_inbox_message'])
398 return
399
400 if data is None:
401 gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin')
402 return
403
404 if not isinstance(data, gmProviderInbox.cInboxMessage):
405 gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin')
406 return
407
408 gmDispatcher.send(signal = 'display_widget', name = 'gmProviderInboxPlugin', filter_by_active_patient = True)
409 return
410 #-----------------------------------------------------
411 #-----------------------------------------------------
413
414 list_items = []
415 list_data = []
416
417 # export area items
418 item_count = len(patient.export_area.items)
419 if item_count == 1:
420 list_items.append(_('Export area: 1 item'))
421 list_data.append('')
422 if item_count > 1:
423 list_items.append(_('Export area: %s items') % item_count)
424 list_data.append('')
425
426 doc_folder = patient.get_document_folder()
427
428 # unsigned docs first
429 docs = doc_folder.get_unsigned_documents()
430 no_of_unsigned = len(docs)
431 for doc in docs:
432 list_items.append('%s %s (%s)' % (
433 gmDateTime.pydt_strftime(doc['clin_when'], format = '%m/%Y', accuracy = gmDateTime.acc_months),
434 doc['l10n_type'],
435 gmTools.u_writing_hand
436 ))
437 list_data.append(doc)
438
439 # other, signed docs second
440 docs = doc_folder.get_documents(order_by = 'ORDER BY clin_when DESC', exclude_unsigned = True)
441 for doc in docs[:5]:
442 list_items.append('%s %s' % (
443 gmDateTime.pydt_strftime(doc['clin_when'], format = '%m/%Y', accuracy = gmDateTime.acc_months),
444 doc['l10n_type']
445 ))
446 list_data.append(doc)
447 if len(docs) > 5:
448 list_items.append(_('%s %s more not shown %s') % (
449 gmTools.u_ellipsis,
450 len(docs) - 5,
451 gmTools.u_ellipsis
452 ))
453 list_data.append('')
454
455 self._LCTRL_documents.set_string_items(items = list_items)
456 self._LCTRL_documents.set_data(data = list_data)
457
458 if no_of_unsigned > 0:
459 start_idx = 0
460 if item_count > 0:
461 start_idx = 1
462 end_idx = no_of_unsigned + start_idx
463 for idx in range(start_idx, end_idx):
464 self._LCTRL_documents.SetItemTextColour(idx, wx.Colour('RED'))
465 #-----------------------------------------------------
467 emr = gmPerson.gmCurrentPatient().emr
468
469 if isinstance(data, gmDocuments.cDocument):
470 return data.format()
471
472 return None
473 #-----------------------------------------------------
475 data = self._LCTRL_documents.get_selected_item_data(only_one = True)
476
477 if data is not None:
478 # <ctrl> down ?
479 if wx.GetKeyState(wx.WXK_CONTROL):
480 if isinstance(data, gmDocuments.cDocument):
481 if len(data.parts) > 0:
482 gmDocumentWidgets.display_document_part(parent = self, part = data.parts[0])
483 else:
484 gmDocumentWidgets.review_document(parent = self, document = data)
485 return
486
487 gmDispatcher.send(signal = 'display_widget', name = 'gmShowMedDocs')
488 return
489 #-----------------------------------------------------
490 #-----------------------------------------------------
492
493 emr = patient.emr
494
495 list_items = []
496 list_data = []
497
498 is_waiting = False
499 wlist = patient.get_waiting_list_entry()
500 if len(wlist) > 0:
501 is_waiting = True
502 list_items.append(_('Currently %s entries in waiting list') % len(wlist))
503 tt = []
504 for w in wlist:
505 tt.append('%s %s%s%s' % (
506 gmTools.u_triangular_bullet,
507 gmDateTime.format_interval_medically(w['waiting_time']),
508 gmTools.coalesce(w['waiting_zone'], '', ' in "%s"'),
509 gmTools.coalesce(w['comment'], '', ': %s')
510 ))
511 if len(tt) > 0:
512 tt = '\n'.join(tt)
513 else:
514 tt = None
515 list_data.append({'wlist': tt})
516
517 first = emr.get_first_encounter()
518 if first is not None:
519 list_items.append (
520 _('first (in GMd): %s, %s') % (
521 gmDateTime.pydt_strftime (
522 first['started'],
523 format = '%Y %b %d',
524 accuracy = gmDateTime.acc_days
525 ),
526 first['l10n_type']
527 )
528 )
529 list_data.append(first)
530
531 last = emr.get_last_but_one_encounter()
532 if last is not None:
533 list_items.append (
534 _('last: %s, %s') % (
535 gmDateTime.pydt_strftime (
536 last['started'],
537 format = '%Y %b %d',
538 accuracy = gmDateTime.acc_days
539 ),
540 last['l10n_type']
541 )
542 )
543 list_data.append(last)
544
545 encs = emr.get_encounter_stats_by_type()
546 for enc in encs:
547 item = ' %s x %s' % (enc['frequency'], enc['l10n_type'])
548 list_items.append(item)
549 list_data.append(item)
550
551 stays = emr.get_hospital_stay_stats_by_hospital()
552 for stay in stays:
553 item = ' %s x %s' % (
554 stay['frequency'],
555 stay['hospital']
556 )
557 list_items.append(item)
558 list_data.append({'stay': item})
559
560 self._LCTRL_encounters.set_string_items(items = list_items)
561 self._LCTRL_encounters.set_data(data = list_data)
562 if is_waiting:
563 self._LCTRL_encounters.SetItemTextColour(0, wx.Colour('RED'))
564
565 #-----------------------------------------------------
567 emr = gmPerson.gmCurrentPatient().emr
568
569 if isinstance(data, gmEMRStructItems.cEncounter):
570 return data.format (
571 with_vaccinations = False,
572 with_tests = False,
573 with_docs = False,
574 with_co_encountlet_hints = True,
575 with_rfe_aoe = True
576 )
577
578 if type(data) is dict:
579 key, val = list(data.items())[0]
580 if key == 'wlist':
581 return val
582 if key == 'stay':
583 return None
584
585 return data
586 #-----------------------------------------------------
588 data = self._LCTRL_encounters.get_selected_item_data(only_one = True)
589 if data is not None:
590 # <ctrl> down ?
591 if wx.GetKeyState(wx.WXK_CONTROL):
592 if isinstance(data, gmEMRStructItems.cEncounter):
593 gmEncounterWidgets.edit_encounter(parent = self, encounter = data)
594 return
595
596 if type(data) is dict:
597 key, val = list(data.items())[0]
598 if key == 'wlist':
599 gmDispatcher.send(signal = 'display_widget', name = 'gmWaitingListPlugin')
600 return
601 if key == 'stay':
602 wx.CallAfter(gmHospitalStayWidgets.manage_hospital_stays, parent = self)
603 return
604
605 wx.CallAfter(gmEncounterWidgets.manage_encounters, parent = self, ignore_OK_button = False)
606
607 #-----------------------------------------------------
608 #-----------------------------------------------------
610 emr = patient.emr
611
612 sort_key_list = []
613 date_format4sorting = '%Y %m %d %H %M %S'
614 now = gmDateTime.pydt_now_here()
615 data = {}
616
617 # undated entries
618 # pregnancy
619 edc = emr.EDC
620 if edc is not None:
621 sort_key = '99999 edc'
622 if emr.EDC_is_fishy:
623 label = _('EDC (!?!): %s') % gmDateTime.pydt_strftime(edc, format = '%Y %b %d')
624 tt = _(
625 'The Expected Date of Confinement is rather questionable.\n'
626 '\n'
627 'Please check patient age, patient gender, time until/since EDC.'
628 )
629 else:
630 label = _('EDC: %s') % gmDateTime.pydt_strftime(edc, format = '%Y %b %d')
631 tt = ''
632 sort_key_list.append(sort_key)
633 data[sort_key] = [label, tt]
634
635 # family history
636 fhxs = emr.get_family_history()
637 for fhx in fhxs:
638 sort_key = '99998 %s::%s' % (fhx['l10n_relation'], fhx['pk_family_history'])
639 sort_key_list.append(sort_key)
640 #gmDateTime.pydt_strftime(fhx['when_known_to_patient'], format = '%Y %m %d %H %M %S')
641 label = '%s%s: %s' % (fhx['l10n_relation'], gmTools.coalesce(fhx['age_noted'], '', ' (@ %s)'), fhx['condition'])
642 data[sort_key] = [label, fhx]
643 del fhxs
644
645 # dated entries
646 issues = [
647 i for i in emr.get_health_issues()
648 if ((i['clinically_relevant'] is False) or (i['is_active'] is False))
649 ]
650 for issue in issues:
651 last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
652 linked_encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
653 when_candidates = [issue['modified_when'], linked_encounter['last_affirmed']]
654 if last_encounter is not None:
655 when_candidates.append(last_encounter['last_affirmed'])
656 if (patient['dob'] is not None) and (issue['age_noted'] is not None):
657 when_candidates.append(patient['dob'] + issue['age_noted'])
658 if issue['is_active']:
659 # sort active issues by time of most recent clinical access, which
660 # means the most recent of:
661 # issue.modified_when
662 # last_encounter.last_affirmed
663 # linked_encounter.last_affirmed
664 # dob + age
665 relevant_date = max(when_candidates)
666 else:
667 # sort IN-active issues by best guess of real clinical start
668 # means either:
669 # - dob + age
670 # or the earliest of:
671 # - issue.modified_when
672 # - last_encounter.last_affirmed
673 # - linked_encounter.last_affirmed
674 if (patient['dob'] is not None) and (issue['age_noted'] is not None):
675 relevant_date = patient['dob'] + issue['age_noted']
676 else:
677 relevant_date = min(when_candidates)
678 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(relevant_date, format = date_format4sorting), issue['pk_health_issue'])
679 relevant_date_str = gmDateTime.pydt_strftime(relevant_date, format = '%Y %b')
680 if issue['age_noted'] is None:
681 encounter = gmEMRStructItems.cEncounter(issue['pk_encounter'])
682 age = _(' (entered %s ago)') % gmDateTime.format_interval_medically(now - encounter['started'])
683 else:
684 age = ' (@ %s)' % gmDateTime.format_interval_medically(issue['age_noted'])
685 sort_key_list.append(sort_key)
686 data[sort_key] = ['%s %s%s' % (relevant_date_str, issue['description'], age), issue]
687 del issues
688
689 stays = emr.get_hospital_stays()
690 for stay in stays:
691 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(stay['admission'], format = date_format4sorting), stay['pk_hospital_stay'])
692 label = '%s %s: %s (%s)' % (
693 gmDateTime.pydt_strftime(stay['admission'], format = '%Y %b'),
694 stay['hospital'],
695 stay['episode'],
696 _('%s ago') % gmDateTime.format_interval_medically(now - stay['admission'])
697 )
698 sort_key_list.append(sort_key)
699 data[sort_key] = [label, stay]
700 del stays
701
702 procs = emr.get_performed_procedures()
703 for proc in procs:
704 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(proc['clin_when'], format = date_format4sorting), proc['pk_procedure'])
705 label = '%s%s %s (%s @ %s)' % (
706 gmDateTime.pydt_strftime(proc['clin_when'], format = '%Y %b'),
707 gmTools.bool2subst(proc['is_ongoing'], gmTools.u_ellipsis, '', ''),
708 proc['performed_procedure'],
709 _('%s ago') % gmDateTime.format_interval_medically(now - proc['clin_when']),
710 gmDateTime.format_interval_medically(proc['clin_when'] - patient['dob'])
711 )
712 sort_key_list.append(sort_key)
713 data[sort_key] = [label, proc]
714 del procs
715
716 vaccs = emr.get_latest_vaccinations()
717 for ind, tmp in vaccs.items():
718 no_of_shots, vacc = tmp
719 sort_key = '%s::%s::%s' % (gmDateTime.pydt_strftime(vacc['date_given'], format = date_format4sorting), vacc['pk_vaccination'], ind)
720 label = _('%s Vacc: %s (latest of %s: %s ago)') % (
721 gmDateTime.pydt_strftime(vacc['date_given'], format = '%Y %b'),
722 ind,
723 no_of_shots,
724 gmDateTime.format_interval_medically(now - vacc['date_given'])
725 )
726 sort_key_list.append(sort_key)
727 data[sort_key] = [label, vacc]
728 del vaccs
729
730 for abuse in [ a for a in emr.abused_substances if a['harmful_use_type'] == 3 ]:
731 sort_key = '%s::%s' % (gmDateTime.pydt_strftime(abuse['last_checked_when'], format = date_format4sorting), abuse['substance'])
732 label = _('Hx of addiction: %s') % abuse['substance']
733 sort_key_list.append(sort_key)
734 data[sort_key] = [label, abuse]
735
736 sort_key_list.sort()
737 sort_key_list.reverse()
738 list_items = []
739 list_data = []
740 for key in sort_key_list:
741 label, item = data[key]
742 list_items.append(label)
743 list_data.append(item)
744
745 self._LCTRL_history.set_string_items(items = list_items)
746 self._LCTRL_history.set_data(data = list_data)
747
748 #-----------------------------------------------------
750
751 if isinstance(data, gmEMRStructItems.cHealthIssue):
752 return data.format (
753 patient = gmPerson.gmCurrentPatient(),
754 with_medications = False,
755 with_hospital_stays = False,
756 with_procedures = False,
757 with_family_history = False,
758 with_documents = False,
759 with_tests = False,
760 with_vaccinations = False
761 ).strip('\n')
762
763 if isinstance(data, gmMedication.cSubstanceIntakeEntry):
764 return data.format(single_line = False)
765
766 if isinstance(data, gmFamilyHistory.cFamilyHistory):
767 return data.format(include_episode = True, include_comment = True)
768
769 if isinstance(data, gmEMRStructItems.cHospitalStay):
770 return data.format()
771
772 if isinstance(data, gmEMRStructItems.cPerformedProcedure):
773 return data.format(include_episode = True, include_codes = False, include_address = True, include_comm = True)
774
775 if isinstance(data, gmVaccination.cVaccination):
776 return '\n'.join(data.format (
777 with_indications = True,
778 with_comment = True,
779 with_reaction = True,
780 date_format = '%Y %b %d'
781 ))
782
783 # EDC
784 if isinstance(data, str):
785 if data == '':
786 return None
787 return data
788
789 return None
790
791 #-----------------------------------------------------
793 data = self._LCTRL_history.get_selected_item_data(only_one = True)
794 if data is None:
795 return
796
797 if isinstance(data, str):
798 gmPregWidgets.calculate_edc(parent = self, patient = gmPerson.gmCurrentPatient())
799 return
800
801 # <ctrl> down ?
802 if wx.GetKeyState(wx.WXK_CONTROL):
803 if isinstance(data, gmEMRStructItems.cHealthIssue):
804 gmEMRStructWidgets.edit_health_issue(parent = self, issue = data)
805 return
806 if isinstance(data, gmFamilyHistory.cFamilyHistory):
807 FamilyHistoryWidgets.edit_family_history(parent = self, family_history = data)
808 return
809 if isinstance(data, gmEMRStructItems.cHospitalStay):
810 gmHospitalStayWidgets.edit_hospital_stay(parent = self, hospital_stay = data)
811 return
812 if isinstance(data, gmEMRStructItems.cPerformedProcedure):
813 gmProcedureWidgets.edit_procedure(parent = self, procedure = data)
814 return
815 if isinstance(data, gmVaccination.cVaccination):
816 gmVaccWidgets.edit_vaccination(parent = self, vaccination = data, single_entry = True)
817 return
818 return
819
820 if isinstance(data, gmEMRStructItems.cHealthIssue):
821 gmDispatcher.send(signal = 'display_widget', name = 'gmEMRBrowserPlugin')
822 return
823 if isinstance(data, gmFamilyHistory.cFamilyHistory):
824 FamilyHistoryWidgets.manage_family_history(parent = self)
825 return
826 if isinstance(data, gmEMRStructItems.cHospitalStay):
827 gmHospitalStayWidgets.manage_hospital_stays(parent = self)
828 return
829 if isinstance(data, gmEMRStructItems.cPerformedProcedure):
830 gmProcedureWidgets.manage_performed_procedures(parent = self)
831 return
832 if isinstance(data, gmVaccination.cVaccination):
833 gmVaccWidgets.manage_vaccinations(parent = self)
834 return
835
836 return
837 #-----------------------------------------------------
838 #-----------------------------------------------------
840
841 emr = patient.emr
842
843 list_items = []
844 data_items = []
845 first_red = False
846
847 # harmful substance use ?
848 abuses = emr.abused_substances
849 if len([ a for a in abuses if a['harmful_use_type'] in [1, 2] ]) > 0:
850 list_items.append(_('active substance abuse'))
851 data_items.append('\n'.join([ a.format(left_margin=0, date_format='%Y %b %d', single_line=True) for a in abuses ]))
852
853 # list by product or substance:
854 intakes = emr.get_current_medications(include_inactive = False, include_unapproved = True, order_by = 'substance')
855 multi_products_already_seen = []
856 for intake in intakes:
857 drug = intake.containing_drug
858 if len(drug['components']) == 1:
859 list_items.append(_('%s %s%s%s') % (
860 intake['substance'],
861 intake['amount'],
862 intake.formatted_units,
863 gmTools.coalesce(intake['schedule'], '', ': %s')
864 ))
865 data_items.append(intake)
866 else:
867 if intake['product'] in multi_products_already_seen:
868 continue
869 multi_products_already_seen.append(intake['product'])
870 list_items.append(_('%s %s%s') % (
871 intake['product'],
872 drug['l10n_preparation'],
873 gmTools.coalesce(intake['schedule'], '', ': %s')
874 ))
875 data_items.append(intake)
876
877 self._LCTRL_meds.set_string_items(items = list_items)
878 self._LCTRL_meds.set_data(data = data_items)
879
880 if first_red:
881 self._LCTRL_meds.SetItemTextColour(0, wx.Colour('RED'))
882
883 #-----------------------------------------------------
885 if isinstance(data, str):
886 return data
887 emr = gmPerson.gmCurrentPatient().emr
888 atcs = []
889 if data['atc_substance'] is not None:
890 atcs.append(data['atc_substance'])
891 # if data['atc_drug'] is not None:
892 # atcs.append(data['atc_drug'])
893 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (data['substance'],), drug = data['product'])
894 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (data['substance'],))
895 if allg is False:
896 allg = None
897 return data.format(single_line = False, allergy = allg, show_all_product_components = True)
898
899 #-----------------------------------------------------
901 data = self._LCTRL_meds.get_selected_item_data(only_one = True)
902
903 if data is None:
904 return
905
906 # if isinstance(data, str):
907 # gmHabitWidgets.manage_substance_abuse(parent = self, patient = gmPerson.gmCurrentPatient())
908 # return
909
910 # <ctrl> down ? -> edit
911 if wx.GetKeyState(wx.WXK_CONTROL):
912 wx.CallAfter(gmMedicationWidgets.edit_intake_of_substance, parent = self, substance = data)
913 return
914
915 gmDispatcher.send(signal = 'display_widget', name = 'gmCurrentSubstancesPlugin')
916
917 #-----------------------------------------------------
918 #-----------------------------------------------------
920 emr = patient.emr
921
922 list_items = []
923 list_data = []
924 is_in_hospital = False
925
926 stays = emr.get_hospital_stays(ongoing_only = True)
927 if len(stays) > 0:
928 list_items.append(_('** Currently hospitalized: %s **') % stays[0]['hospital'])
929 list_data.append(stays[0])
930 is_in_hospital = True
931
932 adrs = patient.get_addresses()
933 for adr in adrs:
934 list_items.append(adr.format(single_line = True, verbose = False, show_type = True))
935 list_data.append(adr)
936
937 comms = patient.get_comm_channels()
938 for comm in comms:
939 list_items.append('%s: %s%s' % (
940 comm['l10n_comm_type'],
941 comm['url'],
942 gmTools.coalesce(comm['comment'], '', ' (%s)')
943 ))
944 list_data.append(comm)
945
946 ident = patient.emergency_contact_in_database
947 if ident is not None:
948 list_items.append(_('emergency: %s') % ident['description_gender'])
949 list_data.append(ident)
950
951 if patient['emergency_contact'] is not None:
952 list_items.append(_('emergency: %s') % patient['emergency_contact'].split('\n')[0])
953 list_data.append(patient['emergency_contact'])
954
955 provider = patient.primary_provider
956 if provider is not None:
957 list_items.append(_('in-praxis: %s') % patient.primary_provider_identity.get_description_gender(with_nickname = False))
958 list_data.append(provider)
959
960 for item in emr.external_care_items:
961 list_items.append(_('care: %s%s@%s') % (
962 gmTools.coalesce(item['provider'], '', '%s, '),
963 item['unit'],
964 item['organization']
965 ))
966 list_data.append(item)
967
968 self._LCTRL_contacts.set_string_items(items = list_items)
969 self._LCTRL_contacts.set_data(data = list_data)
970 if is_in_hospital:
971 self._LCTRL_contacts.SetItemTextColour(0, wx.Colour('RED'))
972
973 #-----------------------------------------------------
975
976 if isinstance(data, gmEMRStructItems.cHospitalStay):
977 return data.format()
978
979 if isinstance(data, gmExternalCare.cExternalCareItem):
980 return '\n'.join(data.format (
981 with_health_issue = True,
982 with_address = True,
983 with_comms = True
984 ))
985
986 if isinstance(data, gmDemographicRecord.cPatientAddress):
987 return '\n'.join(data.format())
988
989 if isinstance(data, gmDemographicRecord.cCommChannel):
990 parts = []
991 if data['is_confidential']:
992 parts.append(_('*** CONFIDENTIAL ***'))
993 if data['comment'] is not None:
994 parts.append(data['comment'])
995 return '\n'.join(parts)
996
997 if isinstance(data, gmPerson.cPerson):
998 return '%s\n\n%s' % (
999 data['description_gender'],
1000 '\n'.join([
1001 '%s: %s%s' % (
1002 c['l10n_comm_type'],
1003 c['url'],
1004 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), '', '')
1005 )
1006 for c in data.get_comm_channels()
1007 ])
1008 )
1009
1010 if isinstance(data, str):
1011 return data
1012
1013 if isinstance(data, gmStaff.cStaff):
1014 ident = data.identity
1015 return '%s: %s\n\n%s%s' % (
1016 data['short_alias'],
1017 ident['description_gender'],
1018 '\n'.join([
1019 '%s: %s%s' % (
1020 c['l10n_comm_type'],
1021 c['url'],
1022 gmTools.bool2subst(c['is_confidential'], _(' (confidential !)'), '', '')
1023 )
1024 for c in ident.get_comm_channels()
1025 ]),
1026 gmTools.coalesce(data['comment'], '', '\n\n%s')
1027 )
1028
1029 return None
1030
1031 #-----------------------------------------------------
1033 data = self._LCTRL_contacts.get_selected_item_data(only_one = True)
1034 if data is not None:
1035 # <ctrl> down ?
1036 if wx.GetKeyState(wx.WXK_CONTROL):
1037 if isinstance(data, gmEMRStructItems.cHospitalStay):
1038 gmHospitalStayWidgets.edit_hospital_stay(parent = self, hospital_stay = data)
1039 return
1040 if isinstance(data, gmDemographicRecord.cPatientAddress):
1041 pass
1042 if isinstance(data, gmDemographicRecord.cCommChannel):
1043 gmContactWidgets.edit_comm_channel(parent = self, comm_channel = data, channel_owner = gmPerson.gmCurrentPatient())
1044 return
1045 if isinstance(data, gmPerson.cPerson):
1046 pass
1047 if isinstance(data, gmStaff.cStaff):
1048 pass
1049
1050 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1051
1052 #-----------------------------------------------------
1053 #-----------------------------------------------------
1055 emr = patient.emr
1056
1057 problems = [
1058 p for p in emr.get_problems(include_closed_episodes = False, include_irrelevant_issues = False)
1059 if p['problem_active']
1060 ]
1061
1062 list_items = []
1063 list_data = []
1064 for problem in problems:
1065 if problem['type'] == 'issue':
1066 issue = emr.problem2issue(problem)
1067 last_encounter = emr.get_last_encounter(issue_id = issue['pk_health_issue'])
1068 if last_encounter is None:
1069 last = issue['modified_when'].strftime('%m/%Y')
1070 else:
1071 last = last_encounter['last_affirmed'].strftime('%m/%Y')
1072 list_items.append('%s: %s' % (problem['problem'], last))
1073 elif problem['type'] == 'episode':
1074 epi = emr.problem2episode(problem)
1075 last_encounter = emr.get_last_encounter(episode_id = epi['pk_episode'])
1076 if last_encounter is None:
1077 last = epi['episode_modified_when'].strftime('%m/%Y')
1078 else:
1079 last = last_encounter['last_affirmed'].strftime('%m/%Y')
1080 list_items.append('%s: %s' % (problem['problem'], last))
1081 list_data.append(problem)
1082
1083 care = emr.get_external_care_items(exclude_inactive = True)
1084 for item in care:
1085 # skip those already-shown(-or-not)
1086 if item['pk_health_issue'] is not None:
1087 continue
1088 list_items.append(_('extrnl: %s (%s@%s)') % (
1089 item['issue'],
1090 item['unit'],
1091 item['organization']
1092 ))
1093 list_data.append(item)
1094
1095 self._LCTRL_problems.set_string_items(items = list_items)
1096 self._LCTRL_problems.set_data(data = list_data)
1097
1098 #-----------------------------------------------------
1100
1101 if isinstance(data, gmExternalCare.cExternalCareItem):
1102 return '\n'.join(data.format (
1103 with_health_issue = True,
1104 with_address = True,
1105 with_comms = True
1106 ))
1107
1108 emr = gmPerson.gmCurrentPatient().emr
1109
1110 if data['type'] == 'issue':
1111 issue = emr.problem2issue(data)
1112 tt = issue.format (
1113 patient = gmPerson.gmCurrentPatient(),
1114 with_medications = False,
1115 with_hospital_stays = False,
1116 with_procedures = False,
1117 with_family_history = False,
1118 with_documents = False,
1119 with_tests = False,
1120 with_vaccinations = False
1121 ).strip('\n')
1122 return tt
1123
1124 if data['type'] == 'episode':
1125 epi = emr.problem2episode(data)
1126 tt = epi.format (
1127 patient = gmPerson.gmCurrentPatient(),
1128 with_encounters = False,
1129 with_hospital_stays = False,
1130 with_procedures = False,
1131 with_family_history = False,
1132 with_documents = False,
1133 with_tests = False,
1134 with_vaccinations = False,
1135 with_health_issue = True
1136 ).strip('\n')
1137 return tt
1138
1139 return None
1140
1141 #-----------------------------------------------------
1143 data = self._LCTRL_problems.get_selected_item_data(only_one = True)
1144 if data is not None:
1145 # <ctrl> down ?
1146 if wx.GetKeyState(wx.WXK_CONTROL):
1147 emr = gmPerson.gmCurrentPatient().emr
1148 if data['type'] == 'issue':
1149 gmEMRStructWidgets.edit_health_issue(parent = self, issue = emr.problem2issue(data))
1150 return
1151 if data['type'] == 'episode':
1152 gmEMRStructWidgets.edit_episode(parent = self, episode = emr.problem2episode(data))
1153 return
1154
1155 gmDispatcher.send(signal = 'display_widget', name = 'gmEMRBrowserPlugin')
1156
1157 #-----------------------------------------------------
1158 #-----------------------------------------------------
1160 # names (.comment -> tooltip)
1161 names = patient.get_names(exclude_active = True)
1162 items = [
1163 _('aka: %(last)s, %(first)s%(nick)s') % {
1164 'last': n['lastnames'],
1165 'first': n['firstnames'],
1166 'nick': gmTools.coalesce(n['preferred'], '', " '%s'")
1167 } for n in names
1168 ]
1169 data = names
1170
1171 # IDs (.issuer & .comment -> tooltip)
1172 ids = patient.external_ids
1173 for i in ids:
1174 items.append('%s: %s' % (i['name'], i['value']))
1175 data.append({'id': i})
1176
1177 # occupation
1178 jobs = patient.get_occupations()
1179 for j in jobs:
1180 items.append(_('job: %s (%s)') % (
1181 j['l10n_occupation'],
1182 j['modified_when'].strftime('%m/%Y')
1183 ))
1184 data.append({'job': j})
1185
1186 self._LCTRL_identity.set_string_items(items = items)
1187 self._LCTRL_identity.set_data(data = data)
1188
1189 #-----------------------------------------------------
1191 if isinstance(data, gmPerson.cPersonName):
1192 return data['comment']
1193 if isinstance(data, dict):
1194 key = list(data.keys())[0]
1195 val = data[key]
1196 if key == 'id':
1197 return _('issued by: %s%s') % (
1198 val['issuer'],
1199 gmTools.coalesce(val['comment'], '', '\n\n%s')
1200 )
1201 if key == 'job':
1202 tt = _('Last modified: %s') % val['modified_when'].strftime('%m/%Y')
1203 if val['activities'] is None:
1204 return tt
1205 return tt + ('\n\n' + _('Activities:\n\n%s') % val['activities'])
1206
1207 return None
1208
1209 #-----------------------------------------------------
1211 data = self._LCTRL_identity.get_selected_item_data(only_one = True)
1212 if data is None:
1213 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1214
1215 # <ctrl> down ?
1216 if not wx.GetKeyState(wx.WXK_CONTROL):
1217 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
1218
1219 # <ctrl> down !
1220 if isinstance(data, gmPerson.cPersonName):
1221 ea = gmDemographicsWidgets.cPersonNameEAPnl(self, -1, name = data)
1222 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1223 dlg.SetTitle(_('Cloning name'))
1224 dlg.ShowModal()
1225 return
1226
1227 if isinstance(data, dict):
1228 key = list(data.keys())[0]
1229 val = data[key]
1230 if key == 'id':
1231 ea = gmDemographicsWidgets.cExternalIDEditAreaPnl(self, -1, external_id = val)
1232 ea.id_holder = gmPerson.gmCurrentPatient()
1233 dlg = gmEditArea.cGenericEditAreaDlg2(self, -1, edit_area = ea, single_entry = True)
1234 dlg.SetTitle(_('Editing external ID'))
1235 dlg.ShowModal()
1236 return
1237 if key == 'job':
1238 gmDemographicsWidgets.edit_occupation()
1239 return
1240
1241 #============================================================
1242 # main
1243 #------------------------------------------------------------
1244 if __name__ == "__main__":
1245
1246 if len(sys.argv) < 2:
1247 sys.exit()
1248
1249 if sys.argv[1] != 'test':
1250 sys.exit()
1251
1252 # from Gnumed.pycommon import gmPG2
1253 # from Gnumed.pycommon import gmI18N
1254 # gmI18N.activate_locale()
1255 # gmI18N.install_domain()
1256
1257 #--------------------------------------------------------
1258 #test_org_unit_prw()
1259
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu May 10 01:55:20 2018 | http://epydoc.sourceforge.net |