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

Source Code for Module Gnumed.wxpython.gmMedicationWidgets

   1  """GNUmed medication/substances handling widgets. 
   2  """ 
   3  #================================================================ 
   4  __version__ = "$Revision: 1.33 $" 
   5  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
   6   
   7  import logging, sys, os.path, decimal 
   8   
   9   
  10  import wx, wx.grid 
  11   
  12   
  13  if __name__ == '__main__': 
  14          sys.path.insert(0, '../../') 
  15  from Gnumed.pycommon import gmDispatcher, gmCfg, gmShellAPI, gmTools, gmDateTime 
  16  from Gnumed.pycommon import gmMatchProvider, gmI18N, gmPrinting, gmCfg2, gmNetworkTools 
  17  from Gnumed.business import gmPerson, gmATC, gmSurgery, gmMedication, gmForms, gmStaff 
  18  from Gnumed.wxpython import gmGuiHelpers, gmRegetMixin, gmAuthWidgets, gmEditArea, gmMacro 
  19  from Gnumed.wxpython import gmCfgWidgets, gmListWidgets, gmPhraseWheel, gmFormWidgets 
  20  from Gnumed.wxpython import gmAllergyWidgets 
  21   
  22   
  23  _log = logging.getLogger('gm.ui') 
  24  _log.info(__version__) 
  25   
  26  #============================================================ 
  27  # generic drug database access 
  28  #============================================================ 
