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 Exception: 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.DestroyLater() 220 return True 221 dlg.DestroyLater() 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.StatusText = _('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.StatusText = _('Error saving substance. %s') % msg 342 return False 343 344 loincs = self._LCTRL_loincs.item_data 345 if loincs is not None: 346 if len(loincs) > 0: 347 subst.loincs = loincs 348 349 self.data = subst 350 return True
351 352 #----------------------------------------------------------------
353 - def _save_as_update(self):
354 self.data['substance'] = self._TCTRL_substance.GetValue().strip() 355 self.data['atc'] = self._PRW_atc.GetData() 356 self.data['intake_instructions'] = self._TCTRL_instructions.GetValue().strip() 357 success, data = self.data.save() 358 if not success: 359 err, msg = data 360 _log.error(err) 361 _log.error(msg) 362 self.StatusText = _('Error saving substance. %s') % msg 363 return False 364 365 loincs = self._LCTRL_loincs.item_data 366 if loincs is not None: 367 if len(loincs) > 0: 368 self.data.loincs = loincs 369 370 return True
371 372 #----------------------------------------------------------------
373 - def _refresh_as_new(self):
374 self._TCTRL_substance.SetValue('') 375 self._PRW_atc.SetText('', None) 376 self._TCTRL_instructions.SetValue('') 377 self._PRW_loinc.SetText('', None) 378 self._LCTRL_loincs.set_string_items() 379 380 self._TCTRL_substance.SetFocus()
381 382 #----------------------------------------------------------------
383 - def _refresh_from_existing(self):
384 self._TCTRL_substance.SetValue(self.data['substance']) 385 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc'], ''), self.data['atc']) 386 self._TCTRL_instructions.SetValue(gmTools.coalesce(self.data['intake_instructions'], '')) 387 self._PRW_loinc.SetText('', None) 388 if len(self.data['loincs']) == 0: 389 self._LCTRL_loincs.set_string_items() 390 else: 391 self._LCTRL_loincs.set_string_items([ [l['loinc'], gmTools.coalesce(l['max_age_str'], ''), gmTools.coalesce(l['comment'], '')] for l in self.data['loincs' ]]) 392 self._LCTRL_loincs.set_data([ l['loinc'] for l in self.data['loincs'] ]) 393 394 self._TCTRL_substance.SetFocus()
395 396 #----------------------------------------------------------------
398 self._refresh_as_new()
399 400 #---------------------------------------------------------------- 401 # event handlers 402 #----------------------------------------------------------------
403 - def _on_add_loinc_button_pressed(self, event):
404 event.Skip() 405 if (self._PRW_loinc.GetData() is None) and (self._PRW_loinc.GetValue().strip() == ''): 406 return 407 408 if self._PRW_loinc.GetData() is None: 409 data = self._PRW_loinc.GetValue().strip().split(':')[0] 410 item = [data, '', ''] 411 else: 412 data = self._PRW_loinc.GetData() 413 item = [data, '', ''] 414 self._LCTRL_loincs.append_string_items_and_data([item], new_data = [data], allow_dupes = False)
415 416 #----------------------------------------------------------------
417 - def _on_remove_loincs_button_pressed(self, event):
418 event.Skip()
419 420 #------------------------------------------------------------
421 -class cSubstancePhraseWheel(gmPhraseWheel.cPhraseWheel):
422
423 - def __init__(self, *args, **kwargs):
424 425 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 426 query = """ 427 SELECT DISTINCT ON (list_label) 428 list_label, 429 field_label, 430 data 431 FROM ( 432 SELECT 433 description AS list_label, 434 description AS field_label, 435 pk AS data 436 FROM ref.substance 437 WHERE 438 description %(fragment_condition)s 439 440 UNION ALL 441 442 SELECT 443 term AS list_label, 444 term AS field_label, 445 NULL::integer AS data 446 FROM ref.atc 447 WHERE 448 term %(fragment_condition)s 449 450 ) AS candidates 451 ORDER BY list_label 452 LIMIT 50 453 """ 454 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 455 mp.setThresholds(1, 2, 4) 456 # mp.word_separators = '[ \t=+&:@]+' 457 self.SetToolTip(_('The substance name.')) 458 self.matcher = mp 459 self.selection_only = False 460 self.phrase_separators = None
461 462 #--------------------------------------------------------
463 - def _data2instance(self):
464 return gmMedication.cSubstance(aPK_obj = self.GetData(as_instance = False, can_create = False))
465 466 #============================================================ 467 # substance dose widgets 468 #------------------------------------------------------------
469 -def edit_substance_dose(parent=None, substance_dose=None, single_entry=False):
470 471 if substance_dose is not None: 472 if substance_dose.is_in_use_by_patients: 473 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True) 474 return False 475 476 ea = cSubstanceDoseEAPnl(parent, -1) 477 ea.data = substance_dose 478 ea.mode = gmTools.coalesce(substance_dose, 'new', 'edit') 479 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 480 dlg.SetTitle(gmTools.coalesce(substance_dose, _('Adding new substance dose'), _('Editing substance dose'))) 481 if dlg.ShowModal() == wx.ID_OK: 482 dlg.DestroyLater() 483 return True 484 dlg.DestroyLater() 485 return False
486 487 #------------------------------------------------------------
488 -def manage_substance_doses(parent=None, vaccine_indications_only=False):
489 490 if parent is None: 491 parent = wx.GetApp().GetTopWindow() 492 493 #------------------------------------------------------------ 494 def add_from_db(substance): 495 drug_db = get_drug_database(parent = parent) 496 if drug_db is None: 497 return False 498 drug_db.import_drugs() 499 return True
500 501 #------------------------------------------------------------ 502 def edit(substance_dose=None): 503 return edit_substance_dose(parent = parent, substance_dose = substance_dose, single_entry = (substance_dose is not None)) 504 505 #------------------------------------------------------------ 506 def delete(substance_dose): 507 if substance_dose.is_in_use_by_patients: 508 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True) 509 return False 510 return gmMedication.delete_substance_dose(pk_dose = substance_dose['pk_dose']) 511 512 #------------------------------------------------------------ 513 def refresh(lctrl): 514 if vaccine_indications_only: 515 substs = [ s for s in gmMedication.get_substance_doses(order_by = 'substance') if gmTools.coalesce(s['atc_substance'], '').startswith('J07') ] 516 else: 517 substs = gmMedication.get_substance_doses(order_by = 'substance') 518 items = [ [ 519 s['substance'], 520 s['amount'], 521 s.formatted_units, 522 gmTools.coalesce(s['atc_substance'], ''), 523 gmTools.coalesce(s['intake_instructions'], ''), 524 s['pk_dose'] 525 ] for s in substs ] 526 lctrl.set_string_items(items) 527 lctrl.set_data(substs) 528 529 #------------------------------------------------------------ 530 def get_item_tooltip(substance_dose): 531 if not isinstance(substance_dose, gmMedication.cSubstanceDose): 532 return None 533 return substance_dose.format(include_loincs = True) 534 535 #------------------------------------------------------------ 536 return gmListWidgets.get_choices_from_list ( 537 parent = parent, 538 caption = _('Substance doses registered with GNUmed.'), 539 columns = [_('Substance'), _('Amount'), _('Unit'), 'ATC', _('Instructions'), '#'], 540 single_selection = False, 541 can_return_empty = False, 542 new_callback = edit, 543 edit_callback = edit, 544 delete_callback = delete, 545 refresh_callback = refresh, 546 left_extra_button = (_('Import'), _('Import substance doses from a drug database.'), add_from_db), 547 list_tooltip_callback = get_item_tooltip 548 ) 549 550 #------------------------------------------------------------ 551 from Gnumed.wxGladeWidgets import wxgSubstanceDoseEAPnl 552
553 -class cSubstanceDoseEAPnl(wxgSubstanceDoseEAPnl.wxgSubstanceDoseEAPnl, gmEditArea.cGenericEditAreaMixin):
554
555 - def __init__(self, *args, **kwargs):
556 557 try: 558 data = kwargs['substance'] 559 del kwargs['substance'] 560 except KeyError: 561 data = None 562 563 wxgSubstanceDoseEAPnl.wxgSubstanceDoseEAPnl.__init__(self, *args, **kwargs) 564 gmEditArea.cGenericEditAreaMixin.__init__(self) 565 566 # Code using this mixin should set mode and data 567 # after instantiating the class: 568 self.mode = 'new' 569 self.data = data 570 if data is not None: 571 self.mode = 'edit' 572 573 self.__init_ui()
574 575 #----------------------------------------------------------------
576 - def __init_ui(self):
577 self._PRW_substance.add_callback_on_modified(callback = self.__refresh_info) 578 self._PRW_substance.add_callback_on_selection(callback = self.__refresh_info) 579 self._TCTRL_amount.add_callback_on_modified(callback = self.__refresh_info) 580 self._PRW_unit.add_callback_on_modified(callback = self.__refresh_info) 581 self._PRW_unit.add_callback_on_selection(callback = self.__refresh_info) 582 self._PRW_dose_unit.add_callback_on_modified(callback = self.__refresh_info) 583 self._PRW_dose_unit.add_callback_on_selection(callback = self.__refresh_info)
584 585 #----------------------------------------------------------------
586 - def __refresh_info(self, change='dummy'):
587 subst = self._PRW_substance.GetValue().strip() 588 if subst == '': 589 subst = '?' 590 amount = self._TCTRL_amount.GetValue().strip() 591 if amount == '': 592 amount = '?' 593 unit = self._PRW_unit.GetValue().strip() 594 if unit == '': 595 unit = '?' 596 dose_unit = self._PRW_dose_unit.GetValue().strip() 597 if dose_unit == '': 598 dose_unit = _('<delivery unit>') 599 self._LBL_info.SetLabel('%s %s %s / %s' % (subst, amount, unit, dose_unit)) 600 self.Refresh()
601 602 #---------------------------------------------------------------- 603 # generic Edit Area mixin API 604 #----------------------------------------------------------------
605 - def _valid_for_save(self):
606 607 validity = True 608 609 if self._PRW_substance.GetValue().strip() == '': 610 validity = False 611 self._PRW_substance.display_as_valid(valid = False) 612 self._PRW_substance.SetFocus() 613 else: 614 self._PRW_substance.display_as_valid(valid = True) 615 616 try: 617 decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')) 618 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 619 except (TypeError, decimal.InvalidOperation): 620 validity = False 621 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 622 self._TCTRL_amount.SetFocus() 623 624 if self._PRW_unit.GetValue().strip() == '': 625 validity = False 626 self._PRW_unit.display_as_valid(valid = False) 627 self._PRW_unit.SetFocus() 628 else: 629 self._PRW_unit.display_as_valid(valid = True) 630 631 if validity is False: 632 self.StatusText = _('Cannot save substance dose. Missing essential input.') 633 634 return validity
635 636 #----------------------------------------------------------------
637 - def _save_as_new(self):
638 pk_subst = self._PRW_substance.GetData() 639 dose = gmMedication.create_substance_dose ( 640 pk_substance = pk_subst, 641 substance = self._PRW_substance.GetValue().strip() if (pk_subst is None) else None, 642 amount = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')), 643 unit = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function4value = ('strip', None)), 644 dose_unit = gmTools.coalesce(self._PRW_dose_unit.GetData(), self._PRW_dose_unit.GetValue().strip(), function4value = ('strip', None)) 645 ) 646 success, data = dose.save() 647 if not success: 648 err, msg = data 649 _log.error(err) 650 _log.error(msg) 651 self.StatusText = _('Cannot create substance dose. %s') % msg 652 return False 653 654 self.data = dose 655 return True
656 657 #----------------------------------------------------------------
658 - def _save_as_update(self):
659 #self.data['pk_substance'] = self._PRW_substance.GetData() 660 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')) 661 self.data['unit'] = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function4value = ('strip', None)) 662 self.data['dose_unit'] = gmTools.coalesce(self._PRW_dose_unit.GetData(), self._PRW_dose_unit.GetValue().strip(), function4value = ('strip', None)) 663 success, data = self.data.save() 664 665 if not success: 666 err, msg = data 667 _log.error(err) 668 _log.error(msg) 669 self.StatusText = _('Cannot save substance dose. %s') % msg 670 return False 671 672 return True
673 674 #----------------------------------------------------------------
675 - def _refresh_as_new(self):
676 self._PRW_substance.SetText('', None) 677 self._TCTRL_amount.SetValue('') 678 self._PRW_unit.SetText('', None) 679 self._PRW_dose_unit.SetText('', None) 680 self._LBL_info.SetLabel('') 681 682 self._PRW_substance.SetFocus()
683 684 #----------------------------------------------------------------
685 - def _refresh_from_existing(self):
686 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance']) 687 self._PRW_substance.Disable() 688 self._TCTRL_amount.SetValue('%s' % self.data['amount']) 689 self._PRW_unit.SetText(self.data['unit'], self.data['unit']) 690 self._PRW_dose_unit.SetText(gmTools.coalesce(self.data['dose_unit'], ''), self.data['dose_unit']) 691 692 self._PRW_substance.SetFocus()
693 694 #----------------------------------------------------------------
696 self._refresh_as_new()
697 698 #============================================================ 699 # drug component widgets 700 #------------------------------------------------------------
701 -def manage_drug_components(parent=None):
702 703 if parent is None: 704 parent = wx.GetApp().GetTopWindow() 705 706 #------------------------------------------------------------ 707 def edit(component=None): 708 substance_dose = gmMedication.cSubstanceDose(aPK_obj = component['pk_dose']) 709 return edit_substance_dose(parent = parent, substance_dose = substance_dose, single_entry = True)
710 711 #------------------------------------------------------------ 712 def delete(component): 713 if component.is_in_use_by_patients: 714 gmDispatcher.send(signal = 'statustext', msg = _('Cannot remove this component from the drug. It is in use.'), beep = True) 715 return False 716 return component.containing_drug.remove_component(pk_component = component['pk_component']) 717 718 #------------------------------------------------------------ 719 def refresh(lctrl): 720 comps = gmMedication.get_drug_components() 721 items = [ [ 722 '%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], '', ' [%s]')), 723 '%s %s' % (c['amount'], c.formatted_units), 724 '%s%s' % (c['product'], gmTools.coalesce(c['atc_drug'], '', ' [%s]')), 725 c['l10n_preparation'], 726 gmTools.coalesce(c['external_code'], '', '%%s [%s]' % c['external_code_type']), 727 c['pk_component'] 728 ] for c in comps ] 729 lctrl.set_string_items(items) 730 lctrl.set_data(comps) 731 732 #------------------------------------------------------------ 733 def get_item_tooltip(component): 734 if not isinstance(component, gmMedication.cDrugComponent): 735 return None 736 return component.format(include_loincs = True) 737 738 #------------------------------------------------------------ 739 gmListWidgets.get_choices_from_list ( 740 parent = parent, 741 caption = _('Drug components currently known to GNUmed'), 742 columns = [_('Component'), _('Strength'), _('Product name'), _('Preparation'), _('Code'), '#'], 743 single_selection = True, 744 #new_callback = edit, 745 edit_callback = edit, 746 delete_callback = delete, 747 refresh_callback = refresh, 748 list_tooltip_callback = get_item_tooltip 749 ) 750 751 #------------------------------------------------------------
752 -def edit_drug_component(parent=None, drug_component=None, single_entry=False):
753 ea = cDrugComponentEAPnl(parent, -1) 754 ea.data = drug_component 755 ea.mode = gmTools.coalesce(drug_component, 'new', 'edit') 756 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 757 dlg.SetTitle(gmTools.coalesce(drug_component, _('Adding new drug component'), _('Editing drug component'))) 758 if dlg.ShowModal() == wx.ID_OK: 759 dlg.DestroyLater() 760 return True 761 dlg.DestroyLater() 762 return False
763 764 #------------------------------------------------------------ 765 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl 766
767 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
768
769 - def __init__(self, *args, **kwargs):
770 771 try: 772 data = kwargs['component'] 773 del kwargs['component'] 774 except KeyError: 775 data = None 776 777 wxgDrugComponentEAPnl.wxgDrugComponentEAPnl.__init__(self, *args, **kwargs) 778 gmEditArea.cGenericEditAreaMixin.__init__(self) 779 780 # Code using this mixin should set mode and data 781 # after instantiating the class: 782 self.mode = 'new' 783 self.data = data 784 if data is not None: 785 self.mode = 'edit'
786 787 #self.__init_ui() 788 #---------------------------------------------------------------- 789 # def __init_ui(self): 790 # # adjust phrasewheels etc 791 #---------------------------------------------------------------- 792 # generic Edit Area mixin API 793 #----------------------------------------------------------------
794 - def _valid_for_save(self):
795 if self.data is not None: 796 if self.data['is_in_use']: 797 self.StatusText = _('Cannot edit drug component. It is in use.') 798 return False 799 800 validity = True 801 802 if self._PRW_substance.GetData() is None: 803 validity = False 804 self._PRW_substance.display_as_valid(False) 805 else: 806 self._PRW_substance.display_as_valid(True) 807 808 val = self._TCTRL_amount.GetValue().strip().replace(',', '.', 1) 809 try: 810 decimal.Decimal(val) 811 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 812 except Exception: 813 validity = False 814 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 815 816 if self._PRW_unit.GetValue().strip() == '': 817 validity = False 818 self._PRW_unit.display_as_valid(False) 819 else: 820 self._PRW_unit.display_as_valid(True) 821 822 if validity is False: 823 self.StatusText = _('Cannot save drug component. Invalid or missing essential input.') 824 825 return validity
826 #----------------------------------------------------------------
827 - def _save_as_new(self):
828 # save the data as a new instance 829 data = 1 830 data[''] = 1 831 data[''] = 1 832 # data.save() 833 834 # must be done very late or else the property access 835 # will refresh the display such that later field 836 # access will return empty values 837 # self.data = data 838 return False 839 return True
840 #----------------------------------------------------------------
841 - def _save_as_update(self):
842 self.data['pk_dose'] = self._PRW_substance.GetData() 843 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.', 1)) 844 self.data['unit'] = self._PRW_unit.GetValue().strip() 845 return self.data.save()
846 847 #----------------------------------------------------------------
848 - def _refresh_as_new(self):
849 self._TCTRL_product_name.SetValue('') 850 self._TCTRL_components.SetValue('') 851 self._TCTRL_codes.SetValue('') 852 self._PRW_substance.SetText('', None) 853 self._TCTRL_amount.SetValue('') 854 self._PRW_unit.SetText('', None) 855 856 self._PRW_substance.SetFocus()
857 858 #----------------------------------------------------------------
859 - def _refresh_from_existing(self):
860 self._TCTRL_product_name.SetValue('%s (%s)' % (self.data['product'], self.data['l10n_preparation'])) 861 self._TCTRL_components.SetValue(' / '.join(self.data.containing_drug['components'])) 862 details = [] 863 if self.data['atc_drug'] is not None: 864 details.append('ATC: %s' % self.data['atc_drug']) 865 if self.data['external_code_product'] is not None: 866 details.append('%s: %s' % (self.data['external_code_type_product'], self.data['external_code_product'])) 867 self._TCTRL_codes.SetValue('; '.join(details)) 868 869 self._PRW_substance.SetText(self.data['substance'], self.data['pk_dose']) 870 self._TCTRL_amount.SetValue('%s' % self.data['amount']) 871 self._PRW_unit.SetText(self.data['unit'], self.data['unit']) 872 873 self._PRW_substance.SetFocus()
874 875 #----------------------------------------------------------------
877 #self._PRW_drug_product.SetText(u'', None) 878 #self._TCTRL_prep.SetValue(u'') 879 #self._TCTRL_product_name_details.SetValue(u'') 880 self._PRW_substance.SetText('', None) 881 self._TCTRL_amount.SetValue('') 882 self._PRW_unit.SetText('', None) 883 884 self._PRW_substance.SetFocus()
885 886 #------------------------------------------------------------
887 -class cDrugComponentPhraseWheel(gmPhraseWheel.cPhraseWheel):
888
889 - def __init__(self, *args, **kwargs):
890 891 mp = gmMedication.cDrugComponentMatchProvider() 892 mp.setThresholds(2, 3, 4) 893 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 894 self.SetToolTip(_('A drug component with optional strength.')) 895 self.matcher = mp 896 self.selection_only = False
897 #--------------------------------------------------------
898 - def _data2instance(self):
899 return gmMedication.cDrugComponent(aPK_obj = self.GetData(as_instance = False, can_create = False))
900 901 #============================================================ 902 # drug products widgets 903 #------------------------------------------------------------
904 -def edit_drug_product(parent=None, drug_product=None, single_entry=False):
905 906 if drug_product is not None: 907 if drug_product.is_in_use_by_patients: 908 gmGuiHelpers.gm_show_info ( 909 aTitle = _('Editing drug'), 910 aMessage = _( 911 'Cannot edit the drug product\n' 912 '\n' 913 ' "%s" (%s)\n' 914 '\n' 915 'because it is currently taken by patients.\n' 916 ) % (drug_product['product'], drug_product['l10n_preparation']) 917 ) 918 return False 919 920 if parent is None: 921 parent = wx.GetApp().GetTopWindow() 922 923 #-------------------------------------------- 924 def manage_substances(drug): 925 manage_substance_doses(parent = parent)
926 927 #-------------------------------------------- 928 ea = cDrugProductEAPnl(parent, -1) 929 ea.data = drug_product 930 ea.mode = gmTools.coalesce(drug_product, 'new', 'edit') 931 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 932 dlg.SetTitle(gmTools.coalesce(drug_product, _('Adding new drug product'), _('Editing drug product'))) 933 dlg.left_extra_button = ( 934 _('Substances'), 935 _('Manage substances'), 936 manage_substances 937 ) 938 if dlg.ShowModal() == wx.ID_OK: 939 dlg.DestroyLater() 940 return True 941 dlg.DestroyLater() 942 return False 943 944 #------------------------------------------------------------
945 -def manage_drug_products(parent=None, ignore_OK_button=False):
946 947 if parent is None: 948 parent = wx.GetApp().GetTopWindow() 949 950 #------------------------------------------------------------ 951 def add_from_db(drug): 952 drug_db = get_drug_database(parent = parent) 953 if drug_db is None: 954 return False 955 drug_db.import_drugs() 956 return True
957 958 #------------------------------------------------------------ 959 def get_tooltip(product=None): 960 return product.format(include_component_details = True) 961 962 #------------------------------------------------------------ 963 def edit(product): 964 if product is not None: 965 if product.is_in_use_as_vaccine: 966 gmGuiHelpers.gm_show_info ( 967 aTitle = _('Editing medication'), 968 aMessage = _( 969 'Cannot edit the vaccine product\n' 970 '\n' 971 ' "%s" (%s)\n' 972 '\n' 973 'because it is in use.' 974 ) % (product['product'], product['l10n_preparation']) 975 ) 976 return False 977 978 return edit_drug_product(parent = parent, drug_product = product, single_entry = True) 979 980 #------------------------------------------------------------ 981 def delete(product): 982 if not product.delete_associated_vaccine(): 983 gmGuiHelpers.gm_show_info ( 984 aTitle = _('Deleting vaccine'), 985 aMessage = _( 986 'Cannot delete the vaccine product\n' 987 '\n' 988 ' "%s" (%s)\n' 989 '\n' 990 'because it is in use.' 991 ) % (product['product'], product['l10n_preparation']) 992 ) 993 return False 994 995 gmMedication.delete_drug_product(pk_drug_product = product['pk_drug_product']) 996 return True 997 998 #------------------------------------------------------------ 999 def new(): 1000 return edit_drug_product(parent = parent, drug_product = None, single_entry = False) 1001 1002 #------------------------------------------------------------ 1003 def refresh(lctrl): 1004 drugs = gmMedication.get_drug_products() 1005 items = [ [ 1006 '%s%s' % ( 1007 d['product'], 1008 gmTools.bool2subst(d['is_fake_product'], ' (%s)' % _('fake'), '') 1009 ), 1010 d['l10n_preparation'], 1011 gmTools.coalesce(d['atc'], ''), 1012 '; '.join([ '%s %s%s' % ( 1013 c['substance'], 1014 c['amount'], 1015 gmMedication.format_units(c['unit'], c['dose_unit']) 1016 ) for c in d['components']]), 1017 gmTools.coalesce(d['external_code'], '', '%%s [%s]' % d['external_code_type']), 1018 d['pk_drug_product'] 1019 ] for d in drugs ] 1020 lctrl.set_string_items(items) 1021 lctrl.set_data(drugs) 1022 1023 #------------------------------------------------------------ 1024 gmListWidgets.get_choices_from_list ( 1025 parent = parent, 1026 caption = _('Drug products currently known to GNUmed.'), 1027 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), '#'], 1028 single_selection = True, 1029 ignore_OK_button = ignore_OK_button, 1030 refresh_callback = refresh, 1031 new_callback = new, 1032 edit_callback = edit, 1033 delete_callback = delete, 1034 list_tooltip_callback = get_tooltip, 1035 left_extra_button = (_('Import'), _('Import substances and products from a drug database.'), add_from_db) 1036 #, middle_extra_button = (_('Clone'), _('Clone selected drug into a new entry for editing.'), clone_from_existing) 1037 #, right_extra_button = (_('Reassign'), _('Reassign all patients taking the selected drug to another drug.'), reassign_patients) 1038 ) 1039 1040 #------------------------------------------------------------
1041 -def manage_components_of_drug_product(parent=None, product=None):
1042 1043 if product is not None: 1044 if product.is_in_use_by_patients: 1045 gmGuiHelpers.gm_show_info ( 1046 aTitle = _('Managing components of a drug'), 1047 aMessage = _( 1048 'Cannot manage the components of the drug product\n' 1049 '\n' 1050 ' "%s" (%s)\n' 1051 '\n' 1052 'because it is currently taken by patients.\n' 1053 ) % (product['product'], product['l10n_preparation']) 1054 ) 1055 return False 1056 1057 #-------------------------------------------------------- 1058 if parent is None: 1059 parent = wx.GetApp().GetTopWindow() 1060 1061 #-------------------------------------------------------- 1062 # def manage_substances(): 1063 # pass 1064 1065 #-------------------------------------------------------- 1066 if product is None: 1067 msg = _('Pick the substance doses which are components of this drug.') 1068 right_col = _('Components of drug') 1069 comp_doses = [] 1070 else: 1071 right_col = '%s (%s)' % (product['product'], product['l10n_preparation']) 1072 msg = _( 1073 'Adjust the components of "%s"\n' 1074 '\n' 1075 'The drug must contain at least one component. Any given\n' 1076 'substance can only be included once per drug.' 1077 ) % right_col 1078 comp_doses = [ comp.substance_dose for comp in product.components ] 1079 1080 doses = gmMedication.get_substance_doses(order_by = 'substance') 1081 choices = [ '%s %s %s' % (d['substance'], d['amount'], d.formatted_units) for d in doses ] 1082 picks = [ '%s %s %s' % (d['substance'], d['amount'], d.formatted_units) for d in comp_doses ] 1083 1084 picker = gmListWidgets.cItemPickerDlg ( 1085 parent, 1086 -1, 1087 title = _('Managing components of a drug ...'), 1088 msg = msg 1089 ) 1090 picker.set_columns(['Substance doses'], [right_col]) 1091 picker.set_choices(choices = choices, data = doses) 1092 picker.set_picks(picks = picks, data = comp_doses) 1093 # picker.extra_button = ( 1094 # _('Substances'), 1095 # _('Manage list of substances'), 1096 # manage_substances 1097 # ) 1098 1099 btn_pressed = picker.ShowModal() 1100 doses2set = picker.get_picks() 1101 picker.DestroyLater() 1102 1103 if btn_pressed != wx.ID_OK: 1104 return (False, None) 1105 1106 if product is not None: 1107 product.set_substance_doses_as_components(substance_doses = doses2set) 1108 1109 return (True, doses2set)
1110 1111 #------------------------------------------------------------ 1112 from Gnumed.wxGladeWidgets import wxgDrugProductEAPnl 1113
1114 -class cDrugProductEAPnl(wxgDrugProductEAPnl.wxgDrugProductEAPnl, gmEditArea.cGenericEditAreaMixin):
1115
1116 - def __init__(self, *args, **kwargs):
1117 try: 1118 data = kwargs['drug'] 1119 del kwargs['drug'] 1120 except KeyError: 1121 data = None 1122 1123 wxgDrugProductEAPnl.wxgDrugProductEAPnl.__init__(self, *args, **kwargs) 1124 gmEditArea.cGenericEditAreaMixin.__init__(self) 1125 1126 self.__component_doses = [] 1127 1128 self.mode = 'new' 1129 self.data = data 1130 if data is not None: 1131 self.mode = 'edit' 1132 self.__component_doses = data.components_as_doses
1133 1134 #self.__init_ui() 1135 #---------------------------------------------------------------- 1136 # def __init_ui(self): 1137 # adjust external type PRW 1138 #---------------------------------------------------------------- 1139 # generic Edit Area mixin API 1140 #----------------------------------------------------------------
1141 - def _valid_for_save(self):
1142 1143 if self.data is not None: 1144 if self.data.is_in_use_by_patients: 1145 self.StatusText = _('Cannot edit drug product. It is in use.') 1146 return False 1147 1148 validity = True 1149 1150 product_name = self._PRW_product_name.GetValue().strip() 1151 if product_name == '': 1152 validity = False 1153 self._PRW_product_name.display_as_valid(False) 1154 else: 1155 self._PRW_product_name.display_as_valid(True) 1156 1157 preparation = self._PRW_preparation.GetValue().strip() 1158 if preparation == '': 1159 validity = False 1160 self._PRW_preparation.display_as_valid(False) 1161 else: 1162 self._PRW_preparation.display_as_valid(True) 1163 1164 if validity is True: 1165 # dupe ? 1166 drug = gmMedication.get_drug_by_name(product_name = product_name, preparation = preparation) 1167 if drug is not None: 1168 if self.mode != 'edit': 1169 validity = False 1170 self._PRW_product_name.display_as_valid(False) 1171 self._PRW_preparation.display_as_valid(False) 1172 gmGuiHelpers.gm_show_error ( 1173 title = _('Checking product data'), 1174 error = _( 1175 'The information you entered:\n' 1176 '\n' 1177 ' [%s %s]\n' 1178 '\n' 1179 'already exists as a drug product.' 1180 ) % (product_name, preparation) 1181 ) 1182 else: 1183 # lacking components ? 1184 self._TCTRL_components.SetBackgroundColour(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BACKGROUND)) 1185 if len(self.__component_doses) == 0: 1186 wants_empty = gmGuiHelpers.gm_show_question ( 1187 title = _('Checking product data'), 1188 question = _( 1189 'You have not selected any substances\n' 1190 'as drug components.\n' 1191 '\n' 1192 'Without components you will not be able to\n' 1193 'use this drug for documenting patient care.\n' 1194 '\n' 1195 'Are you sure you want to save\n' 1196 'it without components ?' 1197 ) 1198 ) 1199 if not wants_empty: 1200 validity = False 1201 self.display_ctrl_as_valid(ctrl = self._TCTRL_components, valid = False) 1202 1203 if validity is False: 1204 self.StatusText = _('Cannot save drug product. Invalid or missing essential input.') 1205 1206 return validity
1207 1208 #----------------------------------------------------------------
1209 - def _save_as_new(self):
1210 drug = gmMedication.create_drug_product ( 1211 product_name = self._PRW_product_name.GetValue().strip(), 1212 preparation = gmTools.coalesce ( 1213 self._PRW_preparation.GetData(), 1214 self._PRW_preparation.GetValue() 1215 ).strip(), 1216 doses = self.__component_doses if (len(self.__component_doses) > 0) else None, 1217 return_existing = True 1218 ) 1219 drug['is_fake_product'] = self._CHBOX_is_fake.GetValue() 1220 drug['atc'] = self._PRW_atc.GetData() 1221 code = self._TCTRL_external_code.GetValue().strip() 1222 if code != '': 1223 drug['external_code'] = code 1224 drug['external_code_type'] = self._PRW_external_code_type.GetData().strip() 1225 drug.save() 1226 self.data = drug 1227 return True
1228 1229 #----------------------------------------------------------------
1230 - def _save_as_update(self):
1231 self.data['product'] = self._PRW_product_name.GetValue().strip() 1232 self.data['preparation'] = gmTools.coalesce ( 1233 self._PRW_preparation.GetData(), 1234 self._PRW_preparation.GetValue() 1235 ).strip() 1236 self.data['is_fake_product'] = self._CHBOX_is_fake.GetValue() 1237 self.data['atc'] = self._PRW_atc.GetData() 1238 code = self._TCTRL_external_code.GetValue().strip() 1239 if code != '': 1240 self.data['external_code'] = code 1241 self.data['external_code_type'] = self._PRW_external_code_type.GetData().strip() 1242 success, data = self.data.save() 1243 if not success: 1244 err, msg = data 1245 _log.error('problem saving') 1246 _log.error('%s', err) 1247 _log.error('%s', msg) 1248 return (success is True)
1249 1250 #----------------------------------------------------------------
1251 - def _refresh_as_new(self):
1252 self._PRW_product_name.SetText('', None) 1253 self._PRW_preparation.SetText('', None) 1254 self._CHBOX_is_fake.SetValue(False) 1255 self._TCTRL_components.SetValue('') 1256 self._PRW_atc.SetText('', None) 1257 self._TCTRL_external_code.SetValue('') 1258 self._PRW_external_code_type.SetText('', None) 1259 1260 self._PRW_product_name.SetFocus() 1261 1262 self.__component_doses = []
1263 1264 #----------------------------------------------------------------
1266 self._refresh_as_new()
1267 1268 #----------------------------------------------------------------
1269 - def _refresh_from_existing(self):
1270 self._PRW_product_name.SetText(self.data['product'], self.data['pk_drug_product']) 1271 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation']) 1272 self._CHBOX_is_fake.SetValue(self.data['is_fake_product']) 1273 comp_str = '' 1274 if len(self.data['components']) > 0: 1275 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'] ]) 1276 self._TCTRL_components.SetValue(comp_str) 1277 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc'], ''), self.data['atc']) 1278 self._TCTRL_external_code.SetValue(gmTools.coalesce(self.data['external_code'], '')) 1279 t = gmTools.coalesce(self.data['external_code_type'], '') 1280 self._PRW_external_code_type.SetText(t, t) 1281 1282 self._PRW_product_name.SetFocus() 1283 1284 self.__component_doses = self.data.components_as_doses
1285 1286 #---------------------------------------------------------------- 1287 # event handler 1288 #----------------------------------------------------------------
1289 - def _on_manage_components_button_pressed(self, event):
1290 event.Skip() 1291 if self.mode == 'new_from_existing': 1292 product = None 1293 else: 1294 product = self.data 1295 OKed, doses = manage_components_of_drug_product(parent = self, product = product) 1296 if OKed is True: 1297 self.__component_doses = doses 1298 comp_str = '' 1299 if len(doses) > 0: 1300 comp_str = '- %s' % '\n- '.join([ '%s %s%s' % (d['substance'], d['amount'], gmMedication.format_units(d['unit'], d['dose_unit'])) for d in doses ]) 1301 self._TCTRL_components.SetValue(comp_str)
1302 1303 #------------------------------------------------------------
1304 -class cDrugProductPhraseWheel(gmPhraseWheel.cPhraseWheel):
1305
1306 - def __init__(self, *args, **kwargs):
1307 1308 query = """ 1309 SELECT 1310 pk 1311 AS data, 1312 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', '')) 1313 AS list_label, 1314 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', '')) 1315 AS field_label 1316 FROM ref.drug_product 1317 WHERE description %(fragment_condition)s 1318 ORDER BY list_label 1319 LIMIT 50""" 1320 1321 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query) 1322 mp.setThresholds(2, 3, 4) 1323 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs) 1324 self.SetToolTip(_( 1325 'The product name of the drug.\n' 1326 '\n' 1327 'Note: a product name will need to be linked to\n' 1328 'one or more components before it can be used,\n' 1329 'except in the case of fake (generic) vaccines.' 1330 )) 1331 self.matcher = mp 1332 self.selection_only = False
1333 1334 #============================================================ 1335 # single-component generic drugs 1336 # drug name is forced to substance + amount + unit + dose_unit 1337 #------------------------------------------------------------
1338 -def edit_single_component_generic_drug(parent=None, drug=None, single_entry=False, fields=None, return_drug=False):
1339 1340 # if drug is not None: 1341 # if drug.is_in_use_by_patients: 1342 # gmGuiHelpers.gm_show_info ( 1343 # aTitle = _('Editing single-component generic drug'), 1344 # aMessage = _( 1345 # 'Cannot edit the single-component generic drug\n' 1346 # '\n' 1347 # ' "%s" (%s)\n' 1348 # '\n' 1349 # 'because it is currently taken by patients.\n' 1350 # ) % (drug['product'], drug['l10n_preparation']) 1351 # ) 1352 # return False 1353 1354 if parent is None: 1355 parent = wx.GetApp().GetTopWindow() 1356 1357 # #-------------------------------------------- 1358 # def manage_substances(drug): 1359 # manage_substance_doses(parent = parent) 1360 1361 #-------------------------------------------- 1362 ea = cSingleComponentGenericDrugEAPnl(parent, -1) 1363 ea.data = drug 1364 ea.mode = gmTools.coalesce(drug, 'new', 'edit') 1365 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = single_entry) 1366 if fields is not None: 1367 ea.set_fields(fields) 1368 dlg.SetTitle(gmTools.coalesce(drug, _('Adding new single-component generic drug'), _('Editing single-component generic drug'))) 1369 # dlg.left_extra_button = ( 1370 # _('Substances'), 1371 # _('Manage substances'), 1372 # manage_substances 1373 # ) 1374 if dlg.ShowModal() == wx.ID_OK: 1375 drug = ea.data 1376 dlg.DestroyLater() 1377 if return_drug: 1378 return drug 1379 return True 1380 dlg.DestroyLater() 1381 if return_drug: 1382 return None 1383 return False
1384 1385 #------------------------------------------------------------
1386 -def manage_single_component_generic_drugs(parent=None, ignore_OK_button=False):
1387 1388 if parent is None: 1389 parent = wx.GetApp().GetTopWindow() 1390 1391 #------------------------------------------------------------ 1392 def add_from_db(drug): 1393 drug_db = get_drug_database(parent = parent) 1394 if drug_db is None: 1395 return False 1396 drug_db.import_drugs() 1397 return True
1398 1399 #------------------------------------------------------------ 1400 def get_tooltip(product=None): 1401 return product.format(include_component_details = True) 1402 1403 #------------------------------------------------------------ 1404 def edit(product): 1405 if product is not None: 1406 if product.is_vaccine: 1407 gmGuiHelpers.gm_show_info ( 1408 aTitle = _('Editing medication'), 1409 aMessage = _( 1410 'Cannot edit the medication\n' 1411 '\n' 1412 ' "%s" (%s)\n' 1413 '\n' 1414 'because it is a vaccine. Please edit it\n' 1415 'from the vaccine management section !\n' 1416 ) % (product['product'], product['l10n_preparation']) 1417 ) 1418 return False 1419 1420 return edit_drug_product(parent = parent, drug_product = product, single_entry = True) 1421 1422 #------------------------------------------------------------ 1423 def delete(product): 1424 if product.is_vaccine: 1425 gmGuiHelpers.gm_show_info ( 1426 aTitle = _('Deleting medication'), 1427 aMessage = _( 1428 'Cannot delete the medication\n' 1429 '\n' 1430 ' "%s" (%s)\n' 1431 '\n' 1432 'because it is a vaccine. Please delete it\n' 1433 'from the vaccine management section !\n' 1434 ) % (product['product'], product['l10n_preparation']) 1435 ) 1436 return False 1437 gmMedication.delete_drug_product(pk_drug_product = product['pk_drug_product']) 1438 return True 1439 1440 #------------------------------------------------------------ 1441 def new(): 1442 return edit_drug_product(parent = parent, drug_product = None, single_entry = False) 1443 1444 #------------------------------------------------------------ 1445 def refresh(lctrl): 1446 drugs = gmMedication.get_drug_products() 1447 items = [ [ 1448 '%s%s' % ( 1449 d['product'], 1450 gmTools.bool2subst(d['is_fake_product'], ' (%s)' % _('fake'), '') 1451 ), 1452 d['l10n_preparation'], 1453 gmTools.coalesce(d['atc'], ''), 1454 '; '.join([ '%s %s%s' % ( 1455 c['substance'], 1456 c['amount'], 1457 gmMedication.format_units(c['unit'], c['dose_unit']) 1458 ) for c in d['components']]), 1459 gmTools.coalesce(d['external_code'], '', '%%s [%s]' % d['external_code_type']), 1460 d['pk_drug_product'] 1461 ] for d in drugs ] 1462 lctrl.set_string_items(items) 1463 lctrl.set_data(drugs) 1464 1465 #------------------------------------------------------------ 1466 gmListWidgets.get_choices_from_list ( 1467 parent = parent, 1468 caption = _('Drug products currently known to GNUmed.'), 1469 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), '#'], 1470 single_selection = True, 1471 ignore_OK_button = ignore_OK_button, 1472 refresh_callback = refresh, 1473 new_callback = new, 1474 edit_callback = edit, 1475 delete_callback = delete, 1476 list_tooltip_callback = get_tooltip, 1477 #left_extra_button = (_('Import'), _('Import substances and products from a drug database.'), add_from_db) 1478 #, middle_extra_button = (_('Clone'), _('Clone selected drug into a new entry for editing.'), clone_from_existing) 1479 #, right_extra_button = (_('Reassign'), _('Reassign all patients taking the selected drug to another drug.'), reassign_patients) 1480 ) 1481 1482 #------------------------------------------------------------ 1483 from Gnumed.wxGladeWidgets import wxgSingleComponentGenericDrugEAPnl 1484
1485 -class cSingleComponentGenericDrugEAPnl(wxgSingleComponentGenericDrugEAPnl.wxgSingleComponentGenericDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
1486
1487 - def __init__(self, *args, **kwargs):
1488 1489 try: 1490 data = kwargs['drug'] 1491 del kwargs['drug'] 1492 except KeyError: 1493 data = None 1494 1495 wxgSingleComponentGenericDrugEAPnl.wxgSingleComponentGenericDrugEAPnl.__init__(self, *args, **kwargs) 1496 gmEditArea.cGenericEditAreaMixin.__init__(self) 1497 1498 self.mode = 'new' 1499 self.data = data 1500 if data is not None: 1501 self.mode = 'edit' 1502 1503 self.__init_ui()
1504 1505 #----------------------------------------------------------------
1506 - def __init_ui(self):
1507 self._PRW_substance.add_callback_on_modified(callback = self._on_name_field_modified) 1508 self._PRW_substance.add_callback_on_selection(callback = self._on_name_field_modified) 1509 self._TCTRL_amount.add_callback_on_modified(callback = self._on_name_field_modified) 1510 self._PRW_unit.add_callback_on_modified(callback = self._on_name_field_modified) 1511 self._PRW_unit.add_callback_on_selection(callback = self._on_name_field_modified) 1512 self._PRW_dose_unit.add_callback_on_modified(callback = self._on_name_field_modified) 1513 self._PRW_dose_unit.add_callback_on_selection(callback = self._on_name_field_modified)
1514 1515 #---------------------------------------------------------------- 1516 # generic Edit Area mixin API 1517 #----------------------------------------------------------------
1518 - def _valid_for_save(self):
1519 1520 validity = True 1521 1522 if self._PRW_preparation.Value.strip() == '': 1523 validity = False 1524 self._PRW_preparation.display_as_valid(False) 1525 self.StatusText = _('Drug form is missing.') 1526 self._PRW_preparation.SetFocus() 1527 else: 1528 self._PRW_preparation.display_as_valid(True) 1529 1530 if self._PRW_unit.GetData() is None: 1531 validity = False 1532 self._PRW_unit.display_as_valid(False) 1533 self.StatusText = _('Unit for amount is missing.') 1534 self._PRW_unit.SetFocus() 1535 else: 1536 self._PRW_unit.display_as_valid(True) 1537 1538 if self._TCTRL_amount.GetValue().strip() == '': 1539 validity = False 1540 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False) 1541 self.StatusText = _('Amount is missing.') 1542 self._TCTRL_amount.SetFocus() 1543 else: 1544 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True) 1545 1546 if self._PRW_substance.GetData() is None: 1547 val = self._PRW_substance.Value.strip() 1548 if val != '' and gmATC.exists_as_atc(val): 1549 subst = gmMedication.create_substance(substance = val) 1550 self._PRW_substance.SetText(subst['substance'], subst['pk_substance']) 1551 self._PRW_substance.display_as_valid(True) 1552 else: 1553 validity = False 1554 self._PRW_substance.display_as_valid(False) 1555 self.StatusText = _('Substance is missing.') 1556 self._PRW_substance.SetFocus() 1557 else: 1558 self._PRW_substance.display_as_valid(True) 1559 1560 return validity
1561 1562 #----------------------------------------------------------------
1563 - def _save_as_new(self):
1564 dose = gmMedication.create_substance_dose ( 1565 pk_substance = self._PRW_substance.GetData(), 1566 amount = self._TCTRL_amount.Value.strip(), 1567 unit = self._PRW_unit.GetData(), 1568 dose_unit = self._PRW_dose_unit.GetData() 1569 ) 1570 dose_unit = self._PRW_dose_unit.GetValue().strip() 1571 if dose_unit != '': 1572 dose_unit = '/' + dose_unit 1573 name = '%s %s%s%s' % ( 1574 self._PRW_substance.GetValue().strip(), 1575 self._TCTRL_amount.Value.strip(), 1576 self._PRW_unit.GetValue().strip(), 1577 dose_unit 1578 ) 1579 drug = gmMedication.create_drug_product ( 1580 product_name = name, 1581 preparation = self._PRW_preparation.GetValue().strip(), 1582 return_existing = True, 1583 doses = [dose] 1584 ) 1585 drug['is_fake_product'] = True 1586 drug.save() 1587 self.data = drug 1588 return True
1589 1590 #----------------------------------------------------------------
1591 - def _save_as_update(self):
1592 return False
1593 # self.data[''] = self._CHBOX_xxx.GetValue() 1594 # self.data.save() 1595 # return True 1596 1597 #----------------------------------------------------------------
1598 - def _refresh_as_new(self):
1599 self._LBL_drug_name.SetLabel('') 1600 self._PRW_substance.SetText('', None) 1601 self._TCTRL_amount.SetValue('') 1602 self._PRW_unit.SetText('', None) 1603 self._PRW_dose_unit.SetText('', None) 1604 self._PRW_preparation.SetText('', None)
1605 1606 #----------------------------------------------------------------
1608 self._refresh_as_new()
1609 1610 #----------------------------------------------------------------
1611 - def _refresh_from_existing(self):
1612 pass
1613 1614 #----------------------------------------------------------------
1615 - def set_fields(self, fields):
1616 try: 1617 self._PRW_substance.SetText(fields['substance']['value'], fields['substance']['data']) 1618 except KeyError: 1619 _log.error('cannot set field [substance] from <%s>', fields)
1620 1621 #----------------------------------------------------------------
1622 - def _on_name_field_modified(self, data=None):
1623 dose_unit = self._PRW_dose_unit.GetValue().strip() 1624 if dose_unit != '': 1625 dose_unit = '/' + dose_unit 1626 name = '%s %s%s%s' % ( 1627 self._PRW_substance.GetValue().strip(), 1628 self._TCTRL_amount.Value.strip(), 1629 self._PRW_unit.GetValue().strip(), 1630 dose_unit 1631 ) 1632 self._LBL_drug_name.SetLabel('"%s"' % name.strip())
1633 1634 #============================================================ 1635 # main 1636 #------------------------------------------------------------ 1637 if __name__ == '__main__': 1638 1639 if len(sys.argv) < 2: 1640 sys.exit() 1641 1642 if sys.argv[1] != 'test': 1643 sys.exit() 1644 1645 from Gnumed.business import gmPersonSearch 1646 1647 pat = gmPersonSearch.ask_for_patient() 1648 if pat is None: 1649 sys.exit() 1650 gmPerson.set_active_patient(patient = pat) 1651 1652 #---------------------------------------- 1653 app = wx.PyWidgetTester(size = (600, 300)) 1654 app.SetWidget(cSubstancePhraseWheel, -1) 1655 app.MainLoop() 1656 #manage_substance_intakes() 1657 edit_single_component_generic_drug ( 1658 single_entry = True, 1659 fields = {'substance': {'value': val, 'data': None}}, 1660 return_drug = True 1661 ) 1662