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