29 -def configure_drug_data_source(parent=None):
30 gmCfgWidgets.configure_string_from_list_option ( 31 parent = parent, 32 message = _( 33 '\n' 34 'Please select the default drug data source from the list below.\n' 35 '\n' 36 'Note that to actually use it you need to have the database installed, too.' 37 ), 38 option = 'external.drug_data.default_source', 39 bias = 'user', 40 default_value = None, 41 choices = gmMedication.drug_data_source_interfaces.keys(), 42 columns = [_('Drug data source')], 43 data = gmMedication.drug_data_source_interfaces.keys(), 44 caption = _('Configuring default drug data source') 45 )
46 #============================================================
47 -def get_drug_database(parent = None):
48 dbcfg = gmCfg.cCfgSQL() 49 50 # load from option 51 default_db = dbcfg.get2 ( 52 option = 'external.drug_data.default_source', 53 workplace = gmSurgery.gmCurrentPractice().active_workplace, 54 bias = 'workplace' 55 ) 56 57 # not configured -> try to configure 58 if default_db is None: 59 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True) 60 configure_drug_data_source(parent = parent) 61 default_db = dbcfg.get2 ( 62 option = 'external.drug_data.default_source', 63 workplace = gmSurgery.gmCurrentPractice().active_workplace, 64 bias = 'workplace' 65 ) 66 # still not configured -> return 67 if default_db is None: 68 gmGuiHelpers.gm_show_error ( 69 aMessage = _('There is no default drug database configured.'), 70 aTitle = _('Jumping to drug database') 71 ) 72 return None 73 74 # now it MUST be configured (either newly or previously) 75 # but also *validly* ? 76 try: 77 drug_db = gmMedication.drug_data_source_interfaces[default_db]() 78 except KeyError: 79 # not valid 80 _log.error('faulty default drug data source configuration: %s', default_db) 81 # try to configure 82 configure_drug_data_source(parent = parent) 83 default_db = dbcfg.get2 ( 84 option = 'external.drug_data.default_source', 85 workplace = gmSurgery.gmCurrentPractice().active_workplace, 86 bias = 'workplace' 87 ) 88 # deconfigured or aborted (and thusly still misconfigured) ? 89 try: 90 drug_db = gmMedication.drug_data_source_interfaces[default_db]() 91 except KeyError: 92 _log.error('still faulty default drug data source configuration: %s', default_db) 93 return None 94 95 pat = gmPerson.gmCurrentPatient() 96 if pat.connected: 97 drug_db.patient = pat 98 99 return drug_db
100 #============================================================
101 -def jump_to_drug_database():
102 dbcfg = gmCfg.cCfgSQL() 103 drug_db = get_drug_database() 104 if drug_db is None: 105 return 106 drug_db.switch_to_frontend(blocking = False)
107 108 #============================================================
109 -def jump_to_ifap(import_drugs=False):
110 111 dbcfg = gmCfg.cCfgSQL() 112 113 ifap_cmd = dbcfg.get2 ( 114 option = 'external.ifap-win.shell_command', 115 workplace = gmSurgery.gmCurrentPractice().active_workplace, 116 bias = 'workplace', 117 default = 'wine "C:\Ifapwin\WIAMDB.EXE"' 118 ) 119 found, binary = gmShellAPI.detect_external_binary(ifap_cmd) 120 if not found: 121 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd) 122 return False 123 ifap_cmd = binary 124 125 if import_drugs: 126 transfer_file = os.path.expanduser(dbcfg.get2 ( 127 option = 'external.ifap-win.transfer_file', 128 workplace = gmSurgery.gmCurrentPractice().active_workplace, 129 bias = 'workplace', 130 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv' 131 )) 132 # file must exist for Ifap to write into it 133 try: 134 f = open(transfer_file, 'w+b').close() 135 except IOError: 136 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file) 137 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file) 138 return False 139 140 wx.BeginBusyCursor() 141 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs) 142 wx.EndBusyCursor() 143 144 if import_drugs: 145 # COMMENT: this file must exist PRIOR to invoking IFAP 146 # COMMENT: or else IFAP will not write data into it ... 147 try: 148 csv_file = open(transfer_file, 'rb') # FIXME: encoding 149 except: 150 _log.exception('cannot access [%s]', fname) 151 csv_file = None 152 153 if csv_file is not None: 154 import csv 155 csv_lines = csv.DictReader ( 156 csv_file, 157 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(), 158 delimiter = ';' 159 ) 160 pat = gmPerson.gmCurrentPatient() 161 emr = pat.get_emr() 162 # dummy episode for now 163 epi = emr.add_episode(episode_name = _('Current medication')) 164 for line in csv_lines: 165 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 166 line['Packungszahl'].strip(), 167 line['Handelsname'].strip(), 168 line['Form'].strip(), 169 line[u'Packungsgr\xf6\xdfe'].strip(), 170 line['Abpackungsmenge'].strip(), 171 line['Einheit'].strip(), 172 line['Hersteller'].strip(), 173 line['PZN'].strip() 174 ) 175 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi) 176 csv_file.close() 177 178 return True
179 180 #============================================================ 181 # ATC related widgets 182 #============================================================ 183
184 -def browse_atc_reference(parent=None):
185 186 if parent is None: 187 parent = wx.GetApp().GetTopWindow() 188 #------------------------------------------------------------ 189 def refresh(lctrl): 190 atcs = gmATC.get_reference_atcs() 191 192 items = [ [ 193 a['atc'], 194 a['term'], 195 u'%s' % gmTools.coalesce(a['ddd'], u''), 196 gmTools.coalesce(a['unit'], u''), 197 gmTools.coalesce(a['administrative_route'], u''), 198 gmTools.coalesce(a['comment'], u''), 199 a['version'], 200 a['lang'] 201 ] for a in atcs ] 202 lctrl.set_string_items(items) 203 lctrl.set_data(atcs)
204 #------------------------------------------------------------ 205 gmListWidgets.get_choices_from_list ( 206 parent = parent, 207 msg = _('\nThe ATC codes as known to GNUmed.\n'), 208 caption = _('Showing ATC codes.'), 209 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ], 210 single_selection = True, 211 refresh_callback = refresh 212 ) 213 214 #============================================================
215 -def update_atc_reference_data():
216 217 dlg = wx.FileDialog ( 218 parent = None, 219 message = _('Choose an ATC import config file'), 220 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')), 221 defaultFile = '', 222 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')), 223 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST 224 ) 225 226 result = dlg.ShowModal() 227 if result == wx.ID_CANCEL: 228 return 229 230 cfg_file = dlg.GetPath() 231 dlg.Destroy() 232 233 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data')) 234 if conn is None: 235 return False 236 237 wx.BeginBusyCursor() 238 239 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn): 240 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.')) 241 else: 242 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True) 243 244 wx.EndBusyCursor() 245 return True
246 247 #============================================================ 248
249 -class cATCPhraseWheel(gmPhraseWheel.cPhraseWheel):
250
251 - def __init__(self, *args, **kwargs):
252 253 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 254 255 query = u""" 256 257 SELECT DISTINCT ON (label) 258 atc_code, 259 label 260 FROM ( 261 262 SELECT 263 code as atc_code, 264 (code || ': ' || term || coalesce(' (' || ddd || unit || ')', '')) 265 AS label 266 FROM ref.atc 267 WHERE 268 term %(fragment_condition)s 269 OR 270 code %(fragment_condition)s 271 272 UNION ALL 273 274 SELECT 275 atc_code, 276 (atc_code || ': ' || description) 277 AS label 278 FROM ref.consumable_substance 279 WHERE 280 description %(fragment_condition)s 281 OR 282 atc_code %(fragment_condition)s 283 284 UNION ALL 285 286 SELECT 287 atc_code, 288 (atc_code || ': ' || description || ' (' || preparation || ')') 289 AS label 290 FROM ref.branded_drug 291 WHERE 292 description %(fragment_condition)s 293 OR 294 atc_code %(fragment_condition)s 295 296 -- it would be nice to be able to include clin.vacc_indication but that's hard to do in SQL 297 298 ) AS candidates 299 WHERE atc_code IS NOT NULL 300 ORDER BY label 301 LIMIT 50""" 302 303 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 304 mp.setThresholds(1, 2, 4) 305 # mp.word_separators = '[ \t=+&:@]+' 306 self.SetToolTipString(_('Select an ATC (Anatomical-Therapeutic-Chemical) code.')) 307 self.matcher = mp 308 self.selection_only = True
309 310 #============================================================ 311 # consumable substances widgets 312 #------------------------------------------------------------
313 -def manage_consumable_substances(parent=None):
314 315 if parent is None: 316 parent = wx.GetApp().GetTopWindow() 317 #------------------------------------------------------------ 318 def add_from_db(substance): 319 drug_db = get_drug_database(parent = parent) 320 if drug_db is None: 321 return False 322 drug_db.import_drugs() 323 return True
324 #------------------------------------------------------------ 325 def edit(substance=None): 326 return edit_consumable_substance(parent = parent, substance = substance, single_entry = (substance is not None)) 327 #------------------------------------------------------------ 328 def delete(substance): 329 if substance.is_in_use_by_patients: 330 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True) 331 return False 332 333 return gmMedication.delete_consumable_substance(substance = substance['pk']) 334 #------------------------------------------------------------ 335 def refresh(lctrl): 336 substs = gmMedication.get_consumable_substances(order_by = 'description') 337 items = [ [ 338 s['description'], 339 s['amount'], 340 s['unit'], 341 gmTools.coalesce(s['atc_code'], u''), 342 s['pk'] 343 ] for s in substs ] 344 lctrl.set_string_items(items) 345 lctrl.set_data(substs) 346 #------------------------------------------------------------ 347 msg = _('\nThese are the consumable substances registered with GNUmed.\n') 348 349 gmListWidgets.get_choices_from_list ( 350 parent = parent, 351 msg = msg, 352 caption = _('Showing consumable substances.'), 353 columns = [_('Substance'), _('Amount'), _('Unit'), 'ATC', u'#'], 354 single_selection = True, 355 new_callback = edit, 356 edit_callback = edit, 357 delete_callback = delete, 358 refresh_callback = refresh, 359 left_extra_button = (_('Import'), _('Import consumable substances from a drug database.'), add_from_db) 360 ) 361 362 #------------------------------------------------------------
363 -def edit_consumable_substance(parent=None, substance=None, single_entry=False):
364 365 if substance is not None: 366 if substance.is_in_use_by_patients: 367 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True) 368 return False 369 370 ea = cConsumableSubstanceEAPnl(parent = parent, id = -1) 371 ea.data = substance 372 ea.mode = gmTools.coalesce(substance, 'new', 'edit') 373 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry) 374 dlg.SetTitle(gmTools.coalesce(substance, _('Adding new consumable substance'), _('Editing consumable substance'))) 375 if dlg.ShowModal() == wx.ID_OK: 376 dlg.Destroy() 377 return True 378 dlg.Destroy() 379 return False
380 381 #============================================================ 382 from Gnumed.wxGladeWidgets import wxgConsumableSubstanceEAPnl 383
384 -class cConsumableSubstanceEAPnl(wxgConsumableSubstanceEAPnl.wxgConsumableSubstanceEAPnl, gmEditArea.cGenericEditAreaMixin):
385
386 - def __init__(self, *args, **kwargs):
387 388 try: 389 data = kwargs['substance'] 390 del kwargs['substance'] 391 except KeyError: 392 data = None 393 394 wxgConsumableSubstanceEAPnl.wxgConsumableSubstanceEAPnl.__init__(self, *args, **kwargs) 395 gmEditArea.cGenericEditAreaMixin.__init__(self) 396 397 # Code using this mixin should set mode and data 398 # after instantiating the class: 399 self.mode = 'new' 400 self.data = data 401 if data is not None: 402 self.mode = 'edit'
403 404 # self.__init_ui() 405 #---------------------------------------------------------------- 406 # def __init_ui(self): 407 # self._PRW_atc.selection_only = False 408 #---------------------------------------------------------------- 409 # generic Edit Area mixin API 410 #----------------------------------------------------------------
411 - def _valid_for_save(self):
412 413 validity = True 414 415 if self._TCTRL_substance.GetValue().strip() == u'': 416 validity = False 417 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = False) 418 self._TCTRL_substance.SetFocus() 419 else: 420 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = True) 421 422 try: 423 decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')) 424 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 425 except (TypeError, decimal.InvalidOperation): 426 validity = False 427 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 428 self._TCTRL_amount.SetFocus() 429 430 if self._PRW_unit.GetValue().strip() == u'': 431 validity = False 432 self._PRW_unit.display_as_valid(valid = False) 433 self._TCTRL_substance.SetFocus() 434 else: 435 self._PRW_unit.display_as_valid(valid = True) 436 437 if validity is False: 438 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. Missing essential input.')) 439 440 return validity
441 #----------------------------------------------------------------
442 - def _save_as_new(self):
443 subst = gmMedication.create_consumable_substance ( 444 substance = self._TCTRL_substance.GetValue().strip(), 445 atc = self._PRW_atc.GetData(), 446 amount = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')), 447 unit = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None)) 448 ) 449 success, data = subst.save() 450 if not success: 451 err, msg = data 452 _log.error(err) 453 _log.error(msg) 454 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True) 455 return False 456 457 self.data = subst 458 return True
459 #----------------------------------------------------------------
460 - def _save_as_update(self):
461 self.data['description'] = self._TCTRL_substance.GetValue().strip() 462 self.data['atc_code'] = self._PRW_atc.GetData() 463 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')) 464 self.data['unit'] = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None)) 465 success, data = self.data.save() 466 467 if not success: 468 err, msg = data 469 _log.error(err) 470 _log.error(msg) 471 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True) 472 return False 473 474 return True
475 #----------------------------------------------------------------
476 - def _refresh_as_new(self):
477 self._TCTRL_substance.SetValue(u'') 478 self._TCTRL_amount.SetValue(u'') 479 self._PRW_unit.SetText(u'', None) 480 self._PRW_atc.SetText(u'', None) 481 482 self._TCTRL_substance.SetFocus()
483 #----------------------------------------------------------------
484 - def _refresh_from_existing(self):
485 self._TCTRL_substance.SetValue(self.data['description']) 486 self._TCTRL_amount.SetValue(u'%s' % self.data['amount']) 487 self._PRW_unit.SetText(self.data['unit'], self.data['unit']) 488 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc_code'], u''), self.data['atc_code']) 489 490 self._TCTRL_substance.SetFocus()
491 #----------------------------------------------------------------
493 self._refresh_as_new()
494 495 #============================================================ 496 # drug component widgets 497 #------------------------------------------------------------
498 -def manage_drug_components(parent=None):
499 500 if parent is None: 501 parent = wx.GetApp().GetTopWindow() 502 503 #------------------------------------------------------------ 504 def edit(component=None): 505 substance = gmMedication.cConsumableSubstance(aPK_obj = component['pk_consumable_substance']) 506 return edit_consumable_substance(parent = parent, substance = substance, single_entry = True)
507 #------------------------------------------------------------ 508 def delete(component): 509 if component.is_in_use_by_patients: 510 gmDispatcher.send(signal = 'statustext', msg = _('Cannot remove this component from the drug. It is in use.'), beep = True) 511 return False 512 513 return component.containing_drug.remove_component(substance = component['pk_component']) 514 #------------------------------------------------------------ 515 def refresh(lctrl): 516 comps = gmMedication.get_drug_components() 517 items = [ [ 518 u'%s%s' % (c['brand'], gmTools.coalesce(c['atc_brand'], u'', u' [%s]')), 519 u'%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], u'', u' [%s]')), 520 u'%s%s' % (c['amount'], c['unit']), 521 c['preparation'], 522 gmTools.coalesce(c['external_code_brand'], u'', u'%%s [%s]' % c['external_code_type_brand']), 523 c['pk_component'] 524 ] for c in comps ] 525 lctrl.set_string_items(items) 526 lctrl.set_data(comps) 527 #------------------------------------------------------------ 528 msg = _('\nThese are the components in the drug brands known to GNUmed.\n') 529 530 gmListWidgets.get_choices_from_list ( 531 parent = parent, 532 msg = msg, 533 caption = _('Showing drug brand components.'), 534 columns = [_('Brand'), _('Substance'), _('Strength'), _('Preparation'), _('Code'), u'#'], 535 single_selection = True, 536 #new_callback = edit, 537 edit_callback = edit, 538 delete_callback = delete, 539 refresh_callback = refresh 540 ) 541 542 #------------------------------------------------------------
543 -def edit_drug_component(parent=None, drug_component=None, single_entry=False):
544 ea = cDrugComponentEAPnl(parent = parent, id = -1) 545 ea.data = drug_component 546 ea.mode = gmTools.coalesce(drug_component, 'new', 'edit') 547 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry) 548 dlg.SetTitle(gmTools.coalesce(drug_component, _('Adding new drug component'), _('Editing drug component'))) 549 if dlg.ShowModal() == wx.ID_OK: 550 dlg.Destroy() 551 return True 552 dlg.Destroy() 553 return False
554 555 #============================================================ 556 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl 557
558 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
559
560 - def __init__(self, *args, **kwargs):
561 562 try: 563 data = kwargs['component'] 564 del kwargs['component'] 565 except KeyError: 566 data = None 567 568 wxgDrugComponentEAPnl.wxgDrugComponentEAPnl.__init__(self, *args, **kwargs) 569 gmEditArea.cGenericEditAreaMixin.__init__(self) 570 571 # Code using this mixin should set mode and data 572 # after instantiating the class: 573 self.mode = 'new' 574 self.data = data 575 if data is not None: 576 self.mode = 'edit'
577 578 #self.__init_ui() 579 #---------------------------------------------------------------- 580 # def __init_ui(self): 581 # # adjust phrasewheels etc 582 #---------------------------------------------------------------- 583 # generic Edit Area mixin API 584 #----------------------------------------------------------------
585 - def _valid_for_save(self):
586 if self.data is not None: 587 if self.data['is_in_use']: 588 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug component. It is in use.'), beep = True) 589 return False 590 591 validity = True 592 593 if self._PRW_substance.GetData() is None: 594 validity = False 595 self._PRW_substance.display_as_valid(False) 596 else: 597 self._PRW_substance.display_as_valid(True) 598 599 val = self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1) 600 try: 601 decimal.Decimal(val) 602 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 603 except: 604 validity = False 605 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 606 607 if self._PRW_unit.GetValue().strip() == u'': 608 validity = False 609 self._PRW_unit.display_as_valid(False) 610 else: 611 self._PRW_unit.display_as_valid(True) 612 613 if validity is False: 614 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save drug component. Invalid or missing essential input.')) 615 616 return validity
617 #----------------------------------------------------------------
618 - def _save_as_new(self):
619 # save the data as a new instance 620 data = 1 621 data[''] = 1 622 data[''] = 1 623 # data.save() 624 625 # must be done very late or else the property access 626 # will refresh the display such that later field 627 # access will return empty values 628 # self.data = data 629 return False 630 return True
631 #----------------------------------------------------------------
632 - def _save_as_update(self):
633 self.data['pk_consumable_substance'] = self._PRW_substance.GetData() 634 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1)) 635 self.data['unit'] = self._PRW_unit.GetValue().strip() 636 return self.data.save()
637 #----------------------------------------------------------------
638 - def _refresh_as_new(self):
639 self._TCTRL_brand.SetValue(u'') 640 self._TCTRL_components.SetValue(u'') 641 self._TCTRL_codes.SetValue(u'') 642 self._PRW_substance.SetText(u'', None) 643 self._TCTRL_amount.SetValue(u'') 644 self._PRW_unit.SetText(u'', None) 645 646 self._PRW_substance.SetFocus()
647 #----------------------------------------------------------------
648 - def _refresh_from_existing(self):
649 self._TCTRL_brand.SetValue(u'%s (%s)' % (self.data['brand'], self.data['preparation'])) 650 self._TCTRL_components.SetValue(u' / '.join(self.data.containing_drug['components'])) 651 details = [] 652 if self.data['atc_brand'] is not None: 653 details.append(u'ATC: %s' % self.data['atc_brand']) 654 if self.data['external_code_brand'] is not None: 655 details.append(u'%s: %s' % (self.data['external_code_type_brand'], self.data['external_code_brand'])) 656 self._TCTRL_codes.SetValue(u'; '.join(details)) 657 658 self._PRW_substance.SetText(self.data['substance'], self.data['pk_consumable_substance']) 659 self._TCTRL_amount.SetValue(u'%s' % self.data['amount']) 660 self._PRW_unit.SetText(self.data['unit'], self.data['unit']) 661 662 self._PRW_substance.SetFocus()
663 #----------------------------------------------------------------
665 #self._PRW_brand.SetText(u'', None) 666 #self._TCTRL_prep.SetValue(u'') 667 #self._TCTRL_brand_details.SetValue(u'') 668 self._PRW_substance.SetText(u'', None) 669 self._TCTRL_amount.SetValue(u'') 670 self._PRW_unit.SetText(u'', None) 671 672 self._PRW_substance.SetFocus()
673 674 #============================================================
675 -class cDrugComponentPhraseWheel(gmPhraseWheel.cPhraseWheel):
676
677 - def __init__(self, *args, **kwargs):
678 679 mp = gmMedication.cDrugComponentMatchProvider() 680 mp.setThresholds(2, 3, 4) 681 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 682 self.SetToolTipString(_('A drug component with optional strength.')) 683 self.matcher = mp 684 self.selection_only = False
685 #--------------------------------------------------------
686 - def _data2instance(self):
687 return gmMedication.cDrugComponent(aPK_obj = self.GetData(as_instance = False, can_create = False))
688 #============================================================ 689 #============================================================
690 -class cSubstancePreparationPhraseWheel(gmPhraseWheel.cPhraseWheel):
691
692 - def __init__(self, *args, **kwargs):
693 694 query = u""" 695 ( 696 SELECT DISTINCT ON (preparation) 697 preparation as prep, preparation 698 FROM ref.branded_drug 699 WHERE preparation %(fragment_condition)s 700 ) UNION ( 701 SELECT DISTINCT ON (preparation) 702 preparation as prep, preparation 703 FROM clin.substance_intake 704 WHERE preparation %(fragment_condition)s 705 ) 706 ORDER BY prep 707 limit 30""" 708 709 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 710 mp.setThresholds(1, 2, 4) 711 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 712 self.SetToolTipString(_('The preparation (form) of the substance or brand.')) 713 self.matcher = mp 714 self.selection_only = False
715 #============================================================
716 -class cSubstancePhraseWheel(gmPhraseWheel.cPhraseWheel):
717
718 - def __init__(self, *args, **kwargs):
719 720 mp = gmMedication.cSubstanceMatchProvider() 721 mp.setThresholds(1, 2, 4) 722 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 723 self.SetToolTipString(_('The substance with optional strength.')) 724 self.matcher = mp 725 self.selection_only = False 726 self.phrase_separators = None
727 728 #--------------------------------------------------------
729 - def _data2instance(self):
730 return gmMedication.cConsumableSubstance(aPK_obj = self.GetData(as_instance = False, can_create = False))
731 #============================================================ 732 # branded drugs widgets 733 #------------------------------------------------------------
734 -def manage_components_of_branded_drug(parent=None, brand=None):
735 736 if brand is not None: 737 if brand.is_in_use_by_patients: 738 gmGuiHelpers.gm_show_info ( 739 aTitle = _('Managing components of a drug'), 740 aMessage = _( 741 'Cannot manage the components of the branded drug product\n' 742 '\n' 743 ' "%s" (%s)\n' 744 '\n' 745 'because it is currently taken by patients.\n' 746 ) % (brand['brand'], brand['preparation']) 747 ) 748 return False 749 #-------------------------------------------------------- 750 if parent is None: 751 parent = wx.GetApp().GetTopWindow() 752 #-------------------------------------------------------- 753 # def manage_substances(): 754 # pass 755 #-------------------------------------------------------- 756 if brand is None: 757 msg = _('Pick the substances which are components of this drug.') 758 right_col = _('Components of drug') 759 comp_substs = [] 760 else: 761 right_col = u'%s (%s)' % (brand['brand'], brand['preparation']) 762 msg = _( 763 'Adjust the components of "%s"\n' 764 '\n' 765 'The drug must contain at least one component. Any given\n' 766 'substance can only be included once per drug.' 767 ) % right_col 768 comp_substs = [ c.substance for c in brand.components ] 769 770 substs = gmMedication.get_consumable_substances(order_by = 'description') 771 choices = [ u'%s %s%s' % (s['description'], s['amount'], s['unit']) for s in substs ] 772 picks = [ u'%s %s%s' % (c['description'], c['amount'], c['unit']) for c in comp_substs ] 773 774 picker = gmListWidgets.cItemPickerDlg ( 775 parent, 776 -1, 777 title = _('Managing components of a drug ...'), 778 msg = msg 779 ) 780 picker.set_columns(['Substances'], [right_col]) 781 picker.set_choices(choices = choices, data = substs) 782 picker.set_picks(picks = picks, data = comp_substs) 783 # picker.extra_button = ( 784 # _('Substances'), 785 # _('Manage list of consumable substances'), 786 # manage_substances 787 # ) 788 789 btn_pressed = picker.ShowModal() 790 substs = picker.get_picks() 791 picker.Destroy() 792 793 if btn_pressed != wx.ID_OK: 794 return (False, None) 795 796 if brand is not None: 797 brand.set_substances_as_components(substances = substs) 798 799 return (True, substs)
800 #------------------------------------------------------------
801 -def manage_branded_drugs(parent=None, ignore_OK_button=False):
802 803 if parent is None: 804 parent = wx.GetApp().GetTopWindow() 805 #------------------------------------------------------------ 806 def add_from_db(brand): 807 drug_db = get_drug_database(parent = parent) 808 if drug_db is None: 809 return False 810 drug_db.import_drugs() 811 return True
812 #------------------------------------------------------------ 813 def get_tooltip(brand=None): 814 tt = u'%s %s\n' % (brand['brand'], brand['preparation']) 815 tt += u'\n' 816 tt += u'%s%s%s\n' % ( 817 gmTools.bool2subst(brand.is_vaccine, u'%s, ' % _('Vaccine'), u''), 818 u'%s, ' % gmTools.bool2subst(brand.is_in_use_by_patients, _('in use'), _('not in use')), 819 gmTools.bool2subst(brand['is_fake_brand'], _('fake'), u'') 820 ) 821 tt += gmTools.coalesce(brand['atc'], u'', _('ATC: %s\n')) 822 tt += gmTools.coalesce(brand['external_code'], u'', u'%s: %%s\n' % brand['external_code_type']) 823 if brand['components'] is not None: 824 tt += u'- %s' % u'\n- '.join(brand['components']) 825 return tt 826 #------------------------------------------------------------ 827 def edit(brand): 828 if brand is not None: 829 if brand.is_vaccine: 830 gmGuiHelpers.gm_show_info ( 831 aTitle = _('Editing medication'), 832 aMessage = _( 833 'Cannot edit the medication\n' 834 '\n' 835 ' "%s" (%s)\n' 836 '\n' 837 'because it is a vaccine. Please edit it\n' 838 'from the vaccine management section !\n' 839 ) % (brand['brand'], brand['preparation']) 840 ) 841 return False 842 843 return edit_branded_drug(parent = parent, branded_drug = brand, single_entry = True) 844 #------------------------------------------------------------ 845 def delete(brand): 846 if brand.is_vaccine: 847 gmGuiHelpers.gm_show_info ( 848 aTitle = _('Deleting medication'), 849 aMessage = _( 850 'Cannot delete the medication\n' 851 '\n' 852 ' "%s" (%s)\n' 853 '\n' 854 'because it is a vaccine. Please delete it\n' 855 'from the vaccine management section !\n' 856 ) % (brand['brand'], brand['preparation']) 857 ) 858 return False 859 gmMedication.delete_branded_drug(brand = brand['pk_brand']) 860 return True 861 #------------------------------------------------------------ 862 def new(): 863 return edit_branded_drug(parent = parent, branded_drug = None, single_entry = False) 864 #------------------------------------------------------------ 865 def refresh(lctrl): 866 drugs = gmMedication.get_branded_drugs() 867 items = [ [ 868 u'%s%s' % ( 869 d['brand'], 870 gmTools.bool2subst(d['is_fake_brand'], ' (%s)' % _('fake'), u'') 871 ), 872 d['preparation'], 873 gmTools.coalesce(d['atc'], u''), 874 gmTools.coalesce(d['components'], u''), 875 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']), 876 d['pk_brand'] 877 ] for d in drugs ] 878 lctrl.set_string_items(items) 879 lctrl.set_data(drugs) 880 #------------------------------------------------------------ 881 msg = _('\nThese are the drug brands known to GNUmed.\n') 882 883 gmListWidgets.get_choices_from_list ( 884 parent = parent, 885 msg = msg, 886 caption = _('Showing branded drugs.'), 887 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), u'#'], 888 single_selection = True, 889 ignore_OK_button = ignore_OK_button, 890 refresh_callback = refresh, 891 new_callback = new, 892 edit_callback = edit, 893 delete_callback = delete, 894 list_tooltip_callback = get_tooltip, 895 left_extra_button = (_('Import'), _('Import substances and brands from a drug database.'), add_from_db) 896 #, middle_extra_button = (_('Clone'), _('Clone selected drug into a new entry for editing.'), clone_from_existing) 897 #, right_extra_button = (_('Reassign'), _('Reassign all patients taking the selected drug to another drug.'), reassign_patients) 898 ) 899 900 #------------------------------------------------------------
901 -def edit_branded_drug(parent=None, branded_drug=None, single_entry=False):
902 903 if branded_drug is not None: 904 if branded_drug.is_in_use_by_patients: 905 gmGuiHelpers.gm_show_info ( 906 aTitle = _('Editing drug'), 907 aMessage = _( 908 'Cannot edit the branded drug product\n' 909 '\n' 910 ' "%s" (%s)\n' 911 '\n' 912 'because it is currently taken by patients.\n' 913 ) % (branded_drug['brand'], branded_drug['preparation']) 914 ) 915 return False 916 917 if parent is None: 918 parent = wx.GetApp().GetTopWindow() 919 #-------------------------------------------- 920 def manage_substances(drug): 921 manage_consumable_substances(parent = parent)
922 #-------------------------------------------- 923 ea = cBrandedDrugEAPnl(parent = parent, id = -1) 924 ea.data = branded_drug 925 ea.mode = gmTools.coalesce(branded_drug, 'new', 'edit') 926 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry) 927 dlg.SetTitle(gmTools.coalesce(branded_drug, _('Adding new drug brand'), _('Editing drug brand'))) 928 dlg.left_extra_button = ( 929 _('Substances'), 930 _('Manage consumable substances'), 931 manage_substances 932 ) 933 if dlg.ShowModal() == wx.ID_OK: 934 dlg.Destroy() 935 return True 936 dlg.Destroy() 937 return False 938 939 #============================================================ 940 from Gnumed.wxGladeWidgets import wxgBrandedDrugEAPnl 941
942 -class cBrandedDrugEAPnl(wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
943
944 - def __init__(self, *args, **kwargs):
945 946 try: 947 data = kwargs['drug'] 948 del kwargs['drug'] 949 except KeyError: 950 data = None 951 952 wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl.__init__(self, *args, **kwargs) 953 gmEditArea.cGenericEditAreaMixin.__init__(self) 954 955 self.mode = 'new' 956 self.data = data 957 if data is not None: 958 self.mode = 'edit' 959 self.__component_substances = data.components_as_substances
960 961 #self.__init_ui() 962 #---------------------------------------------------------------- 963 # def __init_ui(self): 964 # adjust external type PRW 965 #---------------------------------------------------------------- 966 # generic Edit Area mixin API 967 #----------------------------------------------------------------
968 - def _valid_for_save(self):
969 970 if self.data is not None: 971 if self.data.is_in_use_by_patients: 972 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug brand. It is in use.'), beep = True) 973 return False 974 975 validity = True 976 977 if self._PRW_brand.GetValue().strip() == u'': 978 validity = False 979 self._PRW_brand.display_as_valid(False) 980 else: 981 self._PRW_brand.display_as_valid(True) 982 983 if self._PRW_preparation.GetValue().strip() == u'': 984 validity = False 985 self._PRW_preparation.display_as_valid(False) 986 else: 987 self._PRW_preparation.display_as_valid(True) 988 989 if validity is True: 990 self._TCTRL_components.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND)) 991 if len(self.__component_substances) == 0: 992 wants_empty = gmGuiHelpers.gm_show_question ( 993 title = _('Checking brand data'), 994 question = _( 995 'You have not selected any substances\n' 996 'as drug components.\n' 997 '\n' 998 'Without components you will not be able to\n' 999 'use this drug for documenting patient care.\n' 1000 '\n' 1001 'Are you sure you want to save\n' 1002 'it without components ?' 1003 ) 1004 ) 1005 if not wants_empty: 1006 validity = False 1007 self.display_ctrl_as_valid(ctrl = self._TCTRL_components, valid = False) 1008 1009 if validity is False: 1010 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save branded drug. Invalid or missing essential input.')) 1011 1012 return validity
1013 #----------------------------------------------------------------
1014 - def _save_as_new(self):
1015 1016 drug = gmMedication.create_branded_drug ( 1017 brand_name = self._PRW_brand.GetValue().strip(), 1018 preparation = gmTools.coalesce ( 1019 self._PRW_preparation.GetData(), 1020 self._PRW_preparation.GetValue() 1021 ).strip(), 1022 return_existing = True 1023 ) 1024 drug['is_fake_brand'] = self._CHBOX_is_fake.GetValue() 1025 drug['atc'] = self._PRW_atc.GetData() 1026 code = self._TCTRL_external_code.GetValue().strip() 1027 if code != u'': 1028 drug['external_code'] = code 1029 drug['external_code_type'] = self._PRW_external_code_type.GetData().strip() 1030 1031 drug.save() 1032 1033 if len(self.__component_substances) > 0: 1034 drug.set_substances_as_components(substances = self.__component_substances) 1035 1036 self.data = drug 1037 1038 return True
1039 #----------------------------------------------------------------
1040 - def _save_as_update(self):
1041 self.data['brand'] = self._PRW_brand.GetValue().strip() 1042 self.data['preparation'] = gmTools.coalesce ( 1043 self._PRW_preparation.GetData(), 1044 self._PRW_preparation.GetValue() 1045 ).strip() 1046 self.data['is_fake_brand'] = self._CHBOX_is_fake.GetValue() 1047 self.data['atc'] = self._PRW_atc.GetData() 1048 code = self._TCTRL_external_code.GetValue().strip() 1049 if code != u'': 1050 self.data['external_code'] = code 1051 self.data['external_code_type'] = self._PRW_external_code_type.GetData().strip() 1052 success, data = self.data.save() 1053 if not success: 1054 err, msg = data 1055 _log.error('problem saving') 1056 _log.error('%s', err) 1057 _log.error('%s', msg) 1058 return (success is True)
1059 #----------------------------------------------------------------
1060 - def _refresh_as_new(self):
1061 self._PRW_brand.SetText(u'', None) 1062 self._PRW_preparation.SetText(u'', None) 1063 self._CHBOX_is_fake.SetValue(False) 1064 self._TCTRL_components.SetValue(u'') 1065 self._PRW_atc.SetText(u'', None) 1066 self._TCTRL_external_code.SetValue(u'') 1067 self._PRW_external_code_type.SetText(u'', None) 1068 1069 self._PRW_brand.SetFocus() 1070 1071 self.__component_substances = []
1072 #----------------------------------------------------------------
1074 self._refresh_as_new()
1075 #----------------------------------------------------------------
1076 - def _refresh_from_existing(self):
1077 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand']) 1078 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation']) 1079 self._CHBOX_is_fake.SetValue(self.data['is_fake_brand']) 1080 comps = u'' 1081 if self.data['components'] is not None: 1082 comps = u'- %s' % u'\n- '.join(self.data['components']) 1083 self._TCTRL_components.SetValue(comps) 1084 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc'], u''), self.data['atc']) 1085 self._TCTRL_external_code.SetValue(gmTools.coalesce(self.data['external_code'], u'')) 1086 t = gmTools.coalesce(self.data['external_code_type'], u'') 1087 self._PRW_external_code_type.SetText(t, t) 1088 1089 self._PRW_brand.SetFocus() 1090 1091 self.__component_substances = self.data.components_as_substances
1092 #---------------------------------------------------------------- 1093 # event handler 1094 #----------------------------------------------------------------
1095 - def _on_manage_components_button_pressed(self, event):
1096 event.Skip() 1097 if self.mode == 'new_from_existing': 1098 brand = None 1099 else: 1100 brand = self.data 1101 OKed, substs = manage_components_of_branded_drug(parent = self, brand = brand) 1102 if OKed is True: 1103 self.__component_substances = substs 1104 comps = u'' 1105 if len(substs) > 0: 1106 comps = u'- %s' % u'\n- '.join([ u'%s %s%s' % (s['description'], s['amount'], s['unit']) for s in substs ]) 1107 self._TCTRL_components.SetValue(comps)
1108 #============================================================
1109 -class cBrandedDrugPhraseWheel(gmPhraseWheel.cPhraseWheel):
1110
1111 - def __init__(self, *args, **kwargs):
1112 1113 query = u""" 1114 SELECT 1115 pk 1116 AS data, 1117 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', '')) 1118 AS list_label, 1119 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', '')) 1120 AS field_label 1121 FROM ref.branded_drug 1122 WHERE description %(fragment_condition)s 1123 ORDER BY list_label 1124 LIMIT 50""" 1125 1126 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 1127 mp.setThresholds(2, 3, 4) 1128 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1129 self.SetToolTipString(_( 1130 'The brand name of the drug.\n' 1131 '\n' 1132 'Note: a brand name will need to be linked to\n' 1133 'one or more components before it can be used,\n' 1134 'except in the case of fake (generic) vaccines.' 1135 )) 1136 self.matcher = mp 1137 self.selection_only = False
1138 1139 #============================================================ 1140 # current substance intake widgets 1141 #------------------------------------------------------------
1142 -class cSubstanceSchedulePhraseWheel(gmPhraseWheel.cPhraseWheel):
1143
1144 - def __init__(self, *args, **kwargs):
1145 1146 query = u""" 1147 SELECT DISTINCT ON (sched) 1148 schedule as sched, 1149 schedule 1150 FROM clin.substance_intake 1151 WHERE schedule %(fragment_condition)s 1152 ORDER BY sched 1153 LIMIT 50""" 1154 1155 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 1156 mp.setThresholds(1, 2, 4) 1157 mp.word_separators = '[ \t=+&:@]+' 1158 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1159 self.SetToolTipString(_('The schedule for taking this substance.')) 1160 self.matcher = mp 1161 self.selection_only = False
1162 #============================================================
1163 -def turn_substance_intake_into_allergy(parent=None, intake=None, emr=None):
1164 1165 if intake['is_currently_active']: 1166 intake['discontinued'] = gmDateTime.pydt_now_here() 1167 if intake['discontinue_reason'] is None: 1168 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), _('discontinued due to allergy or intolerance')) 1169 else: 1170 if not intake['discontinue_reason'].startswith(_('not tolerated:')): 1171 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), intake['discontinue_reason']) 1172 if not intake.save(): 1173 return False 1174 1175 allg = intake.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter']) 1176 1177 brand = intake.containing_drug 1178 if brand is not None: 1179 comps = [ c['substance'] for c in brand.components ] 1180 if len(comps) > 1: 1181 gmGuiHelpers.gm_show_info ( 1182 aTitle = _(u'Documented an allergy'), 1183 aMessage = _( 1184 u'An allergy was documented against the substance:\n' 1185 u'\n' 1186 u' [%s]\n' 1187 u'\n' 1188 u'This substance was taken with the multi-component brand:\n' 1189 u'\n' 1190 u' [%s (%s)]\n' 1191 u'\n' 1192 u'Note that ALL components of this brand were discontinued.' 1193 ) % ( 1194 intake['substance'], 1195 intake['brand'], 1196 u' & '.join(comps) 1197 ) 1198 ) 1199 1200 if parent is None: 1201 parent = wx.GetApp().GetTopWindow() 1202 1203 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = parent, id = -1) 1204 dlg.ShowModal() 1205 1206 return True
1207 #============================================================ 1208 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl 1209
1210 -class cSubstanceIntakeEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
1211
1212 - def __init__(self, *args, **kwargs):
1213 1214 try: 1215 data = kwargs['substance'] 1216 del kwargs['substance'] 1217 except KeyError: 1218 data = None 1219 1220 wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl.__init__(self, *args, **kwargs) 1221 gmEditArea.cGenericEditAreaMixin.__init__(self) 1222 1223 self.mode = 'new' 1224 self.data = data 1225 if data is not None: 1226 self.mode = 'edit' 1227 1228 self.__init_ui()
1229 #----------------------------------------------------------------
1230 - def __init_ui(self):
1231 1232 self._PRW_component.add_callback_on_lose_focus(callback = self._on_leave_component) 1233 self._PRW_component.selection_only = True 1234 1235 self._PRW_substance.add_callback_on_lose_focus(callback = self._on_leave_substance) 1236 self._PRW_substance.selection_only = True
1237 #----------------------------------------------------------------
1238 - def __refresh_allergies(self):
1239 emr = gmPerson.gmCurrentPatient().get_emr() 1240 1241 state = emr.allergy_state 1242 if state['last_confirmed'] is None: 1243 confirmed = _('never') 1244 else: 1245 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding()) 1246 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed) 1247 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by']) 1248 msg += u'\n' 1249 1250 for allergy in emr.get_allergies(): 1251 msg += u'%s (%s, %s): %s\n' % ( 1252 allergy['descriptor'], 1253 allergy['l10n_type'], 1254 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'), 1255 gmTools.coalesce(allergy['reaction'], _('reaction not recorded')) 1256 ) 1257 1258 self._LBL_allergies.SetLabel(msg)
1259 #---------------------------------------------------------------- 1260 # generic Edit Area mixin API 1261 #----------------------------------------------------------------
1262 - def _valid_for_save(self):
1263 1264 validity = True 1265 1266 has_component = (self._PRW_component.GetData() is not None) 1267 has_substance = (self._PRW_substance.GetValue().strip() != u'') 1268 1269 self._PRW_component.display_as_valid(True) 1270 1271 # cannot add duplicate components 1272 if self.mode == 'new': 1273 msg = _( 1274 'The patient is already taking\n' 1275 '\n' 1276 ' %s\n' 1277 '\n' 1278 'You will want to adjust the schedule\n' 1279 'rather than document the intake twice.' 1280 ) 1281 title = _('Adding substance intake entry') 1282 if has_component: 1283 emr = gmPerson.gmCurrentPatient().get_emr() 1284 if emr.substance_intake_exists(pk_component = self._PRW_component.GetData()): 1285 gmGuiHelpers.gm_show_warning ( 1286 aTitle = title, 1287 aMessage = msg % self._PRW_component.GetValue().strip() 1288 ) 1289 self._PRW_component.display_as_valid(False) 1290 validity = False 1291 pk_substance = self._PRW_substance.GetData() 1292 if pk_substance is not None: 1293 emr = gmPerson.gmCurrentPatient().get_emr() 1294 if emr.substance_intake_exists(pk_substance = pk_substance): 1295 gmGuiHelpers.gm_show_warning ( 1296 aTitle = title, 1297 aMessage = msg % self._PRW_substance.GetValue().strip() 1298 ) 1299 self._PRW_substance.display_as_valid(False) 1300 validity = False 1301 1302 # must have either brand or substance 1303 if (has_component is False) and (has_substance is False): 1304 self._PRW_substance.display_as_valid(False) 1305 self._PRW_component.display_as_valid(False) 1306 validity = False 1307 else: 1308 self._PRW_substance.display_as_valid(True) 1309 1310 # brands already have a preparation, so only required for substances 1311 if not has_component: 1312 if self._PRW_preparation.GetValue().strip() == u'': 1313 self._PRW_preparation.display_as_valid(False) 1314 validity = False 1315 else: 1316 self._PRW_preparation.display_as_valid(True) 1317 1318 # episode must be set if intake is to be approved of 1319 if self._CHBOX_approved.IsChecked(): 1320 if self._PRW_episode.GetValue().strip() == u'': 1321 self._PRW_episode.display_as_valid(False) 1322 validity = False 1323 else: 1324 self._PRW_episode.display_as_valid(True) 1325 1326 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]: 1327 self._PRW_duration.display_as_valid(True) 1328 else: 1329 if gmDateTime.str2interval(self._PRW_duration.GetValue()) is None: 1330 self._PRW_duration.display_as_valid(False) 1331 validity = False 1332 else: 1333 self._PRW_duration.display_as_valid(True) 1334 1335 # end must be > start if at all 1336 end = self._DP_discontinued.GetData() 1337 if end is not None: 1338 start = self._DP_started.GetData() 1339 if start > end: 1340 self._DP_started.display_as_valid(False) 1341 self._DP_discontinued.display_as_valid(False) 1342 validity = False 1343 else: 1344 self._DP_started.display_as_valid(True) 1345 self._DP_discontinued.display_as_valid(True) 1346 1347 if validity is False: 1348 gmDispatcher.send(signal = 'statustext', msg = _('Input incomplete/invalid for saving as substance intake.')) 1349 1350 return validity
1351 #----------------------------------------------------------------
1352 - def _save_as_new(self):
1353 1354 emr = gmPerson.gmCurrentPatient().get_emr() 1355 epi = self._PRW_episode.GetData(can_create = True) 1356 1357 if self._PRW_substance.GetData() is None: 1358 # auto-creates all components as intakes 1359 intake = emr.add_substance_intake ( 1360 pk_component = self._PRW_component.GetData(), 1361 episode = epi 1362 ) 1363 else: 1364 intake = emr.add_substance_intake ( 1365 pk_substance = self._PRW_substance.GetData(), 1366 episode = epi, 1367 preparation = self._PRW_preparation.GetValue().strip() 1368 ) 1369 1370 if intake is None: 1371 gmDispatcher.send('statustext', msg = _('Cannot add duplicate of (maybe inactive) substance intake.'), beep = True) 1372 return False 1373 1374 intake['started'] = self._DP_started.GetData() 1375 intake['discontinued'] = self._DP_discontinued.GetData() 1376 if intake['discontinued'] is None: 1377 intake['discontinue_reason'] = None 1378 else: 1379 intake['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip() 1380 intake['schedule'] = self._PRW_schedule.GetValue().strip() 1381 intake['aim'] = self._PRW_aim.GetValue().strip() 1382 intake['notes'] = self._PRW_notes.GetValue().strip() 1383 intake['is_long_term'] = self._CHBOX_long_term.IsChecked() 1384 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked() 1385 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]: 1386 intake['duration'] = None 1387 else: 1388 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue()) 1389 intake.save() 1390 1391 self.data = intake 1392 1393 return True
1394 #----------------------------------------------------------------
1395 - def _save_as_update(self):
1396 1397 # auto-applies to all components of drug if any: 1398 self.data['started'] = self._DP_started.GetData() 1399 self.data['discontinued'] = self._DP_discontinued.GetData() 1400 if self.data['discontinued'] is None: 1401 self.data['discontinue_reason'] = None 1402 else: 1403 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip() 1404 self.data['schedule'] = self._PRW_schedule.GetValue() 1405 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked() 1406 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked() 1407 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]: 1408 self.data['duration'] = None 1409 else: 1410 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue()) 1411 1412 # applies to non-component substances only 1413 self.data['preparation'] = self._PRW_preparation.GetValue() 1414 1415 # per-component 1416 self.data['aim'] = self._PRW_aim.GetValue() 1417 self.data['notes'] = self._PRW_notes.GetValue() 1418 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True) 1419 1420 self.data.save() 1421 1422 return True
1423 #----------------------------------------------------------------
1424 - def _refresh_as_new(self):
1425 self._PRW_component.SetText(u'', None) 1426 self._TCTRL_brand_ingredients.SetValue(u'') 1427 self._TCTRL_brand_ingredients.SetToolTipString(u'') 1428 1429 self._PRW_substance.SetText(u'', None) 1430 self._PRW_substance.Enable(True) 1431 1432 self._PRW_preparation.SetText(u'', None) 1433 self._PRW_preparation.Enable(True) 1434 1435 self._PRW_schedule.SetText(u'', None) 1436 self._PRW_duration.SetText(u'', None) 1437 self._PRW_aim.SetText(u'', None) 1438 self._PRW_notes.SetText(u'', None) 1439 self._PRW_episode.SetText(u'', None) 1440 1441 self._CHBOX_long_term.SetValue(False) 1442 self._CHBOX_approved.SetValue(True) 1443 1444 self._DP_started.SetData(gmDateTime.pydt_now_here()) 1445 self._DP_discontinued.SetData(None) 1446 self._PRW_discontinue_reason.SetValue(u'') 1447 1448 self.__refresh_allergies() 1449 1450 self._PRW_component.SetFocus()
1451 #----------------------------------------------------------------
1452 - def _refresh_from_existing(self):
1453 1454 self._TCTRL_brand_ingredients.SetValue(u'') 1455 self._TCTRL_brand_ingredients.SetToolTipString(u'') 1456 1457 if self.data['pk_brand'] is None: 1458 self.__refresh_from_existing_substance() 1459 else: 1460 self.__refresh_from_existing_component() 1461 1462 self._PRW_component.Enable(False) 1463 self._PRW_substance.Enable(False) 1464 1465 if self.data['is_long_term']: 1466 self._CHBOX_long_term.SetValue(True) 1467 self._PRW_duration.Enable(False) 1468 self._PRW_duration.SetText(gmTools.u_infinity, None) 1469 self._BTN_discontinued_as_planned.Enable(False) 1470 else: 1471 self._CHBOX_long_term.SetValue(False) 1472 self._PRW_duration.Enable(True) 1473 self._BTN_discontinued_as_planned.Enable(True) 1474 if self.data['duration'] is None: 1475 self._PRW_duration.SetText(u'', None) 1476 else: 1477 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration']) 1478 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim']) 1479 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes']) 1480 self._PRW_episode.SetData(self.data['pk_episode']) 1481 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule']) 1482 1483 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of']) 1484 1485 self._DP_started.SetData(self.data['started']) 1486 self._DP_discontinued.SetData(self.data['discontinued']) 1487 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u'')) 1488 if self.data['discontinued'] is not None: 1489 self._PRW_discontinue_reason.Enable() 1490 1491 self.__refresh_allergies() 1492 1493 self._PRW_schedule.SetFocus()
1494 #----------------------------------------------------------------
1496 self._LBL_component.Enable(False) 1497 self._PRW_component.SetText(u'', None) 1498 self._PRW_component.display_as_valid(True) 1499 1500 self._PRW_substance.SetText ( 1501 u'%s %s%s' % (self.data['substance'], self.data['amount'], self.data['unit']), 1502 self.data['pk_substance'] 1503 ) 1504 1505 self._PRW_preparation.SetText(gmTools.coalesce(self.data['preparation'], u''), self.data['preparation']) 1506 self._PRW_preparation.Enable(True)
1507 #----------------------------------------------------------------
1509 self._PRW_component.SetText ( 1510 u'%s %s%s (%s)' % (self.data['substance'], self.data['amount'], self.data['unit'], self.data['brand']), 1511 self.data['pk_drug_component'] 1512 ) 1513 1514 brand = gmMedication.cBrandedDrug(aPK_obj = self.data['pk_brand']) 1515 if brand['components'] is not None: 1516 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components'])) 1517 tt = u'%s:\n\n- %s' % ( 1518 self.data['brand'], 1519 u'\n- '.join(brand['components']) 1520 ) 1521 self._TCTRL_brand_ingredients.SetToolTipString(tt) 1522 1523 self._LBL_or.Enable(False) 1524 self._LBL_substance.Enable(False) 1525 self._PRW_substance.SetText(u'', None) 1526 self._PRW_substance.display_as_valid(True) 1527 1528 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation']) 1529 self._PRW_preparation.Enable(False)
1530 #----------------------------------------------------------------
1532 self._refresh_as_new()
1533 #---------------------------------------------------------------- 1534 # event handlers 1535 #----------------------------------------------------------------
1536 - def _on_leave_component(self):
1537 if self._PRW_component.GetData() is None: 1538 self._LBL_or.Enable(True) 1539 self._PRW_component.SetText(u'', None) 1540 self._LBL_substance.Enable(True) 1541 self._PRW_substance.Enable(True) 1542 self._LBL_preparation.Enable(True) 1543 self._PRW_preparation.Enable(True) 1544 self._PRW_preparation.SetText(u'', None) 1545 self._TCTRL_brand_ingredients.SetValue(u'') 1546 self._TCTRL_brand_ingredients.SetToolTipString(u'') 1547 else: 1548 self._LBL_or.Enable(False) 1549 self._LBL_substance.Enable(False) 1550 self._PRW_substance.SetText(u'', None) 1551 self._PRW_substance.display_as_valid(True) 1552 self._PRW_substance.Enable(False) 1553 self._LBL_preparation.Enable(False) 1554 self._PRW_preparation.Enable(False) 1555 comp = gmMedication.cDrugComponent(aPK_obj = self._PRW_component.GetData()) 1556 self._PRW_preparation.SetText(comp['preparation'], comp['preparation']) 1557 brand = comp.containing_drug 1558 if brand['components'] is not None: 1559 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components'])) 1560 tt = u'%s:\n\n- %s' % ( 1561 brand['brand'], 1562 u'\n- '.join(brand['components']) 1563 ) 1564 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1565 #----------------------------------------------------------------
1566 - def _on_leave_substance(self):
1567 if self._PRW_substance.GetData() is None: 1568 self._LBL_or.Enable(True) 1569 self._LBL_component.Enable(True) 1570 self._PRW_component.Enable(True) 1571 self._PRW_substance.SetText(u'', None) 1572 else: 1573 self._LBL_or.Enable(False) 1574 self._LBL_component.Enable(False) 1575 self._PRW_component.SetText(u'', None) 1576 self._PRW_component.display_as_valid(True) 1577 self._PRW_component.Enable(False) 1578 self._LBL_preparation.Enable(True) 1579 self._PRW_preparation.Enable(True) 1580 self._TCTRL_brand_ingredients.SetValue(u'') 1581 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1582 #----------------------------------------------------------------
1583 - def _on_discontinued_date_changed(self, event):
1584 if self._DP_discontinued.GetData() is None: 1585 self._PRW_discontinue_reason.Enable(False) 1586 else: 1587 self._PRW_discontinue_reason.Enable(True)
1588 #----------------------------------------------------------------
1589 - def _on_manage_brands_button_pressed(self, event):
1590 manage_branded_drugs(parent = self, ignore_OK_button = True)
1591 #----------------------------------------------------------------
1592 - def _on_manage_substances_button_pressed(self, event):
1593 manage_consumable_substances(parent = self)
1594 #----------------------------------------------------------------
1595 - def _on_heart_button_pressed(self, event):
1596 gmNetworkTools.open_url_in_browser(url = u'http://qtdrugs.org')
1597 #----------------------------------------------------------------
1598 - def _on_kidneys_button_pressed(self, event):
1599 if self._PRW_component.GetData() is not None: 1600 search_term = self._PRW_component.GetData(as_instance = True) 1601 elif self._PRW_substance.GetData() is not None: 1602 search_term = self._PRW_substance.GetData(as_instance = True) 1603 elif self._PRW_component.GetValue().strip() != u'': 1604 search_term = self._PRW_component.GetValue().strip() 1605 else: 1606 search_term = self._PRW_substance.GetValue().strip() 1607 1608 gmNetworkTools.open_url_in_browser(url = gmMedication.drug2renal_insufficiency_url(search_term = search_term))
1609 #----------------------------------------------------------------
1611 1612 now = gmDateTime.pydt_now_here() 1613 1614 self.__refresh_allergies() 1615 1616 if self.data is None: 1617 return 1618 1619 # do we have a (full) plan ? 1620 if None not in [self.data['started'], self.data['duration']]: 1621 planned_end = self.data['started'] + self.data['duration'] 1622 # the plan hasn't ended so [Per plan] can't apply ;-) 1623 if planned_end > now: 1624 return 1625 self._DP_discontinued.SetData(planned_end) 1626 self._PRW_discontinue_reason.Enable(True) 1627 self._PRW_discontinue_reason.SetValue(u'') 1628 return 1629 1630 # we know started but not duration: apparently the plan is to stop today 1631 if self.data['started'] is not None: 1632 # but we haven't started yet so we can't stop 1633 if self.data['started'] > now: 1634 return 1635 1636 self._DP_discontinued.SetData(now) 1637 self._PRW_discontinue_reason.Enable(True) 1638 self._PRW_discontinue_reason.SetValue(u'')
1639 #----------------------------------------------------------------
1640 - def _on_chbox_long_term_checked(self, event):
1641 if self._CHBOX_long_term.IsChecked() is True: 1642 self._PRW_duration.Enable(False) 1643 self._BTN_discontinued_as_planned.Enable(False) 1644 self._PRW_discontinue_reason.Enable(False) 1645 else: 1646 self._PRW_duration.Enable(True) 1647 self._BTN_discontinued_as_planned.Enable(True) 1648 self._PRW_discontinue_reason.Enable(True) 1649 1650 self.__refresh_allergies()
1651 #----------------------------------------------------------------
1652 - def turn_into_allergy(self, data=None):
1653 if not self.save(): 1654 return False 1655 1656 return turn_substance_intake_into_allergy ( 1657 parent = self, 1658 intake = self.data, 1659 emr = gmPerson.gmCurrentPatient().get_emr() 1660 )
1661 #============================================================
1662 -def delete_substance_intake(parent=None, substance=None):
1663 1664 subst = gmMedication.cSubstanceIntakeEntry(aPK_obj = substance) 1665 msg = _( 1666 '\n' 1667 '[%s]\n' 1668 '\n' 1669 'It may be prudent to edit (before deletion) the details\n' 1670 'of this substance intake entry so as to leave behind\n' 1671 'some indication of why it was deleted.\n' 1672 ) % subst.format() 1673 1674 dlg = gmGuiHelpers.c3ButtonQuestionDlg ( 1675 parent, 1676 -1, 1677 caption = _('Deleting medication / substance intake'), 1678 question = msg, 1679 button_defs = [ 1680 {'label': _('&Edit'), 'tooltip': _('Allow editing of substance intake entry before deletion.'), 'default': True}, 1681 {'label': _('&Delete'), 'tooltip': _('Delete immediately without editing first.')}, 1682 {'label': _('&Cancel'), 'tooltip': _('Abort. Do not delete or edit substance intake entry.')} 1683 ] 1684 ) 1685 1686 edit_first = dlg.ShowModal() 1687 dlg.Destroy() 1688 1689 if edit_first == wx.ID_CANCEL: 1690 return 1691 1692 if edit_first == wx.ID_YES: 1693 edit_intake_of_substance(parent = parent, substance = subst) 1694 delete_it = gmGuiHelpers.gm_show_question ( 1695 aMessage = _('Now delete substance intake entry ?'), 1696 aTitle = _('Deleting medication / substance intake') 1697 ) 1698 else: 1699 delete_it = True 1700 1701 if not delete_it: 1702 return 1703 1704 gmMedication.delete_substance_intake(substance = substance)
1705 #------------------------------------------------------------
1706 -def edit_intake_of_substance(parent = None, substance=None):
1707 ea = cSubstanceIntakeEAPnl(parent = parent, id = -1, substance = substance) 1708 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (substance is not None)) 1709 dlg.SetTitle(gmTools.coalesce(substance, _('Adding medication/non-medication substance intake'), _('Editing medication/non-medication substance intake'))) 1710 dlg.left_extra_button = ( 1711 _('Allergy'), 1712 _('Document an allergy against this substance.'), 1713 ea.turn_into_allergy 1714 ) 1715 if dlg.ShowModal() == wx.ID_OK: 1716 dlg.Destroy() 1717 return True 1718 dlg.Destroy() 1719 return False
1720 1721 #============================================================ 1722 # current substances grid 1723 #------------------------------------------------------------
1724 -def configure_medication_list_template(parent=None):
1725 1726 if parent is None: 1727 parent = wx.GetApp().GetTopWindow() 1728 1729 template = gmFormWidgets.manage_form_templates ( 1730 parent = parent, 1731 template_types = ['current medication list'] 1732 ) 1733 option = u'form_templates.medication_list' 1734 1735 if template is None: 1736 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True) 1737 return None 1738 1739 if template['engine'] != u'L': 1740 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True) 1741 return None 1742 1743 dbcfg = gmCfg.cCfgSQL() 1744 dbcfg.set ( 1745 workplace = gmSurgery.gmCurrentPractice().active_workplace, 1746 option = option, 1747 value = u'%s - %s' % (template['name_long'], template['external_version']) 1748 ) 1749 1750 return template
1751 #------------------------------------------------------------ 1831 #------------------------------------------------------------
1832 -def update_substance_intake_list_from_prescription(parent=None, prescribed_drugs=None, emr=None):
1833 1834 if len(prescribed_drugs) == 0: 1835 return 1836 1837 curr_brands = [ i['pk_brand'] for i in emr.get_current_substance_intake() if i['pk_brand'] is not None ] 1838 new_drugs = [] 1839 for drug in prescribed_drugs: 1840 if drug['pk_brand'] not in curr_brands: 1841 new_drugs.append(drug) 1842 1843 if len(new_drugs) == 0: 1844 return 1845 1846 if parent is None: 1847 parent = wx.GetApp().GetTopWindow() 1848 1849 dlg = gmListWidgets.cItemPickerDlg ( 1850 parent, 1851 -1, 1852 msg = _( 1853 'These brands have been prescribed but are not listed\n' 1854 'in the current medication list of this patient.\n' 1855 '\n' 1856 'Please select those you want added to the medication list.' 1857 ) 1858 ) 1859 dlg.set_columns ( 1860 columns = [_('Newly prescribed drugs')], 1861 columns_right = [_('Add to medication list')] 1862 ) 1863 choices = [ (u'%s %s (%s)' % (d['brand'], d['preparation'], u'; '.join(d['components']))) for d in new_drugs ] 1864 dlg.set_choices ( 1865 choices = choices, 1866 data = new_drugs 1867 ) 1868 dlg.ShowModal() 1869 drugs2add = dlg.get_picks() 1870 dlg.Destroy() 1871 1872 if drugs2add is None: 1873 return 1874 1875 if len(drugs2add) == 0: 1876 return 1877 1878 for drug in drugs2add: 1879 # only add first component since all other components get added by a trigger ... 1880 intake = emr.add_substance_intake ( 1881 pk_component = drug['pk_components'][0], 1882 episode = emr.add_episode(episode_name = gmMedication.DEFAULT_MEDICATION_HISTORY_EPISODE)['pk_episode'], 1883 ) 1884 if intake is None: 1885 continue 1886 intake['intake_is_approved_of'] = True 1887 intake.save() 1888 1889 return
1890 #------------------------------------------------------------
1891 -class cCurrentSubstancesGrid(wx.grid.Grid):
1892 """A grid class for displaying current substance intake. 1893 1894 - does NOT listen to the currently active patient 1895 - thereby it can display any patient at any time 1896 """
1897 - def __init__(self, *args, **kwargs):
1898 1899 wx.grid.Grid.__init__(self, *args, **kwargs) 1900 1901 self.__patient = None 1902 self.__row_data = {} 1903 self.__prev_row = None 1904 self.__prev_tooltip_row = None 1905 self.__prev_cell_0 = None 1906 self.__grouping_mode = u'issue' 1907 self.__filter_show_unapproved = True 1908 self.__filter_show_inactive = True 1909 1910 self.__grouping2col_labels = { 1911 u'issue': [ 1912 _('Health issue'), 1913 _('Substance'), 1914 _('Strength'), 1915 _('Schedule'), 1916 _('Started'), 1917 _('Duration / Until'), 1918 _('Brand'), 1919 _('Advice') 1920 ], 1921 u'brand': [ 1922 _('Brand'), 1923 _('Schedule'), 1924 _('Substance'), 1925 _('Strength'), 1926 _('Started'), 1927 _('Duration / Until'), 1928 _('Health issue'), 1929 _('Advice') 1930 ], 1931 u'episode': [ 1932 _('Episode'), 1933 _('Substance'), 1934 _('Strength'), 1935 _('Schedule'), 1936 _('Started'), 1937 _('Duration / Until'), 1938 _('Brand'), 1939 _('Advice') 1940 ] 1941 } 1942 1943 self.__grouping2order_by_clauses = { 1944 u'issue': u'pk_health_issue nulls first, substance, started', 1945 u'episode': u'pk_health_issue nulls first, episode, substance, started', 1946 u'brand': u'brand nulls last, substance, started' 1947 } 1948 1949 self.__init_ui() 1950 self.__register_events()
1951 #------------------------------------------------------------ 1952 # external API 1953 #------------------------------------------------------------
1954 - def get_selected_cells(self):
1955 1956 sel_block_top_left = self.GetSelectionBlockTopLeft() 1957 sel_block_bottom_right = self.GetSelectionBlockBottomRight() 1958 sel_cols = self.GetSelectedCols() 1959 sel_rows = self.GetSelectedRows() 1960 1961 selected_cells = [] 1962 1963 # individually selected cells (ctrl-click) 1964 selected_cells += self.GetSelectedCells() 1965 1966 # selected rows 1967 selected_cells += list ( 1968 (row, col) 1969 for row in sel_rows 1970 for col in xrange(self.GetNumberCols()) 1971 ) 1972 1973 # selected columns 1974 selected_cells += list ( 1975 (row, col) 1976 for row in xrange(self.GetNumberRows()) 1977 for col in sel_cols 1978 ) 1979 1980 # selection blocks 1981 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()): 1982 selected_cells += [ 1983 (row, col) 1984 for row in xrange(top_left[0], bottom_right[0] + 1) 1985 for col in xrange(top_left[1], bottom_right[1] + 1) 1986 ] 1987 1988 return set(selected_cells)
1989 #------------------------------------------------------------
1990 - def get_selected_rows(self):
1991 rows = {} 1992 1993 for row, col in self.get_selected_cells(): 1994 rows[row] = True 1995 1996 return rows.keys()
1997 #------------------------------------------------------------
1998 - def get_selected_data(self):
1999 return [ self.__row_data[row] for row in self.get_selected_rows() ]
2000 #------------------------------------------------------------
2001 - def repopulate_grid(self):
2002 2003 self.empty_grid() 2004 2005 if self.__patient is None: 2006 return 2007 2008 emr = self.__patient.get_emr() 2009 meds = emr.get_current_substance_intake ( 2010 order_by = self.__grouping2order_by_clauses[self.__grouping_mode], 2011 include_unapproved = self.__filter_show_unapproved, 2012 include_inactive = self.__filter_show_inactive 2013 ) 2014 if not meds: 2015 return 2016 2017 self.BeginBatch() 2018 2019 # columns 2020 labels = self.__grouping2col_labels[self.__grouping_mode] 2021 if self.__filter_show_unapproved: 2022 self.AppendCols(numCols = len(labels) + 1) 2023 else: 2024 self.AppendCols(numCols = len(labels)) 2025 for col_idx in range(len(labels)): 2026 self.SetColLabelValue(col_idx, labels[col_idx]) 2027 if self.__filter_show_unapproved: 2028 self.SetColLabelValue(len(labels), u'OK?') 2029 self.SetColSize(len(labels), 40) 2030 2031 self.AppendRows(numRows = len(meds)) 2032 2033 # loop over data 2034 for row_idx in range(len(meds)): 2035 med = meds[row_idx] 2036 self.__row_data[row_idx] = med 2037 2038 if med['is_currently_active'] is True: 2039 atcs = [] 2040 if med['atc_substance'] is not None: 2041 atcs.append(med['atc_substance']) 2042 # if med['atc_brand'] is not None: 2043 # atcs.append(med['atc_brand']) 2044 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand']) 2045 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],)) 2046 if allg not in [None, False]: 2047 attr = self.GetOrCreateCellAttr(row_idx, 0) 2048 if allg['type'] == u'allergy': 2049 attr.SetTextColour('red') 2050 else: 2051 attr.SetTextColour('yellow') 2052 self.SetRowAttr(row_idx, attr) 2053 else: 2054 attr = self.GetOrCreateCellAttr(row_idx, 0) 2055 attr.SetTextColour('grey') 2056 self.SetRowAttr(row_idx, attr) 2057 2058 if self.__grouping_mode == u'episode': 2059 if med['pk_episode'] is None: 2060 self.__prev_cell_0 = None 2061 epi = gmTools.u_diameter 2062 else: 2063 if self.__prev_cell_0 == med['episode']: 2064 epi = u'' 2065 else: 2066 self.__prev_cell_0 = med['episode'] 2067 epi = gmTools.coalesce(med['episode'], u'') 2068 self.SetCellValue(row_idx, 0, gmTools.wrap(text = epi, width = 40)) 2069 2070 self.SetCellValue(row_idx, 1, med['substance']) 2071 self.SetCellValue(row_idx, 2, u'%s%s' % (med['amount'], med['unit'])) 2072 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u'')) 2073 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d')) 2074 2075 if med['is_long_term']: 2076 self.SetCellValue(row_idx, 5, gmTools.u_infinity) 2077 else: 2078 if med['discontinued'] is None: 2079 if med['duration'] is None: 2080 self.SetCellValue(row_idx, 5, u'') 2081 else: 2082 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days)) 2083 else: 2084 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d')) 2085 2086 if med['pk_brand'] is None: 2087 brand = u'' 2088 else: 2089 if med['fake_brand']: 2090 brand = gmTools.coalesce(med['brand'], u'', _('%s (fake)')) 2091 else: 2092 brand = gmTools.coalesce(med['brand'], u'') 2093 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35)) 2094 2095 elif self.__grouping_mode == u'issue': 2096 if med['pk_health_issue'] is None: 2097 self.__prev_cell_0 = None 2098 issue = u'%s%s' % ( 2099 gmTools.u_diameter, 2100 gmTools.coalesce(med['episode'], u'', u' (%s)') 2101 ) 2102 else: 2103 if self.__prev_cell_0 == med['health_issue']: 2104 issue = u'' 2105 else: 2106 self.__prev_cell_0 = med['health_issue'] 2107 issue = med['health_issue'] 2108 self.SetCellValue(row_idx, 0, gmTools.wrap(text = issue, width = 40)) 2109 2110 self.SetCellValue(row_idx, 1, med['substance']) 2111 self.SetCellValue(row_idx, 2, u'%s%s' % (med['amount'], med['unit'])) 2112 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u'')) 2113 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d')) 2114 2115 if med['is_long_term']: 2116 self.SetCellValue(row_idx, 5, gmTools.u_infinity) 2117 else: 2118 if med['discontinued'] is None: 2119 if med['duration'] is None: 2120 self.SetCellValue(row_idx, 5, u'') 2121 else: 2122 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days)) 2123 else: 2124 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d')) 2125 2126 if med['pk_brand'] is None: 2127 brand = u'' 2128 else: 2129 if med['fake_brand']: 2130 brand = gmTools.coalesce(med['brand'], u'', _('%s (fake)')) 2131 else: 2132 brand = gmTools.coalesce(med['brand'], u'') 2133 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35)) 2134 2135 elif self.__grouping_mode == u'brand': 2136 2137 if med['pk_brand'] is None: 2138 self.__prev_cell_0 = None 2139 brand = gmTools.u_diameter 2140 else: 2141 if self.__prev_cell_0 == med['brand']: 2142 brand = u'' 2143 else: 2144 self.__prev_cell_0 = med['brand'] 2145 if med['fake_brand']: 2146 brand = gmTools.coalesce(med['brand'], u'', _('%s (fake)')) 2147 else: 2148 brand = gmTools.coalesce(med['brand'], u'') 2149 self.SetCellValue(row_idx, 0, gmTools.wrap(text = brand, width = 35)) 2150 2151 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u'')) 2152 self.SetCellValue(row_idx, 2, med['substance']) 2153 self.SetCellValue(row_idx, 3, u'%s%s' % (med['amount'], med['unit'])) 2154 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d')) 2155 2156 if med['is_long_term']: 2157 self.SetCellValue(row_idx, 5, gmTools.u_infinity) 2158 else: 2159 if med['discontinued'] is None: 2160 if med['duration'] is None: 2161 self.SetCellValue(row_idx, 5, u'') 2162 else: 2163 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days)) 2164 else: 2165 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d')) 2166 2167 if med['pk_health_issue'] is None: 2168 issue = u'%s%s' % ( 2169 gmTools.u_diameter, 2170 gmTools.coalesce(med['episode'], u'', u' (%s)') 2171 ) 2172 else: 2173 issue = gmTools.coalesce(med['health_issue'], u'') 2174 self.SetCellValue(row_idx, 6, gmTools.wrap(text = issue, width = 40)) 2175 2176 else: 2177 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode) 2178 2179 if med['notes'] is not None: 2180 self.SetCellValue(row_idx, 7, gmTools.wrap(text = med['notes'], width = 50)) 2181 2182 if self.__filter_show_unapproved: 2183 self.SetCellValue ( 2184 row_idx, 2185 len(labels), 2186 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?') 2187 ) 2188 2189 #self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE) 2190 2191 self.AutoSize() 2192 self.EndBatch()
2193 #------------------------------------------------------------
2194 - def empty_grid(self):
2195 self.BeginBatch() 2196 self.ClearGrid() 2197 # Windows cannot do "nothing", it rather decides to assert() 2198 # on thinking it is supposed to do nothing 2199 if self.GetNumberRows() > 0: 2200 self.DeleteRows(pos = 0, numRows = self.GetNumberRows()) 2201 if self.GetNumberCols() > 0: 2202 self.DeleteCols(pos = 0, numCols = self.GetNumberCols()) 2203 self.EndBatch() 2204 self.__row_data = {} 2205 self.__prev_cell_0 = None
2206 #------------------------------------------------------------
2207 - def show_info_on_entry(self):
2208 2209 if len(self.__row_data) == 0: 2210 return 2211 2212 sel_rows = self.get_selected_rows() 2213 if len(sel_rows) != 1: 2214 return 2215 2216 drug_db = get_drug_database() 2217 if drug_db is None: 2218 return 2219 2220 intake = self.get_selected_data()[0] # just in case 2221 if intake['brand'] is None: 2222 drug_db.show_info_on_substance(substance_intake = intake) 2223 else: 2224 drug_db.show_info_on_drug(substance_intake = intake)
2225 #------------------------------------------------------------
2227 search_term = None 2228 if len(self.__row_data) > 0: 2229 sel_rows = self.get_selected_rows() 2230 if len(sel_rows) == 1: 2231 search_term = self.get_selected_data()[0] 2232 gmNetworkTools.open_url_in_browser(url = gmMedication.drug2renal_insufficiency_url(search_term = search_term))
2233 #------------------------------------------------------------
2234 - def show_cardiac_info(self):
2235 gmNetworkTools.open_url_in_browser(url = u'http://qtdrugs.org')
2236 #------------------------------------------------------------
2237 - def report_ADR(self):
2238 2239 dbcfg = gmCfg.cCfgSQL() 2240 2241 url = dbcfg.get2 ( 2242 option = u'external.urls.report_ADR', 2243 workplace = gmSurgery.gmCurrentPractice().active_workplace, 2244 bias = u'user', 2245 default = u'https://dcgma.org/uaw/meldung.php' # http://www.akdae.de/Arzneimittelsicherheit/UAW-Meldung/UAW-Meldung-online.html 2246 ) 2247 gmNetworkTools.open_url_in_browser(url = url)
2248 #------------------------------------------------------------
2249 - def prescribe(self):
2250 drug_db = get_drug_database() 2251 if drug_db is None: 2252 return 2253 2254 drug_db.reviewer = gmStaff.gmCurrentProvider() 2255 update_substance_intake_list_from_prescription ( 2256 parent = self, 2257 prescribed_drugs = drug_db.prescribe(), 2258 emr = self.__patient.get_emr() 2259 )
2260 #------------------------------------------------------------
2261 - def check_interactions(self):
2262 2263 if len(self.__row_data) == 0: 2264 return 2265 2266 drug_db = get_drug_database() 2267 if drug_db is None: 2268 return 2269 2270 if len(self.get_selected_rows()) > 1: 2271 drug_db.check_interactions(substance_intakes = self.get_selected_data()) 2272 else: 2273 drug_db.check_interactions(substance_intakes = self.__row_data.values())
2274 #------------------------------------------------------------
2275 - def add_substance(self):
2276 edit_intake_of_substance(parent = self, substance = None)
2277 #------------------------------------------------------------
2278 - def edit_substance(self):
2279 2280 rows = self.get_selected_rows() 2281 2282 if len(rows) == 0: 2283 return 2284 2285 if len(rows) > 1: 2286 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit more than one substance at once.'), beep = True) 2287 return 2288 2289 subst = self.get_selected_data()[0] 2290 edit_intake_of_substance(parent = self, substance = subst)
2291 #------------------------------------------------------------
2292 - def delete_substance(self):
2293 2294 rows = self.get_selected_rows() 2295 2296 if len(rows) == 0: 2297 return 2298 2299 if len(rows) > 1: 2300 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True) 2301 return 2302 2303 subst = self.get_selected_data()[0] 2304 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
2305 #------------------------------------------------------------
2307 rows = self.get_selected_rows() 2308 2309 if len(rows) == 0: 2310 return 2311 2312 if len(rows) > 1: 2313 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create allergy from more than one substance at once.'), beep = True) 2314 return 2315 2316 return turn_substance_intake_into_allergy ( 2317 parent = self, 2318 intake = self.get_selected_data()[0], 2319 emr = self.__patient.get_emr() 2320 )
2321 #------------------------------------------------------------
2322 - def print_medication_list(self):
2323 # there could be some filtering/user interaction going on here 2324 print_medication_list(parent = self)
2325 #------------------------------------------------------------
2326 - def get_row_tooltip(self, row=None):
2327 2328 try: 2329 entry = self.__row_data[row] 2330 except KeyError: 2331 return u' ' 2332 2333 emr = self.__patient.get_emr() 2334 atcs = [] 2335 if entry['atc_substance'] is not None: 2336 atcs.append(entry['atc_substance']) 2337 # if entry['atc_brand'] is not None: 2338 # atcs.append(entry['atc_brand']) 2339 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],), brand = entry['brand']) 2340 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],)) 2341 2342 tt = _('Substance intake entry (%s, %s) [#%s] \n') % ( 2343 gmTools.bool2subst ( 2344 boolean = entry['is_currently_active'], 2345 true_return = gmTools.bool2subst ( 2346 boolean = entry['seems_inactive'], 2347 true_return = _('active, needs check'), 2348 false_return = _('active'), 2349 none_return = _('assumed active') 2350 ), 2351 false_return = _('inactive') 2352 ), 2353 gmTools.bool2subst ( 2354 boolean = entry['intake_is_approved_of'], 2355 true_return = _('approved'), 2356 false_return = _('unapproved') 2357 ), 2358 entry['pk_substance_intake'] 2359 ) 2360 2361 if allg not in [None, False]: 2362 certainty = gmTools.bool2subst(allg['definite'], _('definite'), _('suspected')) 2363 tt += u'\n' 2364 tt += u' !! ---- Cave ---- !!\n' 2365 tt += u' %s (%s): %s (%s)\n' % ( 2366 allg['l10n_type'], 2367 certainty, 2368 allg['descriptor'], 2369 gmTools.coalesce(allg['reaction'], u'')[:40] 2370 ) 2371 tt += u'\n' 2372 2373 tt += u' ' + _('Substance: %s [#%s]\n') % (entry['substance'], entry['pk_substance']) 2374 tt += u' ' + _('Preparation: %s\n') % entry['preparation'] 2375 tt += u' ' + _('Amount per dose: %s%s') % (entry['amount'], entry['unit']) 2376 if entry.ddd is not None: 2377 tt += u' (DDD: %s %s)' % (entry.ddd['ddd'], entry.ddd['unit']) 2378 tt += u'\n' 2379 tt += gmTools.coalesce(entry['atc_substance'], u'', _(' ATC (substance): %s\n')) 2380 2381 tt += u'\n' 2382 2383 tt += gmTools.coalesce ( 2384 entry['brand'], 2385 u'', 2386 _(' Brand name: %%s [#%s]\n') % entry['pk_brand'] 2387 ) 2388 tt += gmTools.coalesce(entry['atc_brand'], u'', _(' ATC (brand): %s\n')) 2389 2390 tt += u'\n' 2391 2392 tt += gmTools.coalesce(entry['schedule'], u'', _(' Regimen: %s\n')) 2393 2394 if entry['is_long_term']: 2395 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity) 2396 else: 2397 if entry['duration'] is None: 2398 duration = u'' 2399 else: 2400 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(entry['duration'], gmDateTime.acc_days)) 2401 2402 tt += _(' Started %s%s%s\n') % ( 2403 entry['started'].strftime('%Y %B %d').decode(gmI18N.get_encoding()), 2404 duration, 2405 gmTools.bool2subst(entry['is_long_term'], _(' (long-term)'), _(' (short-term)'), u'') 2406 ) 2407 2408 if entry['discontinued'] is not None: 2409 tt += _(' Discontinued %s\n') % ( 2410 entry['discontinued'].strftime('%Y %B %d').decode(gmI18N.get_encoding()), 2411 ) 2412 tt += _(' Reason: %s\n') % entry['discontinue_reason'] 2413 2414 tt += u'\n' 2415 2416 tt += gmTools.coalesce(entry['aim'], u'', _(' Aim: %s\n')) 2417 tt += gmTools.coalesce(entry['episode'], u'', _(' Episode: %s\n')) 2418 tt += gmTools.coalesce(entry['health_issue'], u'', _(' Health issue: %s\n')) 2419 tt += gmTools.coalesce(entry['notes'], u'', _(' Advice: %s\n')) 2420 2421 tt += u'\n' 2422 2423 tt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % ({ 2424 'row_ver': entry['row_version'], 2425 'mod_when': entry['modified_when'].strftime('%c').decode(gmI18N.get_encoding()), 2426 'mod_by': entry['modified_by'] 2427 }) 2428 2429 return tt
2430 #------------------------------------------------------------ 2431 # internal helpers 2432 #------------------------------------------------------------
2433 - def __init_ui(self):
2434 self.CreateGrid(0, 1) 2435 self.EnableEditing(0) 2436 self.EnableDragGridSize(1) 2437 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows) 2438 2439 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER) 2440 2441 self.SetRowLabelSize(0) 2442 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
2443 #------------------------------------------------------------ 2444 # properties 2445 #------------------------------------------------------------
2446 - def _get_patient(self):
2447 return self.__patient
2448
2449 - def _set_patient(self, patient):
2450 self.__patient = patient 2451 self.repopulate_grid()
2452 2453 patient = property(_get_patient, _set_patient) 2454 #------------------------------------------------------------
2455 - def _get_grouping_mode(self):
2456 return self.__grouping_mode
2457
2458 - def _set_grouping_mode(self, mode):
2459 self.__grouping_mode = mode 2460 self.repopulate_grid()
2461 2462 grouping_mode = property(_get_grouping_mode, _set_grouping_mode) 2463 #------------------------------------------------------------
2465 return self.__filter_show_unapproved
2466
2467 - def _set_filter_show_unapproved(self, val):
2468 self.__filter_show_unapproved = val 2469 self.repopulate_grid()
2470 2471 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved) 2472 #------------------------------------------------------------
2473 - def _get_filter_show_inactive(self):
2474 return self.__filter_show_inactive
2475
2476 - def _set_filter_show_inactive(self, val):
2477 self.__filter_show_inactive = val 2478 self.repopulate_grid()
2479 2480 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive) 2481 #------------------------------------------------------------ 2482 # event handling 2483 #------------------------------------------------------------
2484 - def __register_events(self):
2485 # dynamic tooltips: GridWindow, GridRowLabelWindow, GridColLabelWindow, GridCornerLabelWindow 2486 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells) 2487 #self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels) 2488 #self.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_col_labels) 2489 2490 # editing cells 2491 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
2492 #------------------------------------------------------------
2493 - def __on_mouse_over_cells(self, evt):
2494 """Calculate where the mouse is and set the tooltip dynamically.""" 2495 2496 # Use CalcUnscrolledPosition() to get the mouse position within the 2497 # entire grid including what's offscreen 2498 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY()) 2499 2500 # use this logic to prevent tooltips outside the actual cells 2501 # apply to GetRowSize, too 2502 # tot = 0 2503 # for col in xrange(self.NumberCols): 2504 # tot += self.GetColSize(col) 2505 # if xpos <= tot: 2506 # self.tool_tip.Tip = 'Tool tip for Column %s' % ( 2507 # self.GetColLabelValue(col)) 2508 # break 2509 # else: # mouse is in label area beyond the right-most column 2510 # self.tool_tip.Tip = '' 2511 2512 row, col = self.XYToCell(x, y) 2513 2514 if row == self.__prev_tooltip_row: 2515 return 2516 2517 self.__prev_tooltip_row = row 2518 2519 try: 2520 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row)) 2521 except KeyError: 2522 pass
2523 #------------------------------------------------------------
2524 - def __on_cell_left_dclicked(self, evt):
2525 row = evt.GetRow() 2526 data = self.__row_data[row] 2527 edit_intake_of_substance(parent = self, substance = data)
2528 #============================================================ 2529 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl 2530
2531 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
2532 2533 """Panel holding a grid with current substances. Used as notebook page.""" 2534
2535 - def __init__(self, *args, **kwargs):
2536 2537 wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl.__init__(self, *args, **kwargs) 2538 gmRegetMixin.cRegetOnPaintMixin.__init__(self) 2539 2540 self.__register_interests()
2541 #----------------------------------------------------- 2542 # reget-on-paint mixin API 2543 #-----------------------------------------------------
2544 - def _populate_with_data(self):
2545 """Populate cells with data from model.""" 2546 pat = gmPerson.gmCurrentPatient() 2547 if pat.connected: 2548 self._grid_substances.patient = pat 2549 else: 2550 self._grid_substances.patient = None 2551 return True
2552 #-------------------------------------------------------- 2553 # event handling 2554 #--------------------------------------------------------
2555 - def __register_interests(self):
2556 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection) 2557 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget) 2558 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
2559 # active_substance_mod_db 2560 # substance_brand_mod_db 2561 #--------------------------------------------------------
2562 - def _on_pre_patient_selection(self):
2563 wx.CallAfter(self.__on_pre_patient_selection)
2564 #--------------------------------------------------------
2565 - def __on_pre_patient_selection(self):
2566 self._grid_substances.patient = None
2567 #--------------------------------------------------------
2568 - def _on_add_button_pressed(self, event):
2569 self._grid_substances.add_substance()
2570 #--------------------------------------------------------
2571 - def _on_edit_button_pressed(self, event):
2572 self._grid_substances.edit_substance()
2573 #--------------------------------------------------------
2574 - def _on_delete_button_pressed(self, event):
2575 self._grid_substances.delete_substance()
2576 #--------------------------------------------------------
2577 - def _on_info_button_pressed(self, event):
2578 self._grid_substances.show_info_on_entry()
2579 #--------------------------------------------------------
2580 - def _on_interactions_button_pressed(self, event):
2581 self._grid_substances.check_interactions()
2582 #--------------------------------------------------------
2583 - def _on_issue_grouping_selected(self, event):
2584 self._grid_substances.grouping_mode = 'issue'
2585 #--------------------------------------------------------
2586 - def _on_episode_grouping_selected(self, event):
2587 self._grid_substances.grouping_mode = 'episode'
2588 #--------------------------------------------------------
2589 - def _on_brand_grouping_selected(self, event):
2590 self._grid_substances.grouping_mode = 'brand'
2591 #--------------------------------------------------------
2592 - def _on_show_unapproved_checked(self, event):
2593 self._grid_substances.filter_show_unapproved = self._CHBOX_show_unapproved.GetValue()
2594 #--------------------------------------------------------
2595 - def _on_show_inactive_checked(self, event):
2596 self._grid_substances.filter_show_inactive = self._CHBOX_show_inactive.GetValue()
2597 #--------------------------------------------------------
2598 - def _on_print_button_pressed(self, event):
2599 self._grid_substances.print_medication_list()
2600 #--------------------------------------------------------
2601 - def _on_allergy_button_pressed(self, event):
2602 self._grid_substances.create_allergy_from_substance()
2603 #--------------------------------------------------------
2604 - def _on_button_kidneys_pressed(self, event):
2605 self._grid_substances.show_renal_insufficiency_info()
2606 #--------------------------------------------------------
2607 - def _on_button_heart_pressed(self, event):
2608 self._grid_substances.show_cardiac_info()
2609 #--------------------------------------------------------
2610 - def _on_adr_button_pressed(self, event):
2611 self._grid_substances.report_ADR()
2612 #--------------------------------------------------------
2613 - def _on_rx_button_pressed(self, event):
2614 self._grid_substances.prescribe()
2615 #============================================================ 2616 # main 2617 #------------------------------------------------------------ 2618 if __name__ == '__main__': 2619 2620 if len(sys.argv) < 2: 2621 sys.exit() 2622 2623 if sys.argv[1] != 'test': 2624 sys.exit() 2625 2626 from Gnumed.pycommon import gmI18N 2627 2628 gmI18N.activate_locale() 2629 gmI18N.install_domain(domain = 'gnumed') 2630 2631 #---------------------------------------- 2632 app = wx.PyWidgetTester(size = (600, 600)) 2633 #app.SetWidget(cATCPhraseWheel, -1) 2634 app.SetWidget(cSubstancePhraseWheel, -1) 2635 app.MainLoop() 2636 2637 #============================================================ 2638