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

Source Code for Module Gnumed.wxpython.gmSubstanceMgmtWidgets

   1  # -*- coding: utf-8 -*- 
   2   
   3  #from __future__ import print_function 
   4   
   5  __doc__ = """GNUmed drug / substance reference widgets.""" 
   6   
   7  #================================================================ 
   8  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
   9  __license__ = "GPL v2 or later" 
  10   
  11  import logging 
  12  import sys 
  13  import os.path 
  14  import decimal 
  15   
  16   
  17  import wx 
  18   
  19   
  20  if __name__ == '__main__': 
  21          sys.path.insert(0, '../../') 
  22          from Gnumed.pycommon import gmI18N 
  23          gmI18N.activate_locale() 
  24          gmI18N.install_domain(domain = 'gnumed') 
  25   
  26  from Gnumed.pycommon import gmDispatcher 
  27  from Gnumed.pycommon import gmCfg 
  28  from Gnumed.pycommon import gmShellAPI 
  29  from Gnumed.pycommon import gmTools 
  30  from Gnumed.pycommon import gmMatchProvider 
  31   
  32  from Gnumed.business import gmPerson 
  33  from Gnumed.business import gmPraxis 
  34  from Gnumed.business import gmMedication 
  35  from Gnumed.business import gmDrugDataSources 
  36  from Gnumed.business import gmATC 
  37   
  38  from Gnumed.wxpython import gmGuiHelpers 
  39  from Gnumed.wxpython import gmEditArea 
  40  from Gnumed.wxpython import gmCfgWidgets 
  41  from Gnumed.wxpython import gmListWidgets 
  42  from Gnumed.wxpython import gmPhraseWheel 
  43   
  44   
  45  _log = logging.getLogger('gm.ui') 
  46   
  47  #============================================================ 
  48  # generic drug database access 
  49  #------------------------------------------------------------ 
