Package Gnumed :: Package wxpython :: Module gmPatOverviewWidgets
[frames] | no frames]

Source Code for Module Gnumed.wxpython.gmPatOverviewWidgets

   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
57 - def __init__(self, *args, **kwargs):
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 #--------------------------------------------------------
67 - def __init_ui(self):
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 #--------------------------------------------------------
111 - def __reset_ui_content(self):
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 #-----------------------------------------------------
127 - def __register_interests(self):
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 #--------------------------------------------------------
156 - def _on_post_patient_selection(self):
157 self._schedule_data_reget()
158 159 #--------------------------------------------------------
160 - def _on_database_signal(self, **kwds):
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 #-----------------------------------------------------
201 - def _populate_with_data(self):
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 #-----------------------------------------------------
224 - def __refresh_results(self, patient=None):
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 #-----------------------------------------------------
278 - def _calc_results_list_item_tooltip(self, data):
279 return data.format()
280 281 #-----------------------------------------------------
282 - def _on_result_activated(self, event):
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 #-----------------------------------------------------
295 - def __refresh_inbox(self, patient=None):
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 #-----------------------------------------------------
353 - def _calc_inbox_item_tooltip(self, data):
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 #-----------------------------------------------------
372 - def _on_inbox_item_activated(self, event):
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 #-----------------------------------------------------
412 - def __refresh_documents(self, patient=None):
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 #-----------------------------------------------------
466 - def _calc_documents_list_item_tooltip(self, data):
467 emr = gmPerson.gmCurrentPatient().emr 468 469 if isinstance(data, gmDocuments.cDocument): 470 return data.format() 471 472 return None
473 #-----------------------------------------------------
474 - def _on_document_activated(self, event):
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 #-----------------------------------------------------
491 - def __refresh_encounters(self, patient=None):
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 #-----------------------------------------------------
566 - def _calc_encounters_list_item_tooltip(self, data):
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 #-----------------------------------------------------
587 - def _on_encounter_activated(self, event):
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 #-----------------------------------------------------
609 - def __refresh_history(self, patient=None):
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 #-----------------------------------------------------
749 - def _calc_history_list_item_tooltip(self, data):
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 #-----------------------------------------------------
792 - def _on_history_item_activated(self, event):
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 #-----------------------------------------------------
839 - def __refresh_meds(self, patient=None):
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 #-----------------------------------------------------
884 - def _calc_meds_list_item_tooltip(self, data):
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 #-----------------------------------------------------
900 - def _on_meds_item_activated(self, event):
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 #-----------------------------------------------------
919 - def __refresh_contacts(self, patient=None):
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 #-----------------------------------------------------
974 - def _calc_contacts_list_item_tooltip(self, data):
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 #-----------------------------------------------------
1032 - def _on_contacts_item_activated(self, event):
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 #-----------------------------------------------------
1054 - def __refresh_problems(self, patient=None):
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 #-----------------------------------------------------
1099 - def _calc_problem_list_item_tooltip(self, data):
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 #-----------------------------------------------------
1142 - def _on_problem_activated(self, event):
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 #-----------------------------------------------------
1159 - def __refresh_identity(self, patient=None):
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 #-----------------------------------------------------
1190 - def _calc_identity_item_tooltip(self, data):
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 #-----------------------------------------------------
1210 - def _on_identity_item_activated(self, event):
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