50 -def configure_drug_data_source(parent=None):
51 gmCfgWidgets.configure_string_from_list_option ( 52 parent = parent, 53 message = _( 54 '\n' 55 'Please select the default drug data source from the list below.\n' 56 '\n' 57 'Note that to actually use it you need to have the database installed, too.' 58 ), 59 option = 'external.drug_data.default_source', 60 bias = 'user', 61 default_value = None, 62 choices = gmDrugDataSources.drug_data_source_interfaces.keys(), 63 columns = [_('Drug data source')], 64 data = gmDrugDataSources.drug_data_source_interfaces.keys(), 65 caption = _('Configuring default drug data source') 66 )
67 68 #============================================================
69 -def get_drug_database(parent=None, patient=None):
70 dbcfg = gmCfg.cCfgSQL() 71 72 # load from option 73 default_db = dbcfg.get2 ( 74 option = 'external.drug_data.default_source', 75 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 76 bias = 'workplace' 77 ) 78 79 # not configured -> try to configure 80 if default_db is None: 81 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True) 82 configure_drug_data_source(parent = parent) 83 default_db = dbcfg.get2 ( 84 option = 'external.drug_data.default_source', 85 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 86 bias = 'workplace' 87 ) 88 # still not configured -> return 89 if default_db is None: 90 gmGuiHelpers.gm_show_error ( 91 aMessage = _('There is no default drug database configured.'), 92 aTitle = _('Jumping to drug database') 93 ) 94 return None 95 96 # now it MUST be configured (either newly or previously) 97 # but also *validly* ? 98 try: 99 drug_db = gmDrugDataSources.drug_data_source_interfaces[default_db]() 100 except KeyError: 101 # not valid 102 _log.error('faulty default drug data source configuration: %s', default_db) 103 # try to configure 104 configure_drug_data_source(parent = parent) 105 default_db = dbcfg.get2 ( 106 option = 'external.drug_data.default_source', 107 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 108 bias = 'workplace' 109 ) 110 # deconfigured or aborted (and thusly still misconfigured) ? 111 try: 112 drug_db = gmDrugDataSources.drug_data_source_interfaces[default_db]() 113 except KeyError: 114 _log.error('still faulty default drug data source configuration: %s', default_db) 115 return None 116 117 if patient is not None: 118 drug_db.patient = patient 119 120 return drug_db
121 122 #============================================================
123 -def jump_to_drug_database(patient=None):
124 drug_db = get_drug_database(patient = patient) 125 if drug_db is None: 126 return 127 drug_db.switch_to_frontend(blocking = False)
128 129 #============================================================
130 -def jump_to_ifap_deprecated(import_drugs=False, emr=None):
131 132 if import_drugs and (emr is None): 133 gmDispatcher.send('statustext', msg = _('Cannot import drugs from IFAP into chart without chart.')) 134 return False 135 136 dbcfg = gmCfg.cCfgSQL() 137 138 ifap_cmd = dbcfg.get2 ( 139 option = 'external.ifap-win.shell_command', 140 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 141 bias = 'workplace', 142 default = 'wine "C:\Ifapwin\WIAMDB.EXE"' 143 ) 144 found, binary = gmShellAPI.detect_external_binary(ifap_cmd) 145 if not found: 146 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd) 147 return False 148 ifap_cmd = binary 149 150 if import_drugs: 151 transfer_file = os.path.expanduser(dbcfg.get2 ( 152 option = 'external.ifap-win.transfer_file', 153 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 154 bias = 'workplace', 155 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv' 156 )) 157 # file must exist for Ifap to write into it 158 try: 159 f = io.open(transfer_file, mode = 'wt').close() 160 except IOError: 161 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file) 162 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file) 163 return False 164 165 wx.BeginBusyCursor() 166 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs) 167 wx.EndBusyCursor() 168 169 if import_drugs: 170 # COMMENT: this file must exist PRIOR to invoking IFAP 171 # COMMENT: or else IFAP will not write data into it ... 172 try: 173 csv_file = io.open(transfer_file, mode = 'rt', encoding = 'latin1') # FIXME: encoding unknown 174 except: 175 _log.exception('cannot access [%s]', fname) 176 csv_file = None 177 178 if csv_file is not None: 179 import csv 180 csv_lines = csv.DictReader ( 181 csv_file, 182 fieldnames = 'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(), 183 delimiter = ';' 184 ) 185 # dummy episode for now 186 epi = emr.add_episode(episode_name = _('Current medication')) 187 for line in csv_lines: 188 narr = '%sx %s %s %s (\u2258 %s %s) von %s (%s)' % ( 189 line['Packungszahl'].strip(), 190 line['Handelsname'].strip(), 191 line['Form'].strip(), 192 line['Packungsgr\xf6\xdfe'].strip(), 193 line['Abpackungsmenge'].strip(), 194 line['Einheit'].strip(), 195 line['Hersteller'].strip(), 196 line['PZN'].strip() 197 ) 198 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi) 199 csv_file.close() 200 201 return True
202 203 #============================================================ 204 # substances widgets 205 #------------------------------------------------------------
206 -def edit_substance(parent=None, substance=None, single_entry=False):
207 208 if substance is not None: 209 if substance.is_in_use_by_patients: 210 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True) 211 return False 212 213 ea = cSubstanceEAPnl(parent, -1) 214 ea.data = substance 215 ea.mode = gmTools.coalesce(substance, 'new', 'edit') 216 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 217 dlg.SetTitle(gmTools.coalesce(substance, _('Adding new substance'), _('Editing substance'))) 218 if dlg.ShowModal() == wx.ID_OK: 219 dlg.Destroy() 220 return True 221 dlg.Destroy() 222 return False
223 224 #------------------------------------------------------------
225 -def manage_substances(parent=None):
226 227 if parent is None: 228 parent = wx.GetApp().GetTopWindow() 229 230 #------------------------------------------------------------ 231 def add_from_db(substance): 232 drug_db = get_drug_database(parent = parent) 233 if drug_db is None: 234 return False 235 drug_db.import_drugs() 236 return True
237 238 #------------------------------------------------------------ 239 def edit(substance=None): 240 return edit_substance(parent = parent, substance = substance, single_entry = (substance is not None)) 241 242 #------------------------------------------------------------ 243 def delete(substance): 244 if substance.is_in_use_by_patients: 245 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True) 246 return False 247 return gmMedication.delete_substance(pk_substance = substance['pk_substance']) 248 249 #------------------------------------------------------------ 250 def get_item_tooltip(substance): 251 if not isinstance(substance, gmMedication.cSubstance): 252 return None 253 return substance.format() 254 255 #------------------------------------------------------------ 256 def refresh(lctrl): 257 substs = gmMedication.get_substances(order_by = 'substance') 258 items = [ [ 259 s['substance'], 260 gmTools.coalesce(s['atc'], ''), 261 gmTools.coalesce(s['intake_instructions'], ''), 262 s['pk_substance'] 263 ] for s in substs ] 264 lctrl.set_string_items(items) 265 lctrl.set_data(substs) 266 267 #------------------------------------------------------------ 268 gmListWidgets.get_choices_from_list ( 269 parent = parent, 270 caption = _('Substances registered with GNUmed.'), 271 columns = [_('Substance'), 'ATC', _('Instructions'), '#'], 272 single_selection = True, 273 new_callback = edit, 274 edit_callback = edit, 275 delete_callback = delete, 276 refresh_callback = refresh, 277 left_extra_button = (_('Import'), _('Import substances from a drug database.'), add_from_db), 278 list_tooltip_callback = get_item_tooltip 279 ) 280 281 #------------------------------------------------------------ 282 from Gnumed.wxGladeWidgets import wxgSubstanceEAPnl 283
284 -class cSubstanceEAPnl(wxgSubstanceEAPnl.wxgSubstanceEAPnl, gmEditArea.cGenericEditAreaMixin):
285
286 - def __init__(self, *args, **kwargs):
287 288 try: 289 data = kwargs['substance'] 290 del kwargs['substance'] 291 except KeyError: 292 data = None 293 294 wxgSubstanceEAPnl.wxgSubstanceEAPnl.__init__(self, *args, **kwargs) 295 gmEditArea.cGenericEditAreaMixin.__init__(self) 296 297 # Code using this mixin should set mode and data 298 # after instantiating the class: 299 self.mode = 'new' 300 self.data = data 301 if data is not None: 302 self.mode = 'edit' 303 304 self.__init_ui()
305 306 #----------------------------------------------------------------
307 - def __init_ui(self):
308 self._LCTRL_loincs.set_columns([_('LOINC'), _('Interval'), _('Comment')])
309 310 #---------------------------------------------------------------- 311 # generic Edit Area mixin API 312 #----------------------------------------------------------------
313 - def _valid_for_save(self):
314 315 validity = True 316 317 if self._TCTRL_substance.GetValue().strip() == '': 318 validity = False 319 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = False) 320 self._TCTRL_substance.SetFocus() 321 else: 322 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = True) 323 324 if validity is False: 325 self.status_message = _('Cannot save: Substance name missing.') 326 327 return validity
328 329 #----------------------------------------------------------------
330 - def _save_as_new(self):
331 subst = gmMedication.create_substance ( 332 substance = self._TCTRL_substance.GetValue().strip(), 333 atc = self._PRW_atc.GetData() 334 ) 335 subst['intake_instructions'] = self._TCTRL_instructions.GetValue().strip() 336 success, data = subst.save() 337 if not success: 338 err, msg = data 339 _log.error(err) 340 _log.error(msg) 341 self.status_message = _('Error saving substance. %s') % msg 342 return False 343 344 loincs = self._LCTRL_loincs.item_data 345 if len(loincs) > 0: 346 subst.loincs = loincs 347 348 self.data = subst 349 return True
350 351 #----------------------------------------------------------------
352 - def _save_as_update(self):
353 self.data['substance'] = self._TCTRL_substance.GetValue().strip() 354 self.data['atc'] = self._PRW_atc.GetData() 355 self.data['intake_instructions'] = self._TCTRL_instructions.GetValue().strip() 356 success, data = self.data.save() 357 if not success: 358 err, msg = data 359 _log.error(err) 360 _log.error(msg) 361 self.status_message = _('Error saving substance. %s') % msg 362 return False 363 364 loincs = self._LCTRL_loincs.item_data 365 if len(loincs) > 0: 366 self.data.loincs = loincs 367 368 return True
369 370 #----------------------------------------------------------------
371 - def _refresh_as_new(self):
372 self._TCTRL_substance.SetValue('') 373 self._PRW_atc.SetText('', None) 374 self._TCTRL_instructions.SetValue('') 375 self._PRW_loinc.SetText('', None) 376 self._LCTRL_loincs.set_string_items() 377 378 self._TCTRL_substance.SetFocus()
379 380 #----------------------------------------------------------------
381 - def _refresh_from_existing(self):
382 self._TCTRL_substance.SetValue(self.data['substance']) 383 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc'], ''), self.data['atc']) 384 self._TCTRL_instructions.SetValue(gmTools.coalesce(self.data['intake_instructions'], '')) 385 self._PRW_loinc.SetText('', None) 386 if len(self.data['loincs']) == 0: 387 self._LCTRL_loincs.set_string_items() 388 else: 389 self._LCTRL_loincs.set_string_items([ [l['loinc'], gmTools.coalesce(l['max_age_str'], ''), gmTools.coalesce(l['comment'], '')] for l in self.data['loincs' ]]) 390 self._LCTRL_loincs.set_data([ l['loinc'] for l in self.data['loincs'] ]) 391 392 self._TCTRL_substance.SetFocus()
393 394 #----------------------------------------------------------------
396 self._refresh_as_new()
397 398 #---------------------------------------------------------------- 399 # event handlers 400 #----------------------------------------------------------------
401 - def _on_add_loinc_button_pressed(self, event):
402 event.Skip() 403 if (self._PRW_loinc.GetData() is None) and (self._PRW_loinc.GetValue().strip() == ''): 404 return 405 406 if self._PRW_loinc.GetData() is None: 407 data = self._PRW_loinc.GetValue().strip().split(':')[0] 408 item = [data, '', ''] 409 else: 410 data = self._PRW_loinc.GetData() 411 item = [data, '', ''] 412 self._LCTRL_loincs.append_string_items_and_data([item], new_data = [data], allow_dupes = False)
413 414 #----------------------------------------------------------------
415 - def _on_remove_loincs_button_pressed(self, event):
416 event.Skip()
417 418 #------------------------------------------------------------
419 -class cSubstancePhraseWheel(gmPhraseWheel.cPhraseWheel):
420
421 - def __init__(self, *args, **kwargs):
422 423 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 424 query = """ 425 SELECT DISTINCT ON (list_label) 426 list_label, 427 field_label, 428 data 429 FROM ( 430 SELECT 431 description AS list_label, 432 description AS field_label, 433 pk AS data 434 FROM ref.substance 435 WHERE 436 description %(fragment_condition)s 437 438 UNION ALL 439 440 SELECT 441 term AS list_label, 442 term AS field_label, 443 NULL::integer AS data 444 FROM ref.atc 445 WHERE 446 term %(fragment_condition)s 447 448 ) AS candidates 449 ORDER BY list_label 450 LIMIT 50 451 """ 452 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 453 mp.setThresholds(1, 2, 4) 454 # mp.word_separators = '[ \t=+&:@]+' 455 self.SetToolTip(_('The substance name.')) 456 self.matcher = mp 457 self.selection_only = False 458 self.phrase_separators = None
459 460 #--------------------------------------------------------
461 - def _data2instance(self):
462 return gmMedication.cSubstance(aPK_obj = self.GetData(as_instance = False, can_create = False))
463 464 #============================================================ 465 # substance dose widgets 466 #------------------------------------------------------------
467 -def edit_substance_dose(parent=None, substance_dose=None, single_entry=False):
468 469 if substance_dose is not None: 470 if substance_dose.is_in_use_by_patients: 471 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True) 472 return False 473 474 ea = cSubstanceDoseEAPnl(parent, -1) 475 ea.data = substance_dose 476 ea.mode = gmTools.coalesce(substance_dose, 'new', 'edit') 477 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 478 dlg.SetTitle(gmTools.coalesce(substance_dose, _('Adding new substance dose'), _('Editing substance dose'))) 479 if dlg.ShowModal() == wx.ID_OK: 480 dlg.Destroy() 481 return True 482 dlg.Destroy() 483 return False
484 485 #------------------------------------------------------------
486 -def manage_substance_doses(parent=None, vaccine_indications_only=False):
487 488 if parent is None: 489 parent = wx.GetApp().GetTopWindow() 490 491 #------------------------------------------------------------ 492 def add_from_db(substance): 493 drug_db = get_drug_database(parent = parent) 494 if drug_db is None: 495 return False 496 drug_db.import_drugs() 497 return True
498 499 #------------------------------------------------------------ 500 def edit(substance_dose=None): 501 return edit_substance_dose(parent = parent, substance_dose = substance_dose, single_entry = (substance_dose is not None)) 502 503 #------------------------------------------------------------ 504 def delete(substance_dose): 505 if substance_dose.is_in_use_by_patients: 506 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True) 507 return False 508 return gmMedication.delete_substance_dose(pk_dose = substance_dose['pk_dose']) 509 510 #------------------------------------------------------------ 511 def refresh(lctrl): 512 if vaccine_indications_only: 513 substs = [ s for s in gmMedication.get_substance_doses(order_by = 'substance') if gmTools.coalesce(s['atc_substance'], '').startswith('J07') ] 514 else: 515 substs = gmMedication.get_substance_doses(order_by = 'substance') 516 items = [ [ 517 s['substance'], 518 s['amount'], 519 s.formatted_units, 520 gmTools.coalesce(s['atc_substance'], ''), 521 gmTools.coalesce(s['intake_instructions'], ''), 522 s['pk_dose'] 523 ] for s in substs ] 524 lctrl.set_string_items(items) 525 lctrl.set_data(substs) 526 527 #------------------------------------------------------------ 528 def get_item_tooltip(substance_dose): 529 if not isinstance(substance_dose, gmMedication.cSubstanceDose): 530 return None 531 return substance_dose.format(include_loincs = True) 532 533 #------------------------------------------------------------ 534 return gmListWidgets.get_choices_from_list ( 535 parent = parent, 536 caption = _('Substance doses registered with GNUmed.'), 537 columns = [_('Substance'), _('Amount'), _('Unit'), 'ATC', _('Instructions'), '#'], 538 single_selection = False, 539 can_return_empty = False, 540 new_callback = edit, 541 edit_callback = edit, 542 delete_callback = delete, 543 refresh_callback = refresh, 544 left_extra_button = (_('Import'), _('Import substance doses from a drug database.'), add_from_db), 545 list_tooltip_callback = get_item_tooltip 546 ) 547 548 #------------------------------------------------------------ 549 from Gnumed.wxGladeWidgets import wxgSubstanceDoseEAPnl 550
551 -class cSubstanceDoseEAPnl(wxgSubstanceDoseEAPnl.wxgSubstanceDoseEAPnl, gmEditArea.cGenericEditAreaMixin):
552
553 - def __init__(self, *args, **kwargs):
554 555 try: 556 data = kwargs['substance'] 557 del kwargs['substance'] 558 except KeyError: 559 data = None 560 561 wxgSubstanceDoseEAPnl.wxgSubstanceDoseEAPnl.__init__(self, *args, **kwargs) 562 gmEditArea.cGenericEditAreaMixin.__init__(self) 563 564 # Code using this mixin should set mode and data 565 # after instantiating the class: 566 self.mode = 'new' 567 self.data = data 568 if data is not None: 569 self.mode = 'edit' 570 571 self.__init_ui()
572 573 #----------------------------------------------------------------
574 - def __init_ui(self):
575 self._PRW_substance.add_callback_on_modified(callback = self.__refresh_info) 576 self._PRW_substance.add_callback_on_selection(callback = self.__refresh_info) 577 self._TCTRL_amount.add_callback_on_modified(callback = self.__refresh_info) 578 self._PRW_unit.add_callback_on_modified(callback = self.__refresh_info) 579 self._PRW_unit.add_callback_on_selection(callback = self.__refresh_info) 580 self._PRW_dose_unit.add_callback_on_modified(callback = self.__refresh_info) 581 self._PRW_dose_unit.add_callback_on_selection(callback = self.__refresh_info)
582 583 #----------------------------------------------------------------
584 - def __refresh_info(self, change='dummy'):
585 subst = self._PRW_substance.GetValue().strip() 586 if subst == '': 587 subst = '?' 588 amount = self._TCTRL_amount.GetValue().strip() 589 if amount == '': 590 amount = '?' 591 unit = self._PRW_unit.GetValue().strip() 592 if unit == '': 593 unit = '?' 594 dose_unit = self._PRW_dose_unit.GetValue().strip() 595 if dose_unit == '': 596 dose_unit = _('<delivery unit>') 597 self._LBL_info.SetLabel('%s %s %s / %s' % (subst, amount, unit, dose_unit)) 598 self.Refresh()
599 600 #---------------------------------------------------------------- 601 # generic Edit Area mixin API 602 #----------------------------------------------------------------
603 - def _valid_for_save(self):
604 605 validity = True 606 607 if self._PRW_substance.GetValue().strip() == '': 608 validity = False 609 self._PRW_substance.display_as_valid(valid = False) 610 self._PRW_substance.SetFocus() 611 else: 612 self._PRW_substance.display_as_valid(valid = True) 613 614 try: 615 decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')) 616 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 617 except (TypeError, decimal.InvalidOperation): 618 validity = False 619 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 620 self._TCTRL_amount.SetFocus() 621 622 if self._PRW_unit.GetValue().strip() == '': 623 validity = False 624 self._PRW_unit.display_as_valid(valid = False) 625 self._PRW_unit.SetFocus() 626 else: 627 self._PRW_unit.display_as_valid(valid = True) 628 629 if validity is False: 630 self.status_message = _('Cannot save substance dose. Missing essential input.') 631 632 return validity
633 634 #----------------------------------------------------------------
635 - def _save_as_new(self):
636 dose = gmMedication.create_substance_dose ( 637 pk_substance = self._PRW_substance.GetData(), 638 substance = self._PRW_substance.GetValue().strip(), 639 amount = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')), 640 unit = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None)), 641 dose_unit = gmTools.coalesce(self._PRW_dose_unit.GetData(), self._PRW_dose_unit.GetValue().strip(), function_initial = ('strip', None)) 642 ) 643 success, data = dose.save() 644 if not success: 645 err, msg = data 646 _log.error(err) 647 _log.error(msg) 648 self.status_message = _('Cannot create substance dose. %s') % msg 649 return False 650 651 self.data = dose 652 return True
653 654 #----------------------------------------------------------------
655 - def _save_as_update(self):
656 #self.data['pk_substance'] = self._PRW_substance.GetData() 657 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')) 658 self.data['unit'] = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None)) 659 self.data['dose_unit'] = gmTools.coalesce(self._PRW_dose_unit.GetData(), self._PRW_dose_unit.GetValue().strip(), function_initial = ('strip', None)) 660 success, data = self.data.save() 661 662 if not success: 663 err, msg = data 664 _log.error(err) 665 _log.error(msg) 666 self.status_message = _('Cannot save substance dose. %s') % msg 667 return False 668 669 return True
670 671 #----------------------------------------------------------------
672 - def _refresh_as_new(self):
673 self._PRW_substance.SetText('', None) 674 self._TCTRL_amount.SetValue('') 675 self._PRW_unit.SetText('', None) 676 self._PRW_dose_unit.SetText('', None) 677 self._LBL_info.SetLabel('') 678 679 self._PRW_substance.SetFocus()
680 681 #----------------------------------------------------------------
682 - def _refresh_from_existing(self):
683 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance']) 684 self._PRW_substance.Disable() 685 self._TCTRL_amount.SetValue('%s' % self.data['amount']) 686 self._PRW_unit.SetText(self.data['unit'], self.data['unit']) 687 self._PRW_dose_unit.SetText(gmTools.coalesce(self.data['dose_unit'], ''), self.data['dose_unit']) 688 689 self._PRW_substance.SetFocus()
690 691 #----------------------------------------------------------------
693 self._refresh_as_new()
694 695 #============================================================ 696 # drug component widgets 697 #------------------------------------------------------------
698 -def manage_drug_components(parent=None):
699 700 if parent is None: 701 parent = wx.GetApp().GetTopWindow() 702 703 #------------------------------------------------------------ 704 def edit(component=None): 705 substance_dose = gmMedication.cSubstanceDose(aPK_obj = component['pk_dose']) 706 return edit_substance_dose(parent = parent, substance_dose = substance_dose, single_entry = True)
707 708 #------------------------------------------------------------ 709 def delete(component): 710 if component.is_in_use_by_patients: 711 gmDispatcher.send(signal = 'statustext', msg = _('Cannot remove this component from the drug. It is in use.'), beep = True) 712 return False 713 return component.containing_drug.remove_component(pk_component = component['pk_component']) 714 715 #------------------------------------------------------------ 716 def refresh(lctrl): 717 comps = gmMedication.get_drug_components() 718 items = [ [ 719 '%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], '', ' [%s]')), 720 '%s %s' % (c['amount'], c.formatted_units), 721 '%s%s' % (c['product'], gmTools.coalesce(c['atc_drug'], '', ' [%s]')), 722 c['l10n_preparation'], 723 gmTools.coalesce(c['external_code'], '', '%%s [%s]' % c['external_code_type']), 724 c['pk_component'] 725 ] for c in comps ] 726 lctrl.set_string_items(items) 727 lctrl.set_data(comps) 728 729 #------------------------------------------------------------ 730 def get_item_tooltip(component): 731 if not isinstance(component, gmMedication.cDrugComponent): 732 return None 733 return component.format(include_loincs = True) 734 735 #------------------------------------------------------------ 736 gmListWidgets.get_choices_from_list ( 737 parent = parent, 738 caption = _('Drug components currently known to GNUmed'), 739 columns = [_('Component'), _('Strength'), _('Product name'), _('Preparation'), _('Code'), '#'], 740 single_selection = True, 741 #new_callback = edit, 742 edit_callback = edit, 743 delete_callback = delete, 744 refresh_callback = refresh, 745 list_tooltip_callback = get_item_tooltip 746 ) 747 748 #------------------------------------------------------------
749 -def edit_drug_component(parent=None, drug_component=None, single_entry=False):
750 ea = cDrugComponentEAPnl(parent, -1) 751 ea.data = drug_component 752 ea.mode = gmTools.coalesce(drug_component, 'new', 'edit') 753 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 754 dlg.SetTitle(gmTools.coalesce(drug_component, _('Adding new drug component'), _('Editing drug component'))) 755 if dlg.ShowModal() == wx.ID_OK: 756 dlg.Destroy() 757 return True 758 dlg.Destroy() 759 return False
760 761 #------------------------------------------------------------ 762 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl 763
764 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
765
766 - def __init__(self, *args, **kwargs):
767 768 try: 769 data = kwargs['component'] 770 del kwargs['component'] 771 except KeyError: 772 data = None 773 774 wxgDrugComponentEAPnl.wxgDrugComponentEAPnl.__init__(self, *args, **kwargs) 775 gmEditArea.cGenericEditAreaMixin.__init__(self) 776 777 # Code using this mixin should set mode and data 778 # after instantiating the class: 779 self.mode = 'new' 780 self.data = data 781 if data is not None: 782 self.mode = 'edit'
783 784 #self.__init_ui() 785 #---------------------------------------------------------------- 786 # def __init_ui(self): 787 # # adjust phrasewheels etc 788 #---------------------------------------------------------------- 789 # generic Edit Area mixin API 790 #----------------------------------------------------------------
791 - def _valid_for_save(self):
792 if self.data is not None: 793 if self.data['is_in_use']: 794 self.status_message = _('Cannot edit drug component. It is in use.') 795 return False 796 797 validity = True 798 799 if self._PRW_substance.GetData() is None: 800 validity = False 801 self._PRW_substance.display_as_valid(False) 802 else: 803 self._PRW_substance.display_as_valid(True) 804 805 val = self._TCTRL_amount.GetValue().strip().replace(',', '.', 1) 806 try: 807 decimal.Decimal(val) 808 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 809 except: 810 validity = False 811 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 812 813 if self._PRW_unit.GetValue().strip() == '': 814 validity = False 815 self._PRW_unit.display_as_valid(False) 816 else: 817 self._PRW_unit.display_as_valid(True) 818 819 if validity is False: 820 self.status_message = _('Cannot save drug component. Invalid or missing essential input.') 821 822 return validity
823 #----------------------------------------------------------------
824 - def _save_as_new(self):
825 # save the data as a new instance 826 data = 1 827 data[''] = 1 828 data[''] = 1 829 # data.save() 830 831 # must be done very late or else the property access 832 # will refresh the display such that later field 833 # access will return empty values 834 # self.data = data 835 return False 836 return True
837 #----------------------------------------------------------------
838 - def _save_as_update(self):
839 self.data['pk_dose'] = self._PRW_substance.GetData() 840 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.', 1)) 841 self.data['unit'] = self._PRW_unit.GetValue().strip() 842 return self.data.save()
843 844 #----------------------------------------------------------------
845 - def _refresh_as_new(self):
846 self._TCTRL_product_name.SetValue('') 847 self._TCTRL_components.SetValue('') 848 self._TCTRL_codes.SetValue('') 849 self._PRW_substance.SetText('', None) 850 self._TCTRL_amount.SetValue('') 851 self._PRW_unit.SetText('', None) 852 853 self._PRW_substance.SetFocus()
854 855 #----------------------------------------------------------------
856 - def _refresh_from_existing(self):
857 self._TCTRL_product_name.SetValue('%s (%s)' % (self.data['product'], self.data['l10n_preparation'])) 858 self._TCTRL_components.SetValue(' / '.join(self.data.containing_drug['components'])) 859 details = [] 860 if self.data['atc_drug'] is not None: 861 details.append('ATC: %s' % self.data['atc_drug']) 862 if self.data['external_code_product'] is not None: 863 details.append('%s: %s' % (self.data['external_code_type_product'], self.data['external_code_product'])) 864 self._TCTRL_codes.SetValue('; '.join(details)) 865 866 self._PRW_substance.SetText(self.data['substance'], self.data['pk_dose']) 867 self._TCTRL_amount.SetValue('%s' % self.data['amount']) 868 self._PRW_unit.SetText(self.data['unit'], self.data['unit']) 869 870 self._PRW_substance.SetFocus()
871 872 #----------------------------------------------------------------
874 #self._PRW_drug_product.SetText(u'', None) 875 #self._TCTRL_prep.SetValue(u'') 876 #self._TCTRL_product_name_details.SetValue(u'') 877 self._PRW_substance.SetText('', None) 878 self._TCTRL_amount.SetValue('') 879 self._PRW_unit.SetText('', None) 880 881 self._PRW_substance.SetFocus()
882 883 #------------------------------------------------------------
884 -class cDrugComponentPhraseWheel(gmPhraseWheel.cPhraseWheel):
885
886 - def __init__(self, *args, **kwargs):
887 888 mp = gmMedication.cDrugComponentMatchProvider() 889 mp.setThresholds(2, 3, 4) 890 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 891 self.SetToolTip(_('A drug component with optional strength.')) 892 self.matcher = mp 893 self.selection_only = False
894 #--------------------------------------------------------
895 - def _data2instance(self):
896 return gmMedication.cDrugComponent(aPK_obj = self.GetData(as_instance = False, can_create = False))
897 898 #============================================================ 899 # drug products widgets 900 #------------------------------------------------------------
901 -def edit_drug_product(parent=None, drug_product=None, single_entry=False):
902 903 if drug_product is not None: 904 if drug_product.is_in_use_by_patients: 905 gmGuiHelpers.gm_show_info ( 906 aTitle = _('Editing drug'), 907 aMessage = _( 908 'Cannot edit the drug product\n' 909 '\n' 910 ' "%s" (%s)\n' 911 '\n' 912 'because it is currently taken by patients.\n' 913 ) % (drug_product['product'], drug_product['l10n_preparation']) 914 ) 915 return False 916 917 if parent is None: 918 parent = wx.GetApp().GetTopWindow() 919 920 #-------------------------------------------- 921 def manage_substances(drug): 922 manage_substance_doses(parent = parent)
923 924 #-------------------------------------------- 925 ea = cDrugProductEAPnl(parent, -1) 926 ea.data = drug_product 927 ea.mode = gmTools.coalesce(drug_product, 'new', 'edit') 928 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 929 dlg.SetTitle(gmTools.coalesce(drug_product, _('Adding new drug product'), _('Editing drug product'))) 930 dlg.left_extra_button = ( 931 _('Substances'), 932 _('Manage substances'), 933 manage_substances 934 ) 935 if dlg.ShowModal() == wx.ID_OK: 936 dlg.Destroy() 937 return True 938 dlg.Destroy() 939 return False 940 941 #------------------------------------------------------------
942 -def manage_drug_products(parent=None, ignore_OK_button=False):
943 944 if parent is None: 945 parent = wx.GetApp().GetTopWindow() 946 947 #------------------------------------------------------------ 948 def add_from_db(drug): 949 drug_db = get_drug_database(parent = parent) 950 if drug_db is None: 951 return False 952 drug_db.import_drugs() 953 return True
954 955 #------------------------------------------------------------ 956 def get_tooltip(product=None): 957 return product.format(include_component_details = True) 958 959 #------------------------------------------------------------ 960 def edit(product): 961 if product is not None: 962 if product.is_in_use_as_vaccine: 963 gmGuiHelpers.gm_show_info ( 964 aTitle = _('Editing medication'), 965 aMessage = _( 966 'Cannot edit the vaccine product\n' 967 '\n' 968 ' "%s" (%s)\n' 969 '\n' 970 'because it is in use.' 971 ) % (product['product'], product['l10n_preparation']) 972 ) 973 return False 974 975 return edit_drug_product(parent = parent, drug_product = product, single_entry = True) 976 977 #------------------------------------------------------------ 978 def delete(product): 979 if not product.delete_associated_vaccine(): 980 gmGuiHelpers.gm_show_info ( 981 aTitle = _('Deleting vaccine'), 982 aMessage = _( 983 'Cannot delete the vaccine product\n' 984 '\n' 985 ' "%s" (%s)\n' 986 '\n' 987 'because it is in use.' 988 ) % (product['product'], product['l10n_preparation']) 989 ) 990 return False 991 992 gmMedication.delete_drug_product(pk_drug_product = product['pk_drug_product']) 993 return True 994 995 #------------------------------------------------------------ 996 def new(): 997 return edit_drug_product(parent = parent, drug_product = None, single_entry = False) 998 999 #------------------------------------------------------------ 1000 def refresh(lctrl): 1001 drugs = gmMedication.get_drug_products() 1002 items = [ [ 1003 '%s%s' % ( 1004 d['product'], 1005 gmTools.bool2subst(d['is_fake_product'], ' (%s)' % _('fake'), '') 1006 ), 1007 d['l10n_preparation'], 1008 gmTools.coalesce(d['atc'], ''), 1009 '; '.join([ '%s %s%s' % ( 1010 c['substance'], 1011 c['amount'], 1012 gmMedication.format_units(c['unit'], c['dose_unit']) 1013 ) for c in d['components']]), 1014 gmTools.coalesce(d['external_code'], '', '%%s [%s]' % d['external_code_type']), 1015 d['pk_drug_product'] 1016 ] for d in drugs ] 1017 lctrl.set_string_items(items) 1018 lctrl.set_data(drugs) 1019 1020 #------------------------------------------------------------ 1021 gmListWidgets.get_choices_from_list ( 1022 parent = parent, 1023 caption = _('Drug products currently known to GNUmed.'), 1024 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), '#'], 1025 single_selection = True, 1026 ignore_OK_button = ignore_OK_button, 1027 refresh_callback = refresh, 1028 new_callback = new, 1029 edit_callback = edit, 1030 delete_callback = delete, 1031 list_tooltip_callback = get_tooltip, 1032 left_extra_button = (_('Import'), _('Import substances and products from a drug database.'), add_from_db) 1033 #, middle_extra_button = (_('Clone'), _('Clone selected drug into a new entry for editing.'), clone_from_existing) 1034 #, right_extra_button = (_('Reassign'), _('Reassign all patients taking the selected drug to another drug.'), reassign_patients) 1035 ) 1036 1037 #------------------------------------------------------------
1038 -def manage_components_of_drug_product(parent=None, product=None):
1039 1040 if product is not None: 1041 if product.is_in_use_by_patients: 1042 gmGuiHelpers.gm_show_info ( 1043 aTitle = _('Managing components of a drug'), 1044 aMessage = _( 1045 'Cannot manage the components of the drug product\n' 1046 '\n' 1047 ' "%s" (%s)\n' 1048 '\n' 1049 'because it is currently taken by patients.\n' 1050 ) % (product['product'], product['l10n_preparation']) 1051 ) 1052 return False 1053 1054 #-------------------------------------------------------- 1055 if parent is None: 1056 parent = wx.GetApp().GetTopWindow() 1057 1058 #-------------------------------------------------------- 1059 # def manage_substances(): 1060 # pass 1061 1062 #-------------------------------------------------------- 1063 if product is None: 1064 msg = _('Pick the substance doses which are components of this drug.') 1065 right_col = _('Components of drug') 1066 comp_doses = [] 1067 else: 1068 right_col = '%s (%s)' % (product['product'], product['l10n_preparation']) 1069 msg = _( 1070 'Adjust the components of "%s"\n' 1071 '\n' 1072 'The drug must contain at least one component. Any given\n' 1073 'substance can only be included once per drug.' 1074 ) % right_col 1075 comp_doses = [ comp.substance_dose for comp in product.components ] 1076 1077 doses = gmMedication.get_substance_doses(order_by = 'substance') 1078 choices = [ '%s %s %s' % (d['substance'], d['amount'], d.formatted_units) for d in doses ] 1079 picks = [ '%s %s %s' % (d['substance'], d['amount'], d.formatted_units) for d in comp_doses ] 1080 1081 picker = gmListWidgets.cItemPickerDlg ( 1082 parent, 1083 -1, 1084 title = _('Managing components of a drug ...'), 1085 msg = msg 1086 ) 1087 picker.set_columns(['Substance doses'], [right_col]) 1088 picker.set_choices(choices = choices, data = doses) 1089 picker.set_picks(picks = picks, data = comp_doses) 1090 # picker.extra_button = ( 1091 # _('Substances'), 1092 # _('Manage list of substances'), 1093 # manage_substances 1094 # ) 1095 1096 btn_pressed = picker.ShowModal() 1097 doses2set = picker.get_picks() 1098 picker.Destroy() 1099 1100 if btn_pressed != wx.ID_OK: 1101 return (False, None) 1102 1103 if product is not None: 1104 product.set_substance_doses_as_components(substance_doses = doses2set) 1105 1106 return (True, doses2set)
1107 1108 #------------------------------------------------------------ 1109 from Gnumed.wxGladeWidgets import wxgDrugProductEAPnl 1110
1111 -class cDrugProductEAPnl(wxgDrugProductEAPnl.wxgDrugProductEAPnl, gmEditArea.cGenericEditAreaMixin):
1112
1113 - def __init__(self, *args, **kwargs):
1114 try: 1115 data = kwargs['drug'] 1116 del kwargs['drug'] 1117 except KeyError: 1118 data = None 1119 1120 wxgDrugProductEAPnl.wxgDrugProductEAPnl.__init__(self, *args, **kwargs) 1121 gmEditArea.cGenericEditAreaMixin.__init__(self) 1122 1123 self.mode = 'new' 1124 self.data = data 1125 if data is not None: 1126 self.mode = 'edit' 1127 self.__component_doses = data.components_as_doses
1128 1129 #self.__init_ui() 1130 #---------------------------------------------------------------- 1131 # def __init_ui(self): 1132 # adjust external type PRW 1133 #---------------------------------------------------------------- 1134 # generic Edit Area mixin API 1135 #----------------------------------------------------------------
1136 - def _valid_for_save(self):
1137 1138 if self.data is not None: 1139 if self.data.is_in_use_by_patients: 1140 self.status_message = _('Cannot edit drug product. It is in use.') 1141 return False 1142 1143 validity = True 1144 1145 product_name = self._PRW_product_name.GetValue().strip() 1146 if product_name == '': 1147 validity = False 1148 self._PRW_product_name.display_as_valid(False) 1149 else: 1150 self._PRW_product_name.display_as_valid(True) 1151 1152 preparation = self._PRW_preparation.GetValue().strip() 1153 if preparation == '': 1154 validity = False 1155 self._PRW_preparation.display_as_valid(False) 1156 else: 1157 self._PRW_preparation.display_as_valid(True) 1158 1159 if validity is True: 1160 # dupe ? 1161 drug = gmMedication.get_drug_by_name(product_name = product_name, preparation = preparation) 1162 if drug is not None: 1163 if self.mode != 'edit': 1164 validity = False 1165 self._PRW_product_name.display_as_valid(False) 1166 self._PRW_preparation.display_as_valid(False) 1167 gmGuiHelpers.gm_show_error ( 1168 title = _('Checking product data'), 1169 error = _( 1170 'The information you entered:\n' 1171 '\n' 1172 ' [%s %s]\n' 1173 '\n' 1174 'already exists as a drug product.' 1175 ) % (product_name, preparation) 1176 ) 1177 else: 1178 # lacking components ? 1179 self._TCTRL_components.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)) 1180 if len(self.__component_doses) == 0: 1181 wants_empty = gmGuiHelpers.gm_show_question ( 1182 title = _('Checking product data'), 1183 question = _( 1184 'You have not selected any substances\n' 1185 'as drug components.\n' 1186 '\n' 1187 'Without components you will not be able to\n' 1188 'use this drug for documenting patient care.\n' 1189 '\n' 1190 'Are you sure you want to save\n' 1191 'it without components ?' 1192 ) 1193 ) 1194 if not wants_empty: 1195 validity = False 1196 self.display_ctrl_as_valid(ctrl = self._TCTRL_components, valid = False) 1197 1198 if validity is False: 1199 self.status_message = _('Cannot save drug product. Invalid or missing essential input.') 1200 1201 return validity
1202 1203 #----------------------------------------------------------------
1204 - def _save_as_new(self):
1205 1206 drug = gmMedication.create_drug_product ( 1207 product_name = self._PRW_product_name.GetValue().strip(), 1208 preparation = gmTools.coalesce ( 1209 self._PRW_preparation.GetData(), 1210 self._PRW_preparation.GetValue() 1211 ).strip(), 1212 return_existing = True 1213 ) 1214 drug['is_fake_product'] = self._CHBOX_is_fake.GetValue() 1215 drug['atc'] = self._PRW_atc.GetData() 1216 code = self._TCTRL_external_code.GetValue().strip() 1217 if code != '': 1218 drug['external_code'] = code 1219 drug['external_code_type'] = self._PRW_external_code_type.GetData().strip() 1220 1221 drug.save() 1222 1223 if len(self.__component_doses) > 0: 1224 drug.set_substance_doses_as_components(substance_doses = self.__component_doses) 1225 1226 self.data = drug 1227 1228 return True
1229 1230 #----------------------------------------------------------------
1231 - def _save_as_update(self):
1232 self.data['product'] = self._PRW_product_name.GetValue().strip() 1233 self.data['preparation'] = gmTools.coalesce ( 1234 self._PRW_preparation.GetData(), 1235 self._PRW_preparation.GetValue() 1236 ).strip() 1237 self.data['is_fake_product'] = self._CHBOX_is_fake.GetValue() 1238 self.data['atc'] = self._PRW_atc.GetData() 1239 code = self._TCTRL_external_code.GetValue().strip() 1240 if code != '': 1241 self.data['external_code'] = code 1242 self.data['external_code_type'] = self._PRW_external_code_type.GetData().strip() 1243 success, data = self.data.save() 1244 if not success: 1245 err, msg = data 1246 _log.error('problem saving') 1247 _log.error('%s', err) 1248 _log.error('%s', msg) 1249 return (success is True)
1250 1251 #----------------------------------------------------------------
1252 - def _refresh_as_new(self):
1253 self._PRW_product_name.SetText('', None) 1254 self._PRW_preparation.SetText('', None) 1255 self._CHBOX_is_fake.SetValue(False) 1256 self._TCTRL_components.SetValue('') 1257 self._PRW_atc.SetText('', None) 1258 self._TCTRL_external_code.SetValue('') 1259 self._PRW_external_code_type.SetText('', None) 1260 1261 self._PRW_product_name.SetFocus() 1262 1263 self.__component_substances = []
1264 1265 #----------------------------------------------------------------
1267 self._refresh_as_new()
1268 1269 #----------------------------------------------------------------
1270 - def _refresh_from_existing(self):
1271 self._PRW_product_name.SetText(self.data['product'], self.data['pk_drug_product']) 1272 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation']) 1273 self._CHBOX_is_fake.SetValue(self.data['is_fake_product']) 1274 comp_str = '' 1275 if len(self.data['components']) > 0: 1276 comp_str = '- %s' % '\n- '.join([ '%s %s%s' % (c['substance'], c['amount'], gmMedication.format_units(c['unit'], c['dose_unit'])) for c in self.data['components'] ]) 1277 self._TCTRL_components.SetValue(comp_str) 1278 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc'], ''), self.data['atc']) 1279 self._TCTRL_external_code.SetValue(gmTools.coalesce(self.data['external_code'], '')) 1280 t = gmTools.coalesce(self.data['external_code_type'], '') 1281 self._PRW_external_code_type.SetText(t, t) 1282 1283 self._PRW_product_name.SetFocus() 1284 1285 self.__component_doses = self.data.components_as_doses
1286 1287 #---------------------------------------------------------------- 1288 # event handler 1289 #----------------------------------------------------------------
1290 - def _on_manage_components_button_pressed(self, event):
1291 event.Skip() 1292 if self.mode == 'new_from_existing': 1293 product = None 1294 else: 1295 product = self.data 1296 OKed, doses = manage_components_of_drug_product(parent = self, product = product) 1297 if OKed is True: 1298 self.__component_doses = doses 1299 comp_str = '' 1300 if len(doses) > 0: 1301 comp_str = '- %s' % '\n- '.join([ '%s %s%s' % (d['substance'], d['amount'], gmMedication.format_units(d['unit'], d['dose_unit'])) for d in doses ]) 1302 self._TCTRL_components.SetValue(comp_str)
1303 1304 #------------------------------------------------------------
1305 -class cDrugProductPhraseWheel(gmPhraseWheel.cPhraseWheel):
1306
1307 - def __init__(self, *args, **kwargs):
1308 1309 query = """ 1310 SELECT 1311 pk 1312 AS data, 1313 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', '')) 1314 AS list_label, 1315 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', '')) 1316 AS field_label 1317 FROM ref.drug_product 1318 WHERE description %(fragment_condition)s 1319 ORDER BY list_label 1320 LIMIT 50""" 1321 1322 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 1323 mp.setThresholds(2, 3, 4) 1324 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1325 self.SetToolTip(_( 1326 'The product name of the drug.\n' 1327 '\n' 1328 'Note: a product name will need to be linked to\n' 1329 'one or more components before it can be used,\n' 1330 'except in the case of fake (generic) vaccines.' 1331 )) 1332 self.matcher = mp 1333 self.selection_only = False
1334 1335 #============================================================ 1336 # single-component generic drugs 1337 # drug name is forced to substance + amount + unit + dose_unit 1338 #------------------------------------------------------------
1339 -def edit_single_component_generic_drug(parent=None, drug=None, single_entry=False, fields=None, return_drug=False):
1340 1341 # if drug is not None: 1342 # if drug.is_in_use_by_patients: 1343 # gmGuiHelpers.gm_show_info ( 1344 # aTitle = _('Editing single-component generic drug'), 1345 # aMessage = _( 1346 # 'Cannot edit the single-component generic drug\n' 1347 # '\n' 1348 # ' "%s" (%s)\n' 1349 # '\n' 1350 # 'because it is currently taken by patients.\n' 1351 # ) % (drug['product'], drug['l10n_preparation']) 1352 # ) 1353 # return False 1354 1355 if parent is None: 1356 parent = wx.GetApp().GetTopWindow() 1357 1358 # #-------------------------------------------- 1359 # def manage_substances(drug): 1360 # manage_substance_doses(parent = parent) 1361 1362 #-------------------------------------------- 1363 ea = cSingleComponentGenericDrugEAPnl(parent, -1) 1364 ea.data = drug 1365 ea.mode = gmTools.coalesce(drug, 'new', 'edit') 1366 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 1367 if fields is not None: 1368 ea.set_fields(fields) 1369 dlg.SetTitle(gmTools.coalesce(drug, _('Adding new single-component generic drug'), _('Editing single-component generic drug'))) 1370 # dlg.left_extra_button = ( 1371 # _('Substances'), 1372 # _('Manage substances'), 1373 # manage_substances 1374 # ) 1375 if dlg.ShowModal() == wx.ID_OK: 1376 drug = ea.data 1377 dlg.Destroy() 1378 if return_drug: 1379 return drug 1380 return True 1381 dlg.Destroy() 1382 if return_drug: 1383 return None 1384 return False
1385 1386 #------------------------------------------------------------
1387 -def manage_single_component_generic_drugs(parent=None, ignore_OK_button=False):
1388 1389 if parent is None: 1390 parent = wx.GetApp().GetTopWindow() 1391 1392 #------------------------------------------------------------ 1393 def add_from_db(drug): 1394 drug_db = get_drug_database(parent = parent) 1395 if drug_db is None: 1396 return False 1397 drug_db.import_drugs() 1398 return True
1399 1400 #------------------------------------------------------------ 1401 def get_tooltip(product=None): 1402 return product.format(include_component_details = True) 1403 1404 #------------------------------------------------------------ 1405 def edit(product): 1406 if product is not None: 1407 if product.is_vaccine: 1408 gmGuiHelpers.gm_show_info ( 1409 aTitle = _('Editing medication'), 1410 aMessage = _( 1411 'Cannot edit the medication\n' 1412 '\n' 1413 ' "%s" (%s)\n' 1414 '\n' 1415 'because it is a vaccine. Please edit it\n' 1416 'from the vaccine management section !\n' 1417 ) % (product['product'], product['l10n_preparation']) 1418 ) 1419 return False 1420 1421 return edit_drug_product(parent = parent, drug_product = product, single_entry = True) 1422 1423 #------------------------------------------------------------ 1424 def delete(product): 1425 if product.is_vaccine: 1426 gmGuiHelpers.gm_show_info ( 1427 aTitle = _('Deleting medication'), 1428 aMessage = _( 1429 'Cannot delete the medication\n' 1430 '\n' 1431 ' "%s" (%s)\n' 1432 '\n' 1433 'because it is a vaccine. Please delete it\n' 1434 'from the vaccine management section !\n' 1435 ) % (product['product'], product['l10n_preparation']) 1436 ) 1437 return False 1438 gmMedication.delete_drug_product(pk_drug_product = product['pk_drug_product']) 1439 return True 1440 1441 #------------------------------------------------------------ 1442 def new(): 1443 return edit_drug_product(parent = parent, drug_product = None, single_entry = False) 1444 1445 #------------------------------------------------------------ 1446 def refresh(lctrl): 1447 drugs = gmMedication.get_drug_products() 1448 items = [ [ 1449 '%s%s' % ( 1450 d['product'], 1451 gmTools.bool2subst(d['is_fake_product'], ' (%s)' % _('fake'), '') 1452 ), 1453 d['l10n_preparation'], 1454 gmTools.coalesce(d['atc'], ''), 1455 '; '.join([ '%s %s%s' % ( 1456 c['substance'], 1457 c['amount'], 1458 gmMedication.format_units(c['unit'], c['dose_unit']) 1459 ) for c in d['components']]), 1460 gmTools.coalesce(d['external_code'], '', '%%s [%s]' % d['external_code_type']), 1461 d['pk_drug_product'] 1462 ] for d in drugs ] 1463 lctrl.set_string_items(items) 1464 lctrl.set_data(drugs) 1465 1466 #------------------------------------------------------------ 1467 gmListWidgets.get_choices_from_list ( 1468 parent = parent, 1469 caption = _('Drug products currently known to GNUmed.'), 1470 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), '#'], 1471 single_selection = True, 1472 ignore_OK_button = ignore_OK_button, 1473 refresh_callback = refresh, 1474 new_callback = new, 1475 edit_callback = edit, 1476 delete_callback = delete, 1477 list_tooltip_callback = get_tooltip, 1478 #left_extra_button = (_('Import'), _('Import substances and products from a drug database.'), add_from_db) 1479 #, middle_extra_button = (_('Clone'), _('Clone selected drug into a new entry for editing.'), clone_from_existing) 1480 #, right_extra_button = (_('Reassign'), _('Reassign all patients taking the selected drug to another drug.'), reassign_patients) 1481 ) 1482 1483 #------------------------------------------------------------ 1484 from Gnumed.wxGladeWidgets import wxgSingleComponentGenericDrugEAPnl 1485
1486 -class cSingleComponentGenericDrugEAPnl(wxgSingleComponentGenericDrugEAPnl.wxgSingleComponentGenericDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
1487
1488 - def __init__(self, *args, **kwargs):
1489 1490 try: 1491 data = kwargs['drug'] 1492 del kwargs['drug'] 1493 except KeyError: 1494 data = None 1495 1496 wxgSingleComponentGenericDrugEAPnl.wxgSingleComponentGenericDrugEAPnl.__init__(self, *args, **kwargs) 1497 gmEditArea.cGenericEditAreaMixin.__init__(self) 1498 1499 self.mode = 'new' 1500 self.data = data 1501 if data is not None: 1502 self.mode = 'edit' 1503 1504 self.__init_ui()
1505 1506 #----------------------------------------------------------------
1507 - def __init_ui(self):
1508 self._PRW_substance.add_callback_on_modified(callback = self._on_name_field_modified) 1509 self._PRW_substance.add_callback_on_selection(callback = self._on_name_field_modified) 1510 self._TCTRL_amount.add_callback_on_modified(callback = self._on_name_field_modified) 1511 self._PRW_unit.add_callback_on_modified(callback = self._on_name_field_modified) 1512 self._PRW_unit.add_callback_on_selection(callback = self._on_name_field_modified) 1513 self._PRW_dose_unit.add_callback_on_modified(callback = self._on_name_field_modified) 1514 self._PRW_dose_unit.add_callback_on_selection(callback = self._on_name_field_modified)
1515 1516 #---------------------------------------------------------------- 1517 # generic Edit Area mixin API 1518 #----------------------------------------------------------------
1519 - def _valid_for_save(self):
1520 1521 validity = True 1522 1523 if self._PRW_preparation.Value.strip() == '': 1524 validity = False 1525 self._PRW_preparation.display_as_valid(False) 1526 self.status_message = _('Drug form is missing.') 1527 self._PRW_preparation.SetFocus() 1528 else: 1529 self._PRW_preparation.display_as_valid(True) 1530 1531 if self._PRW_unit.GetData() is None: 1532 validity = False 1533 self._PRW_unit.display_as_valid(False) 1534 self.status_message = _('Unit for amount is missing.') 1535 self._PRW_unit.SetFocus() 1536 else: 1537 self._PRW_unit.display_as_valid(True) 1538 1539 if self._TCTRL_amount.GetValue().strip() == '': 1540 validity = False 1541 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 1542 self.status_message = _('Amount is missing.') 1543 self._TCTRL_amount.SetFocus() 1544 else: 1545 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 1546 1547 if self._PRW_substance.GetData() is None: 1548 val = self._PRW_substance.Value.strip() 1549 if val != '' and gmATC.exists_as_atc(val): 1550 subst = gmMedication.create_substance(substance = val) 1551 self._PRW_substance.SetText(subst['substance'], subst['pk_substance']) 1552 self._PRW_substance.display_as_valid(True) 1553 else: 1554 validity = False 1555 self._PRW_substance.display_as_valid(False) 1556 self.status_message = _('Substance is missing.') 1557 self._PRW_substance.SetFocus() 1558 else: 1559 self._PRW_substance.display_as_valid(True) 1560 1561 return validity
1562 1563 #----------------------------------------------------------------
1564 - def _save_as_new(self):
1565 1566 dose = gmMedication.create_substance_dose ( 1567 pk_substance = self._PRW_substance.GetData(), 1568 amount = self._TCTRL_amount.Value.strip(), 1569 unit = self._PRW_unit.GetData(), 1570 dose_unit = self._PRW_dose_unit.GetData() 1571 ) 1572 dose_unit = self._PRW_dose_unit.GetValue().strip() 1573 if dose_unit != '': 1574 dose_unit = '/' + dose_unit 1575 name = '%s %s%s%s' % ( 1576 self._PRW_substance.GetValue().strip(), 1577 self._TCTRL_amount.Value.strip(), 1578 self._PRW_unit.GetValue().strip(), 1579 dose_unit 1580 ) 1581 drug = gmMedication.create_drug_product ( 1582 product_name = name, 1583 preparation = self._PRW_preparation.GetValue().strip(), 1584 return_existing = True 1585 ) 1586 drug['is_fake_product'] = True 1587 drug.save() 1588 drug.set_substance_doses_as_components(substance_doses = [dose]) 1589 self.data = drug 1590 return True
1591 1592 #----------------------------------------------------------------
1593 - def _save_as_update(self):
1594 return False
1595 # self.data[''] = self._CHBOX_xxx.GetValue() 1596 # self.data.save() 1597 # return True 1598 1599 #----------------------------------------------------------------
1600 - def _refresh_as_new(self):
1601 self._LBL_drug_name.SetLabel('') 1602 self._PRW_substance.SetText('', None) 1603 self._TCTRL_amount.SetValue('') 1604 self._PRW_unit.SetText('', None) 1605 self._PRW_dose_unit.SetText('', None) 1606 self._PRW_preparation.SetText('', None)
1607 1608 #----------------------------------------------------------------
1610 self._refresh_as_new()
1611 1612 #----------------------------------------------------------------
1613 - def _refresh_from_existing(self):
1614 pass
1615 1616 #----------------------------------------------------------------
1617 - def set_fields(self, fields):
1618 try: 1619 self._PRW_substance.SetText(fields['substance']['value'], fields['substance']['data']) 1620 except KeyError: 1621 _log.error('cannot set field [substance] from <%s>', fields)
1622 1623 #----------------------------------------------------------------
1624 - def _on_name_field_modified(self, data=None):
1625 dose_unit = self._PRW_dose_unit.GetValue().strip() 1626 if dose_unit != '': 1627 dose_unit = '/' + dose_unit 1628 name = '%s %s%s%s' % ( 1629 self._PRW_substance.GetValue().strip(), 1630 self._TCTRL_amount.Value.strip(), 1631 self._PRW_unit.GetValue().strip(), 1632 dose_unit 1633 ) 1634 self._LBL_drug_name.SetLabel('"%s"' % name.strip())
1635 1636 #============================================================ 1637 # main 1638 #------------------------------------------------------------ 1639 if __name__ == '__main__': 1640 1641 if len(sys.argv) < 2: 1642 sys.exit() 1643 1644 if sys.argv[1] != 'test': 1645 sys.exit() 1646 1647 from Gnumed.business import gmPersonSearch 1648 1649 pat = gmPersonSearch.ask_for_patient() 1650 if pat is None: 1651 sys.exit() 1652 gmPerson.set_active_patient(patient = pat) 1653 1654 #---------------------------------------- 1655 app = wx.PyWidgetTester(size = (600, 300)) 1656 app.SetWidget(cSubstancePhraseWheel, -1) 1657 app.MainLoop() 1658 #manage_substance_intakes() 1659 edit_single_component_generic_drug ( 1660 single_entry = True, 1661 fields = {'substance': {'value': val, 'data': None}}, 1662 return_drug = True 1663 ) 1664