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

Source Code for Module Gnumed.wxpython.gmMacro

   1  #  coding: utf8 
   2  """GNUmed macro primitives. 
   3   
   4  This module implements functions a macro can legally use. 
   5  """ 
   6  #===================================================================== 
   7  __author__ = "K.Hilbert <karsten.hilbert@gmx.net>" 
   8   
   9  import sys 
  10  import time 
  11  import random 
  12  import types 
  13  import logging 
  14  import os 
  15  import codecs 
  16   
  17   
  18  import wx 
  19   
  20   
  21  if __name__ == '__main__': 
  22          sys.path.insert(0, '../../') 
  23  from Gnumed.pycommon import gmI18N 
  24  if __name__ == '__main__': 
  25          gmI18N.activate_locale() 
  26          gmI18N.install_domain() 
  27  from Gnumed.pycommon import gmGuiBroker 
  28  from Gnumed.pycommon import gmTools 
  29  from Gnumed.pycommon import gmBorg 
  30  from Gnumed.pycommon import gmExceptions 
  31  from Gnumed.pycommon import gmCfg2 
  32  from Gnumed.pycommon import gmDateTime 
  33  from Gnumed.pycommon import gmMimeLib 
  34   
  35  from Gnumed.business import gmPerson 
  36  from Gnumed.business import gmStaff 
  37  from Gnumed.business import gmDemographicRecord 
  38  from Gnumed.business import gmMedication 
  39  from Gnumed.business import gmPathLab 
  40  from Gnumed.business import gmPersonSearch 
  41  from Gnumed.business import gmVaccination 
  42  from Gnumed.business import gmKeywordExpansion 
  43   
  44  from Gnumed.wxpython import gmGuiHelpers 
  45  from Gnumed.wxpython import gmNarrativeWidgets 
  46  from Gnumed.wxpython import gmPatSearchWidgets 
  47  from Gnumed.wxpython import gmPersonContactWidgets 
  48  from Gnumed.wxpython import gmPlugin 
  49  from Gnumed.wxpython import gmEMRStructWidgets 
  50  from Gnumed.wxpython import gmListWidgets 
  51  from Gnumed.wxpython import gmDemographicsWidgets 
  52  from Gnumed.wxpython import gmDocumentWidgets 
  53  from Gnumed.wxpython import gmKeywordExpansionWidgets 
  54  from Gnumed.wxpython import gmMeasurementWidgets 
  55   
  56   
  57  _log = logging.getLogger('gm.scripting') 
  58  _cfg = gmCfg2.gmCfgData() 
  59   
  60  #===================================================================== 
  61  known_placeholders = [ 
  62          u'lastname', 
  63          u'firstname', 
  64          u'title', 
  65          u'date_of_birth', 
  66          u'progress_notes', 
  67          u'soap', 
  68          u'soap_s', 
  69          u'soap_o', 
  70          u'soap_a', 
  71          u'soap_p', 
  72          u'soap_u', 
  73          u'client_version', 
  74          u'current_provider', 
  75          u'primary_praxis_provider',                     # primary provider for current patient in this praxis 
  76          u'allergy_state' 
  77  ] 
  78   
  79   
  80  # values for the following placeholders must be injected from the outside before 
  81  # using them, in use they must conform to the "placeholder::::max length" syntax, 
  82  # as long as they resolve to None they return themselves 
  83  _injectable_placeholders = { 
  84          u'form_name_long': None, 
  85          u'form_name_short': None, 
  86          u'form_version': None 
  87  } 
  88   
  89   
  90  # the following must satisfy the pattern "$<name::args::(optional) max string length>$" when used 
  91  known_variant_placeholders = [ 
  92          # generic: 
  93          u'free_text',                                                   # show a dialog for entering some free text 
  94          u'text_snippet',                                                # a text snippet, taken from the keyword expansion mechanism 
  95                                                                                          # args: <snippet name>//<template> 
  96          u'data_snippet',                                                # a binary snippet, taken from the keyword expansion mechanism 
  97                                                                                          # args: <snippet name>//<template>//<optional target mime type>//<optional target extension> 
  98                                                                                          # returns full path to an exported copy of the 
  99                                                                                          # data rather than the data itself, 
 100                                                                                          #       template: string template for outputting the path 
 101                                                                                          #       target mime type: a mime type into which to convert the image, no conversion if not given 
 102                                                                                          #       target extension: target file name extension, derived from target mime type if not given 
 103          u'tex_escape',                                                  # "args" holds: string to escape 
 104          u'today',                                                               # "args" holds: strftime format 
 105          u'gender_mapper',                                               # "args" holds: <value when person is male> // <is female> // <is other> 
 106                                                                                          #                               eg. "male//female//other" 
 107                                                                                          #                               or: "Lieber Patient//Liebe Patientin" 
 108   
 109          # patient demographics: 
 110          u'name',                                                                # args: template for name parts arrangement 
 111          u'date_of_birth',                                               # args: strftime date/time format directive 
 112   
 113          u'patient_address',                                             # args: <type of address>//<optional formatting template> 
 114          u'adr_street',                                                  # args: <type of address> 
 115          u'adr_number', 
 116          u'adr_subunit', 
 117          u'adr_location', 
 118          u'adr_suburb', 
 119          u'adr_postcode', 
 120          u'adr_region', 
 121          u'adr_country', 
 122   
 123          u'patient_comm',                                                # args: <comm channel type as per database>//<%(key)s-template> 
 124          u'patient_tags',                                                # "args" holds: <%(key)s-template>//<separator> 
 125  #       u'patient_tags_table',                                  # "args" holds: no args 
 126   
 127          u'patient_photo',                                               # args: <template>//<optional target mime type>//<optional target extension> 
 128                                                                                          # returns full path to an exported copy of the 
 129                                                                                          # image rather than the image data itself, 
 130                                                                                          # returns u'' if no mugshot available, 
 131                                                                                          #       template: string template for outputting the path 
 132                                                                                          #       target mime type: a mime type into which to convert the image, no conversion if not given 
 133                                                                                          #       target extension: target file name extension, derived from target mime type if not given 
 134   
 135          u'external_id',                                                 # args: <type of ID>//<issuer of ID> 
 136   
 137   
 138          # clinical record related: 
 139          u'soap', 
 140          u'progress_notes',                                              # "args" holds: categories//template 
 141                                                                                          #       categories: string with 'soapu '; ' ' == None == admin 
 142                                                                                          #       template:       u'something %s something'               (do not include // in template !) 
 143   
 144          u'soap_for_encounters',                                 # lets the user select a list of encounters for which 
 145                                                                                          # LaTeX formatted progress notes are emitted: 
 146                                                                                          # "args": soap categories // strftime date format 
 147   
 148          u'soap_by_issue',                                               # lets the user select a list of issues and 
 149                                                                                          # then SOAP entries from those issues 
 150                                                                                          # "args": soap categories // strftime date format // template 
 151   
 152          u'soap_by_episode',                                             # lets the user select a list of issues and 
 153                                                                                          # then SOAP entries from those issues 
 154                                                                                          # "args": soap categories // strftime date format // template 
 155   
 156          u'emr_journal',                                                 # "args" format:   <categories>//<template>//<line length>//<time range>//<target format> 
 157                                                                                          #       categories:        string with any of "s", "o", "a", "p", "u", " "; 
 158                                                                                          #                                  (" " == None == admin category) 
 159                                                                                          #       template:          something %s something else 
 160                                                                                          #                                  (Do not include // in the template !) 
 161                                                                                          #       line length:   the maximum length of individual lines, not the total placeholder length 
 162                                                                                          #       time range:             the number of weeks going back in time if given as a single number, 
 163                                                                                          #                                       or else it must be a valid PostgreSQL interval definition (w/o the ::interval) 
 164                                                                                          #       target format: "tex" or anything else, if "tex", data will be tex-escaped       (currently only "latex") 
 165   
 166          u'current_meds',                                                # "args" holds: line template//<select> 
 167                                                                                          #       <select>: if this is present the user will be asked which meds to export 
 168          u'current_meds_table',                                  # "args" holds: format, options 
 169          u'current_meds_notes',                                  # "args" holds: format, options 
 170   
 171          u'lab_table',                                                   # "args" holds: format (currently "latex" only) 
 172          u'test_results',                                                # "args":                       <%(key)s-template>//<date format>//<line separator (EOL)> 
 173   
 174          u'latest_vaccs_table',                                  # "args" holds: format, options 
 175          u'vaccination_history',                                 # "args": <%(key)s-template//date format> to format one vaccination per line 
 176   
 177          u'allergies',                                                   # "args" holds: line template, one allergy per line 
 178          u'allergy_list',                                                # "args" holds: template per allergy, allergies on one line 
 179          u'problems',                                                    # "args" holds: line template, one problem per line 
 180          u'PHX',                                                                 # Past medical HiXtory, "args" holds: line template//separator//strftime date format//escape style (latex, currently) 
 181          u'encounter_list',                                              # "args" holds: per-encounter template, each ends up on one line 
 182   
 183          u'documents',                                                   # "args" format:        <select>//<description>//<template>//<path template>//<path> 
 184                                                                                          #       select:                 let user select which documents to include, 
 185                                                                                          #                                       optional, if not given: all documents included 
 186                                                                                          #       description:    whether to include descriptions, optional 
 187                                                                                          #       template:               something %(field)s something else, 
 188                                                                                          #                                       (do not include "//" itself in the template), 
 189                                                                                          #       path template:  the template for outputting the path to exported 
 190                                                                                          #                                       copies of the document pages, if not given no pages 
 191                                                                                          #                                       are exported, this template can contain "%(name)s" 
 192                                                                                          #                                       and/or "%(fullpath)s" which is replaced by the 
 193                                                                                          #                                       appropriate value for each exported file 
 194                                                                                          #       path:                   into which path to export copies of the document pages, 
 195                                                                                          #                                       temp dir if not given 
 196   
 197          # provider related: 
 198          u'current_provider_external_id',                # args: <type of ID>//<issuer of ID> 
 199          u'primary_praxis_provider_external_id', # args: <type of ID>//<issuer of ID> 
 200   
 201          # billing related: 
 202          u'bill',                                                                # args: template for string replacement 
 203          u'bill_item'                                                    # args: template for string replacement 
 204  ] 
 205   
 206  #http://help.libreoffice.org/Common/List_of_Regular_Expressions 
 207  default_placeholder_regex = r'\$<.+?>\$'                                # this one works [except that OOo cannot be non-greedy |-(    ] 
 208  #default_placeholder_regex = r'\$<(?:(?!\$<).)+>\$'             # non-greedy equivalent, uses lookahead (but not supported by LO either |-o  ) 
 209   
 210  default_placeholder_start = u'$<' 
 211  default_placeholder_end = u'>$' 
 212  #===================================================================== 
213 -def show_placeholders():
214 fname = gmTools.get_unique_filename(prefix = 'gm-placeholders-', suffix = '.txt') 215 ph_file = codecs.open(filename = fname, mode = 'wb', encoding = 'utf8', errors = 'replace') 216 217 ph_file.write(u'Here you can find some more documentation on placeholder use:\n') 218 ph_file.write(u'\n http://wiki.gnumed.de/bin/view/Gnumed/GmManualLettersForms\n\n\n') 219 220 ph_file.write(u'Simple placeholders (use like: $<PLACEHOLDER_NAME>$):\n') 221 for ph in known_placeholders: 222 ph_file.write(u' %s\n' % ph) 223 ph_file.write(u'\n') 224 225 ph_file.write(u'Variable placeholders (use like: $<PLACEHOLDER_NAME::ARGUMENTS::MAX OUTPUT LENGTH>$):\n') 226 for ph in known_variant_placeholders: 227 ph_file.write(u' %s\n' % ph) 228 ph_file.write(u'\n') 229 230 ph_file.write(u'Injectable placeholders (use like: $<PLACEHOLDER_NAME::ARGUMENTS::MAX OUTPUT LENGTH>$):\n') 231 for ph in _injectable_placeholders: 232 ph_file.write(u' %s\n' % ph) 233 ph_file.write(u'\n') 234 235 ph_file.close() 236 gmMimeLib.call_viewer_on_file(aFile = fname, block = False)
237 #=====================================================================
238 -class gmPlaceholderHandler(gmBorg.cBorg):
239 """Returns values for placeholders. 240 241 - patient related placeholders operate on the currently active patient 242 - is passed to the forms handling code, for example 243 244 Return values when .debug is False: 245 - errors with placeholders return None 246 - placeholders failing to resolve to a value return an empty string 247 248 Return values when .debug is True: 249 - errors with placeholders return an error string 250 - placeholders failing to resolve to a value return a warning string 251 252 There are several types of placeholders: 253 254 simple static placeholders 255 - those are listed in known_placeholders 256 - they are used as-is 257 258 extended static placeholders 259 - those are, effectively, static placeholders 260 with a maximum length attached (after "::::") 261 262 injectable placeholders 263 - they must be set up before use by set_placeholder() 264 - they should be removed after use by unset_placeholder() 265 - the syntax is like extended static placeholders 266 - they are listed in _injectable_placeholders 267 268 variant placeholders 269 - those are listed in known_variant_placeholders 270 - they are parsed into placeholder, data, and maximum length 271 - the length is optional 272 - data is passed to the handler 273 274 Note that this cannot be called from a non-gui thread unless 275 wrapped in wx.CallAfter(). 276 """
277 - def __init__(self, *args, **kwargs):
278 279 self.pat = gmPerson.gmCurrentPatient() 280 self.debug = False 281 282 self.invalid_placeholder_template = _('invalid placeholder [%s]') 283 284 self.__cache = {} 285 286 self.__esc_style = None 287 self.__esc_func = lambda x:x
288 #-------------------------------------------------------- 289 # external API 290 #--------------------------------------------------------
291 - def set_placeholder(self, key=None, value=None):
294 #--------------------------------------------------------
295 - def unset_placeholder(self, key=None):
298 #--------------------------------------------------------
299 - def set_cache_value(self, key=None, value=None):
300 self.__cache[key] = value
301 #--------------------------------------------------------
302 - def unset_cache_value(self, key=None):
303 del self.__cache[key]
304 #--------------------------------------------------------
305 - def _set_escape_style(escape_style=None):
306 self.__esc_style = escape_style 307 return
308 309 escape_style = property(lambda x:x, _set_escape_style) 310 #--------------------------------------------------------
311 - def _set_escape_function(escape_function=None):
312 if escape_function is None: 313 self.__esc_func = lambda x:x 314 return 315 if not callable(escape_function): 316 raise ValueError(u'[%s._set_escape_function]: <%s> not callable' % (self.__class__.__name__, escape_function)) 317 self.__esc_func = escape_function 318 return
319 320 escape_function = property(lambda x:x, _set_escape_function) 321 #-------------------------------------------------------- 322 # __getitem__ API 323 #--------------------------------------------------------
324 - def __getitem__(self, placeholder):
325 """Map self['placeholder'] to self.placeholder. 326 327 This is useful for replacing placeholders parsed out 328 of documents as strings. 329 330 Unknown/invalid placeholders still deliver a result but 331 it will be glaringly obvious if debugging is enabled. 332 """ 333 _log.debug('replacing [%s]', placeholder) 334 335 original_placeholder = placeholder 336 337 if placeholder.startswith(default_placeholder_start): 338 placeholder = placeholder[len(default_placeholder_start):] 339 if placeholder.endswith(default_placeholder_end): 340 placeholder = placeholder[:-len(default_placeholder_end)] 341 else: 342 _log.debug('placeholder must either start with [%s] and end with [%s] or neither of both', default_placeholder_start, default_placeholder_end) 343 if self.debug: 344 return self.invalid_placeholder_template % original_placeholder 345 return None 346 347 # simple static placeholder ? 348 if placeholder in known_placeholders: 349 return getattr(self, placeholder) 350 351 # injectable placeholder ? 352 parts = placeholder.split('::::', 1) 353 if len(parts) == 2: 354 name, lng = parts 355 unknown_injectable = False 356 try: 357 val = _injectable_placeholders[name] 358 except KeyError: 359 unknown_injectable = True 360 except: 361 _log.exception('placeholder handling error: %s', original_placeholder) 362 if self.debug: 363 return self.invalid_placeholder_template % original_placeholder 364 return None 365 if not unknown_injectable: 366 if val is None: 367 if self.debug: 368 return u'injectable placeholder [%s]: no value available' % name 369 return placeholder 370 return val[:int(lng)] 371 372 # extended static placeholder ? 373 parts = placeholder.split('::::', 1) 374 if len(parts) == 2: 375 name, lng = parts 376 try: 377 return getattr(self, name)[:int(lng)] 378 except: 379 _log.exception('placeholder handling error: %s', original_placeholder) 380 if self.debug: 381 return self.invalid_placeholder_template % original_placeholder 382 return None 383 384 # variable placeholders 385 parts = placeholder.split('::') 386 387 if len(parts) == 1: 388 _log.warning('invalid placeholder layout: %s', original_placeholder) 389 if self.debug: 390 return self.invalid_placeholder_template % original_placeholder 391 return None 392 393 if len(parts) == 2: 394 name, data = parts 395 lng = None 396 397 if len(parts) == 3: 398 name, data, lng = parts 399 try: 400 lng = int(lng) 401 except (TypeError, ValueError): 402 _log.error('placeholder length definition error: %s, discarding length: >%s<', original_placeholder, lng) 403 lng = None 404 405 if len(parts) > 3: 406 _log.warning('invalid placeholder layout: %s', original_placeholder) 407 if self.debug: 408 return self.invalid_placeholder_template % original_placeholder 409 return None 410 411 handler = getattr(self, '_get_variant_%s' % name, None) 412 if handler is None: 413 _log.warning('no handler <_get_variant_%s> for placeholder %s', name, original_placeholder) 414 if self.debug: 415 return self.invalid_placeholder_template % original_placeholder 416 return None 417 418 try: 419 if lng is None: 420 return handler(data = data) 421 return handler(data = data)[:lng] 422 except: 423 _log.exception('placeholder handling error: %s', original_placeholder) 424 if self.debug: 425 return self.invalid_placeholder_template % original_placeholder 426 return None 427 428 _log.error('something went wrong, should never get here') 429 return None
430 #-------------------------------------------------------- 431 # properties actually handling placeholders 432 #-------------------------------------------------------- 433 # property helpers 434 #--------------------------------------------------------
435 - def _setter_noop(self, val):
436 """This does nothing, used as a NOOP properties setter.""" 437 pass
438 #--------------------------------------------------------
439 - def _get_lastname(self):
440 return self._escape(self.pat.get_active_name()['lastnames'])
441 #--------------------------------------------------------
442 - def _get_firstname(self):
443 return self._escape(self.pat.get_active_name()['firstnames'])
444 #--------------------------------------------------------
445 - def _get_title(self):
446 return self._escape(gmTools.coalesce(self.pat.get_active_name()['title'], u''))
447 #--------------------------------------------------------
448 - def _get_dob(self):
449 return self._get_variant_date_of_birth(data = '%x')
450 #--------------------------------------------------------
451 - def _get_progress_notes(self):
452 return self._get_variant_soap()
453 #--------------------------------------------------------
454 - def _get_soap_s(self):
455 return self._get_variant_soap(data = u's')
456 #--------------------------------------------------------
457 - def _get_soap_o(self):
458 return self._get_variant_soap(data = u'o')
459 #--------------------------------------------------------
460 - def _get_soap_a(self):
461 return self._get_variant_soap(data = u'a')
462 #--------------------------------------------------------
463 - def _get_soap_p(self):
464 return self._get_variant_soap(data = u'p')
465 #--------------------------------------------------------
466 - def _get_soap_u(self):
467 return self._get_variant_soap(data = u'u')
468 #--------------------------------------------------------
469 - def _get_soap_admin(self):
470 return self._get_variant_soap(soap_cats = None)
471 #--------------------------------------------------------
472 - def _get_client_version(self):
473 return self._escape ( 474 gmTools.coalesce ( 475 _cfg.get(option = u'client_version'), 476 u'%s' % self.__class__.__name__ 477 ) 478 )
479 #--------------------------------------------------------
481 prov = self.pat.primary_provider 482 if prov is None: 483 return self._get_current_provider() 484 485 title = gmTools.coalesce ( 486 prov['title'], 487 gmPerson.map_gender2salutation(prov['gender']) 488 ) 489 490 tmp = u'%s %s. %s' % ( 491 title, 492 prov['firstnames'][:1], 493 prov['lastnames'] 494 ) 495 return self._escape(tmp)
496 #--------------------------------------------------------
497 - def _get_current_provider(self):
498 prov = gmStaff.gmCurrentProvider() 499 500 title = gmTools.coalesce ( 501 prov['title'], 502 gmPerson.map_gender2salutation(prov['gender']) 503 ) 504 505 tmp = u'%s %s. %s' % ( 506 title, 507 prov['firstnames'][:1], 508 prov['lastnames'] 509 ) 510 return self._escape(tmp)
511 #--------------------------------------------------------
512 - def _get_allergy_state(self):
513 allg_state = self.pat.get_emr().allergy_state 514 515 if allg_state['last_confirmed'] is None: 516 date_confirmed = u'' 517 else: 518 date_confirmed = u' (%s)' % gmDateTime.pydt_strftime ( 519 allg_state['last_confirmed'], 520 format = '%Y %B %d' 521 ) 522 523 tmp = u'%s%s' % ( 524 allg_state.state_string, 525 date_confirmed 526 ) 527 return self._escape(tmp)
528 #-------------------------------------------------------- 529 # property definitions for static placeholders 530 #-------------------------------------------------------- 531 placeholder_regex = property(lambda x: default_placeholder_regex, _setter_noop) 532 533 #-------------------------------------------------------- 534 535 # placeholders 536 lastname = property(_get_lastname, _setter_noop) 537 firstname = property(_get_firstname, _setter_noop) 538 title = property(_get_title, _setter_noop) 539 date_of_birth = property(_get_dob, _setter_noop) 540 541 progress_notes = property(_get_progress_notes, _setter_noop) 542 soap = property(_get_progress_notes, _setter_noop) 543 soap_s = property(_get_soap_s, _setter_noop) 544 soap_o = property(_get_soap_o, _setter_noop) 545 soap_a = property(_get_soap_a, _setter_noop) 546 soap_p = property(_get_soap_p, _setter_noop) 547 soap_u = property(_get_soap_u, _setter_noop) 548 soap_admin = property(_get_soap_admin, _setter_noop) 549 550 allergy_state = property(_get_allergy_state, _setter_noop) 551 552 client_version = property(_get_client_version, _setter_noop) 553 554 current_provider = property(_get_current_provider, _setter_noop) 555 primary_praxis_provider = property(_get_primary_praxis_provider, _setter_noop) 556 #-------------------------------------------------------- 557 # variant handlers 558 #--------------------------------------------------------
559 - def _get_variant_documents(self, data=None):
560 561 select = False 562 include_descriptions = False 563 template = u'%s' 564 path_template = None 565 export_path = None 566 567 data_parts = data.split('//') 568 569 if u'select' in data_parts: 570 select = True 571 data_parts.remove(u'select') 572 573 if u'description' in data_parts: 574 include_descriptions = True 575 data_parts.remove(u'description') 576 577 template = data_parts[0] 578 579 if len(data_parts) > 1: 580 path_template = data_parts[1] 581 582 if len(data_parts) > 2: 583 export_path = data_parts[2] 584 585 # create path 586 if export_path is not None: 587 export_path = os.path.normcase(os.path.expanduser(export_path)) 588 gmTools.mkdir(export_path) 589 590 # select docs 591 if select: 592 docs = gmDocumentWidgets.manage_documents(msg = _('Select the patient documents to reference from the new document.'), single_selection = False) 593 else: 594 docs = self.pat.document_folder.documents 595 596 if docs is None: 597 return u'' 598 599 lines = [] 600 for doc in docs: 601 lines.append(template % doc.fields_as_dict(date_format = '%Y %b %d', escape_style = self.__esc_style)) 602 if include_descriptions: 603 for desc in doc.get_descriptions(max_lng = None): 604 lines.append(self._escape(desc['text'] + u'\n')) 605 if path_template is not None: 606 for part_name in doc.export_parts_to_files(export_dir = export_path): 607 path, name = os.path.split(part_name) 608 lines.append(path_template % {'fullpath': part_name, 'name': name}) 609 610 return u'\n'.join(lines)
611 #--------------------------------------------------------
612 - def _get_variant_encounter_list(self, data=None):
613 614 encounters = gmEMRStructWidgets.select_encounters(single_selection = False) 615 if not encounters: 616 return u'' 617 618 template = data 619 620 lines = [] 621 for enc in encounters: 622 try: 623 lines.append(template % enc.fields_as_dict(date_format = '%Y %b %d', escape_style = self.__esc_style)) 624 except: 625 lines.append(u'error formatting encounter') 626 _log.exception('problem formatting encounter list') 627 _log.error('template: %s', template) 628 _log.error('encounter: %s', encounter) 629 630 return u'\n'.join(lines)
631 #--------------------------------------------------------
632 - def _get_variant_soap_for_encounters(self, data=None):
633 """Select encounters from list and format SOAP thereof. 634 635 data: soap_cats (' ' -> None -> admin) // date format 636 """ 637 # defaults 638 cats = None 639 date_format = None 640 641 if data is not None: 642 data_parts = data.split('//') 643 644 # part[0]: categories 645 if len(data_parts[0]) > 0: 646 cats = [] 647 if u' ' in data_parts[0]: 648 cats.append(None) 649 data_parts[0] = data_parts[0].replace(u' ', u'') 650 cats.extend(list(data_parts[0])) 651 652 # part[1]: date format 653 if len(data_parts) > 1: 654 if len(data_parts[1]) > 0: 655 date_format = data_parts[1] 656 657 encounters = gmEMRStructWidgets.select_encounters(single_selection = False) 658 if not encounters: 659 return u'' 660 661 chunks = [] 662 for enc in encounters: 663 chunks.append(enc.format_latex ( 664 date_format = date_format, 665 soap_cats = cats, 666 soap_order = u'soap_rank, date' 667 )) 668 669 return u''.join(chunks)
670 #--------------------------------------------------------
671 - def _get_variant_emr_journal(self, data=None):
672 # default: all categories, neutral template 673 cats = list(u'soapu') 674 cats.append(None) 675 template = u'%s' 676 interactive = True 677 line_length = 9999 678 target_format = None 679 time_range = None 680 681 if data is not None: 682 data_parts = data.split('//') 683 684 # part[0]: categories 685 cats = [] 686 # ' ' -> None == admin 687 for c in list(data_parts[0]): 688 if c == u' ': 689 c = None 690 cats.append(c) 691 # '' -> SOAP + None 692 if cats == u'': 693 cats = list(u'soapu').append(None) 694 695 # part[1]: template 696 if len(data_parts) > 1: 697 template = data_parts[1] 698 699 # part[2]: line length 700 if len(data_parts) > 2: 701 try: 702 line_length = int(data_parts[2]) 703 except: 704 line_length = 9999 705 706 # part[3]: weeks going back in time 707 if len(data_parts) > 3: 708 try: 709 time_range = 7 * int(data_parts[3]) 710 except: 711 #time_range = None # infinite 712 # pass on literally, meaning it must be a valid PG interval string 713 time_range = data_parts[3] 714 715 # part[4]: output format 716 if len(data_parts) > 4: 717 target_format = data_parts[4] 718 719 # FIXME: will need to be a generator later on 720 narr = self.pat.emr.get_as_journal(soap_cats = cats, time_range = time_range) 721 722 if len(narr) == 0: 723 return u'' 724 725 keys = narr[0].keys() 726 lines = [] 727 line_dict = {} 728 for n in narr: 729 for key in keys: 730 if isinstance(n[key], basestring): 731 line_dict[key] = self._escape(text = n[key]) 732 continue 733 line_dict[key] = n[key] 734 try: 735 lines.append((template % line_dict)[:line_length]) 736 except KeyError: 737 return u'invalid key in template [%s], valid keys: %s]' % (template, str(keys)) 738 739 #------------- 740 # if target_format == u'tex': 741 # keys = narr[0].keys() 742 # lines = [] 743 # line_dict = {} 744 # for n in narr: 745 # for key in keys: 746 # if isinstance(n[key], basestring): 747 # line_dict[key] = gmTools.tex_escape_string(text = n[key]) 748 # continue 749 # line_dict[key] = n[key] 750 # try: 751 # lines.append((template % line_dict)[:line_length]) 752 # except KeyError: 753 # return u'invalid key in template [%s], valid keys: %s]' % (template, str(keys)) 754 # else: 755 # try: 756 # lines = [ (template % n)[:line_length] for n in narr ] 757 # except KeyError: 758 # return u'invalid key in template [%s], valid keys: %s]' % (template, str(narr[0].keys())) 759 #------------------- 760 761 return u'\n'.join(lines)
762 #--------------------------------------------------------
763 - def _get_variant_soap_by_issue(self, data=None):
764 return self.__get_variant_soap_by_issue_or_episode(data = data, mode = u'issue')
765 #--------------------------------------------------------
766 - def _get_variant_soap_by_episode(self, data=None):
767 return self.__get_variant_soap_by_issue_or_episode(data = data, mode = u'episode')
768 #--------------------------------------------------------
769 - def __get_variant_soap_by_issue_or_episode(self, data=None, mode=None):
770 771 # default: all categories, neutral template 772 cats = list(u'soapu') 773 cats.append(None) 774 775 date_format = None 776 template = u'%s' 777 778 if data is not None: 779 data_parts = data.split('//') 780 781 # part[0]: categories 782 if len(data_parts[0]) > 0: 783 cats = [] 784 if u' ' in data_parts[0]: 785 cats.append(None) 786 cats.extend(list(data_parts[0].replace(u' ', u''))) 787 788 # part[1]: date format 789 if len(data_parts) > 1: 790 if len(data_parts[1]) > 0: 791 date_format = data_parts[1] 792 793 # part[2]: template 794 if len(data_parts) > 2: 795 if len(data_parts[2]) > 0: 796 template = data_parts[2] 797 798 if mode == u'issue': 799 narr = gmNarrativeWidgets.select_narrative_by_issue(soap_cats = cats) 800 else: 801 narr = gmNarrativeWidgets.select_narrative_by_episode(soap_cats = cats) 802 803 if narr is None: 804 return u'' 805 806 if len(narr) == 0: 807 return u'' 808 809 try: 810 narr = [ template % n.fields_as_dict(date_format = date_format, escape_style = self.__esc_style) for n in narr ] 811 except KeyError: 812 return u'invalid key in template [%s], valid keys: %s]' % (template, str(narr[0].keys())) 813 814 return u'\n'.join(narr)
815 #--------------------------------------------------------
816 - def _get_variant_progress_notes(self, data=None):
817 return self._get_variant_soap(data=data)
818 #--------------------------------------------------------
819 - def _get_variant_soap(self, data=None):
820 821 # default: all categories, neutral template 822 cats = list(u'soapu') 823 cats.append(None) 824 template = u'%(narrative)s' 825 826 if data is not None: 827 data_parts = data.split('//') 828 829 # part[0]: categories 830 cats = [] 831 # ' ' -> None == admin 832 for cat in list(data_parts[0]): 833 if cat == u' ': 834 cat = None 835 cats.append(cat) 836 # '' -> SOAP + None 837 if cats == u'': 838 cats = list(u'soapu') 839 cats.append(None) 840 841 # part[1]: template 842 if len(data_parts) > 1: 843 template = data_parts[1] 844 845 narr = gmNarrativeWidgets.select_narrative_from_episodes(soap_cats = cats) 846 847 if narr is None: 848 return u'' 849 850 if len(narr) == 0: 851 return u'' 852 853 # if any "%s" is in the template there cannot be any %(key)s 854 # and we also restrict the fields to .narrative (this is the 855 # old placeholder behaviour 856 if u'%s' in template: 857 narr = [ self._escape(n['narrative']) for n in narr ] 858 else: 859 narr = [ n.fields_as_dict(escape_style = self.__esc_style) for n in narr ] 860 861 try: 862 narr = [ template % n for n in narr ] 863 except KeyError: 864 return u'invalid key in template [%s], valid keys: %s]' % (template, str(narr[0].keys())) 865 except TypeError: 866 return u'cannot mix "%%s" and "%%(key)s" in template [%s]' % template 867 868 return u'\n'.join(narr)
869 #--------------------------------------------------------
870 - def _get_variant_name(self, data=None):
871 if data is None: 872 return [_('template is missing')] 873 874 name = self.pat.get_active_name() 875 876 parts = { 877 'title': self._escape(gmTools.coalesce(name['title'], u'')), 878 'firstnames': self._escape(name['firstnames']), 879 'lastnames': self._escape(name['lastnames']), 880 'preferred': self._escape(gmTools.coalesce ( 881 initial = name['preferred'], 882 instead = u' ', 883 template_initial = u' "%s" ' 884 )) 885 } 886 887 return data % parts
888 #--------------------------------------------------------
889 - def _get_variant_date_of_birth(self, data='%x'):
890 return self.pat.get_formatted_dob(format = str(data), encoding = gmI18N.get_encoding())
891 #-------------------------------------------------------- 892 # FIXME: extend to all supported genders
893 - def _get_variant_gender_mapper(self, data='male//female//other'):
894 895 values = data.split('//', 2) 896 897 if len(values) == 2: 898 male_value, female_value = values 899 other_value = u'<unkown gender>' 900 elif len(values) == 3: 901 male_value, female_value, other_value = values 902 else: 903 return _('invalid gender mapping layout: [%s]') % data 904 905 if self.pat['gender'] == u'm': 906 return self._escape(male_value) 907 908 if self.pat['gender'] == u'f': 909 return self._escape(female_value) 910 911 return self._escape(other_value)
912 #-------------------------------------------------------- 913 # address related placeholders 914 #--------------------------------------------------------
915 - def _get_variant_patient_address(self, data=u''):
916 917 data_parts = data.split(u'//') 918 919 # address type 920 adr_type = data_parts[0].strip() 921 orig_type = adr_type 922 if adr_type != u'': 923 adrs = self.pat.get_addresses(address_type = adr_type) 924 if len(adrs) == 0: 925 _log.warning('no address for type [%s]', adr_type) 926 adr_type = u'' 927 if adr_type == u'': 928 _log.debug('asking user for address type') 929 adr = gmPersonContactWidgets.select_address(missing = orig_type, person = self.pat) 930 if adr is None: 931 if self.debug: 932 return _('no address type replacement selected') 933 return u'' 934 adr_type = adr['address_type'] 935 adr = self.pat.get_addresses(address_type = adr_type)[0] 936 937 # formatting template 938 template = _('%(street)s %(number)s, %(postcode)s %(urb)s, %(l10n_state)s, %(l10n_country)s') 939 if len(data_parts) > 1: 940 if data_parts[1].strip() != u'': 941 template = data_parts[1] 942 943 try: 944 return template % adr.fields_as_dict(escape_style = self.__esc_style) 945 except StandardError: 946 _log.exception('error formatting address') 947 _log.error('template: %s', template) 948 949 return None
950 #--------------------------------------------------------
951 - def __get_variant_adr_part(self, data=u'?', part=None):
952 requested_type = data.strip() 953 cache_key = 'adr-type-%s' % requested_type 954 try: 955 type2use = self.__cache[cache_key] 956 _log.debug('cache hit (%s): [%s] -> [%s]', cache_key, requested_type, type2use) 957 except KeyError: 958 type2use = requested_type 959 if type2use != u'': 960 adrs = self.pat.get_addresses(address_type = type2use) 961 if len(adrs) == 0: 962 _log.warning('no address of type [%s] for <%s> field extraction', requested_type, part) 963 type2use = u'' 964 if type2use == u'': 965 _log.debug('asking user for replacement address type') 966 adr = gmPersonContactWidgets.select_address(missing = requested_type, person = self.pat) 967 if adr is None: 968 _log.debug('no replacement selected') 969 if self.debug: 970 return self._escape(_('no address type replacement selected')) 971 return u'' 972 type2use = adr['address_type'] 973 self.__cache[cache_key] = type2use 974 _log.debug('caching (%s): [%s] -> [%s]', cache_key, requested_type, type2use) 975 976 return self._escape(self.pat.get_addresses(address_type = type2use)[0][part])
977 #--------------------------------------------------------
978 - def _get_variant_adr_street(self, data=u'?'):
979 return self.__get_variant_adr_part(data = data, part = 'street')
980 #--------------------------------------------------------
981 - def _get_variant_adr_number(self, data=u'?'):
982 return self.__get_variant_adr_part(data = data, part = 'number')
983 #--------------------------------------------------------
984 - def _get_variant_adr_subunit(self, data=u'?'):
985 return self.__get_variant_adr_part(data = data, part = 'subunit')
986 #--------------------------------------------------------
987 - def _get_variant_adr_location(self, data=u'?'):
988 return self.__get_variant_adr_part(data = data, part = 'urb')
989 #--------------------------------------------------------
990 - def _get_variant_adr_suburb(self, data=u'?'):
991 return self.__get_variant_adr_part(data = data, part = 'suburb')
992 #--------------------------------------------------------
993 - def _get_variant_adr_postcode(self, data=u'?'):
994 return self.__get_variant_adr_part(data = data, part = 'postcode')
995 #--------------------------------------------------------
996 - def _get_variant_adr_region(self, data=u'?'):
997 return self.__get_variant_adr_part(data = data, part = 'l10n_state')
998 #--------------------------------------------------------
999 - def _get_variant_adr_country(self, data=u'?'):
1000 return self.__get_variant_adr_part(data = data, part = 'l10n_country')
1001 #--------------------------------------------------------
1002 - def _get_variant_patient_comm(self, data=None):
1003 comm_type = None 1004 template = u'%(url)s' 1005 if data is not None: 1006 data_parts = data.split(u'//') 1007 if len(data_parts) > 0: 1008 comm_type = data_parts[0] 1009 if len(data_parts) > 1: 1010 template = data_parts[1] 1011 1012 comms = self.pat.get_comm_channels(comm_medium = comm_type) 1013 if len(comms) == 0: 1014 if self.debug: 1015 return template + u': ' + self._escape(_('no URL for comm channel [%s]') % data) 1016 return u'' 1017 1018 return template % comms[0].fields_as_dict(escape_style = self.__esc_style)
1019 # self._escape(comms[0]['url']) 1020 #--------------------------------------------------------
1021 - def _get_variant_patient_photo(self, data=None):
1022 1023 template = u'%s' 1024 target_mime = None 1025 target_ext = None 1026 if data is not None: 1027 parts = data.split(u'//') 1028 template = parts[0] 1029 if len(parts) > 1: 1030 target_mime = parts[1].strip() 1031 if len(parts) > 2: 1032 target_ext = parts[2].strip() 1033 if target_ext is None: 1034 if target_mime is not None: 1035 target_ext = gmMimeLib.guess_ext_by_mimetype(mimetype = target_mime) 1036 1037 mugshot = self.pat.document_folder.latest_mugshot 1038 if mugshot is None: 1039 if self.debug: 1040 return self._escape(_('no mugshot available')) 1041 return u'' 1042 1043 fname = mugshot.export_to_file ( 1044 target_mime = target_mime, 1045 target_extension = target_ext, 1046 ignore_conversion_problems = True 1047 ) 1048 if fname is None: 1049 if self.debug: 1050 return self._escape(_('cannot export or convert latest mugshot')) 1051 return u'' 1052 1053 return template % fname
1054 #--------------------------------------------------------
1055 - def _get_variant_patient_tags(self, data=u'%s//\\n'):
1056 if len(self.pat.tags) == 0: 1057 if self.debug: 1058 return self._escape(_('no tags for this patient')) 1059 return u'' 1060 1061 tags = gmDemographicsWidgets.select_patient_tags(patient = self.pat) 1062 1063 if tags is None: 1064 if self.debug: 1065 return self._escape(_('no patient tags selected for inclusion') % data) 1066 return u'' 1067 1068 template, separator = data.split('//', 2) 1069 1070 return separator.join([ template % t.fields_as_dict(escape_style = self.__esc_style) for t in tags ])
1071 # #-------------------------------------------------------- 1072 # def _get_variant_patient_tags_table(self, data=u'?'): 1073 # pass 1074 #--------------------------------------------------------
1075 - def _get_variant_current_provider_external_id(self, data=u''):
1076 data_parts = data.split(u'//') 1077 if len(data_parts) < 2: 1078 return self._escape(u'current provider external ID: template is missing') 1079 1080 id_type = data_parts[0].strip() 1081 if id_type == u'': 1082 return self._escape(u'current provider external ID: type is missing') 1083 1084 issuer = data_parts[1].strip() 1085 if issuer == u'': 1086 return self._escape(u'current provider external ID: issuer is missing') 1087 1088 prov = gmStaff.gmCurrentProvider() 1089 ids = prov.identity.get_external_ids(id_type = id_type, issuer = issuer) 1090 1091 if len(ids) == 0: 1092 if self.debug: 1093 return self._escape(_('no external ID [%s] by [%s]') % (id_type, issuer)) 1094 return u'' 1095 1096 return self._escape(ids[0]['value'])
1097 #--------------------------------------------------------
1099 data_parts = data.split(u'//') 1100 if len(data_parts) < 2: 1101 return self._escape(u'primary in-praxis provider external ID: template is missing') 1102 1103 id_type = data_parts[0].strip() 1104 if id_type == u'': 1105 return self._escape(u'primary in-praxis provider external ID: type is missing') 1106 1107 issuer = data_parts[1].strip() 1108 if issuer == u'': 1109 return self._escape(u'primary in-praxis provider external ID: issuer is missing') 1110 1111 prov = self.pat.primary_provider 1112 if prov is None: 1113 if self.debug: 1114 return self._escape(_('no primary in-praxis provider')) 1115 return u'' 1116 1117 ids = prov.identity.get_external_ids(id_type = id_type, issuer = issuer) 1118 1119 if len(ids) == 0: 1120 if self.debug: 1121 return self._escape(_('no external ID [%s] by [%s]') % (id_type, issuer)) 1122 return u'' 1123 1124 return self._escape(ids[0]['value'])
1125 #--------------------------------------------------------
1126 - def _get_variant_external_id(self, data=u''):
1127 data_parts = data.split(u'//') 1128 if len(data_parts) < 2: 1129 return self._escape(u'patient external ID: template is missing') 1130 1131 id_type = data_parts[0].strip() 1132 if id_type == u'': 1133 return self._escape(u'patient external ID: type is missing') 1134 1135 issuer = data_parts[1].strip() 1136 if issuer == u'': 1137 return self._escape(u'patient external ID: issuer is missing') 1138 1139 ids = self.pat.get_external_ids(id_type = id_type, issuer = issuer) 1140 1141 if len(ids) == 0: 1142 if self.debug: 1143 return self._escape(_('no external ID [%s] by [%s]') % (id_type, issuer)) 1144 return u'' 1145 1146 return self._escape(ids[0]['value'])
1147 #--------------------------------------------------------
1148 - def _get_variant_allergy_list(self, data=None):
1149 if data is None: 1150 return self._escape(_('template is missing')) 1151 1152 template, separator = data.split('//', 2) 1153 1154 return separator.join([ template % a.fields_as_dict(date_format = '%Y %b %d', escape_style = self.__esc_style) for a in self.pat.emr.get_allergies() ])
1155 #--------------------------------------------------------
1156 - def _get_variant_allergies(self, data=None):
1157 1158 if data is None: 1159 return self._escape(_('template is missing')) 1160 1161 return u'\n'.join([ data % a.fields_as_dict(date_format = '%Y %b %d', escape_style = self.__esc_style) for a in self.pat.emr.get_allergies() ])
1162 #--------------------------------------------------------
1163 - def _get_variant_current_meds(self, data=None):
1164 1165 if data is None: 1166 return self._escape(_('template is missing')) 1167 1168 parts = data.split(u'//') 1169 template = parts[0] 1170 ask_user = False 1171 if len(parts) > 1: 1172 ask_user = (parts[1] == u'select') 1173 1174 emr = self.pat.get_emr() 1175 if ask_user: 1176 from Gnumed.wxpython import gmMedicationWidgets 1177 current_meds = gmMedicationWidgets.manage_substance_intakes(emr = emr) 1178 if current_meds is None: 1179 return u'' 1180 else: 1181 current_meds = emr.get_current_substance_intake ( 1182 include_inactive = False, 1183 include_unapproved = True, 1184 order_by = u'brand, substance' 1185 ) 1186 if len(current_meds) == 0: 1187 return u'' 1188 1189 return u'\n'.join([ template % m.fields_as_dict(date_format = '%Y %b %d', escape_style = self.__esc_style) for m in current_meds ])
1190 #--------------------------------------------------------
1191 - def _get_variant_current_meds_table(self, data=None):
1192 options = data.split('//') 1193 1194 return gmMedication.format_substance_intake ( 1195 emr = self.pat.emr, 1196 output_format = self.__esc_style, 1197 table_type = u'by-brand' 1198 )
1199 #--------------------------------------------------------
1200 - def _get_variant_current_meds_notes(self, data=None):
1201 options = data.split('//') 1202 1203 return gmMedication.format_substance_intake_notes ( 1204 emr = self.pat.get_emr(), 1205 output_format = self.__esc_style, 1206 table_type = u'by-brand' 1207 )
1208 #--------------------------------------------------------
1209 - def _get_variant_lab_table(self, data=None):
1210 options = data.split('//') 1211 1212 return gmPathLab.format_test_results ( 1213 results = self.pat.emr.get_test_results_by_date(), 1214 output_format = self.__esc_style 1215 )
1216 #--------------------------------------------------------
1217 - def _get_variant_test_results(self, data=None):
1218 1219 template = u'' 1220 date_format = '%Y %b %d %H:%M' 1221 separator = u'\n' 1222 1223 options = data.split(u'//') 1224 try: 1225 template = options[0].strip() 1226 date_format = options[1] 1227 separator = options[2] 1228 except IndexError: 1229 pass 1230 1231 if date_format.strip() == u'': 1232 date_format = '%Y %b %d %H:%M' 1233 if separator.strip() == u'': 1234 separator = u'\n' 1235 1236 results = gmMeasurementWidgets.manage_measurements(single_selection = False, emr = self.pat.emr) 1237 if results is None: 1238 if self.debug: 1239 return self._escape(_('no results for this patient (available or selected)')) 1240 return u'' 1241 1242 if template == u'': 1243 return (separator + separator).join([ self._escape(r.format(date_format = date_format)) for r in results ]) 1244 1245 return separator.join([ template % r.fields_as_dict(date_format = date_format, escape_style = self.__esc_style) for r in results ])
1246 #--------------------------------------------------------
1247 - def _get_variant_latest_vaccs_table(self, data=None):
1248 options = data.split('//') 1249 1250 return gmVaccination.format_latest_vaccinations ( 1251 output_format = self.__esc_style, 1252 emr = self.pat.emr 1253 )
1254 #--------------------------------------------------------
1255 - def _get_variant_vaccination_history(self, data=None):
1256 options = data.split('//') 1257 template = options[0] 1258 if len(options) > 1: 1259 date_format = options[1] 1260 else: 1261 date_format = u'%Y %b %d' 1262 1263 vaccs = self.pat.emr.get_vaccinations(order_by = u'date_given DESC, vaccine') 1264 1265 return u'\n'.join([ template % v.fields_as_dict(date_format = date_format, escape_style = self.__esc_style) for v in vaccs ])
1266 #--------------------------------------------------------
1267 - def _get_variant_PHX(self, data=None):
1268 1269 if data is None: 1270 if self.debug: 1271 _log.error('PHX: missing placeholder arguments') 1272 return self._escape(_('PHX: Invalid placeholder options.')) 1273 return u'' 1274 1275 _log.debug('arguments: %s', data) 1276 1277 data_parts = data.split(u'//') 1278 template = u'%s' 1279 separator = u'\n' 1280 date_format = '%Y %b %d' 1281 esc_style = None 1282 try: 1283 template = data_parts[0] 1284 separator = data_parts[1] 1285 date_format = data_parts[2] 1286 esc_style = data_parts[3] 1287 except IndexError: 1288 pass 1289 1290 phxs = gmEMRStructWidgets.select_health_issues(emr = self.pat.emr) 1291 if phxs is None: 1292 if self.debug: 1293 return self._escape(_('no PHX for this patient (available or selected)')) 1294 return u'' 1295 1296 return separator.join ([ 1297 template % phx.fields_as_dict ( 1298 date_format = date_format, 1299 #escape_style = esc_style, 1300 escape_style = self.__esc_style, 1301 bool_strings = (self._escape(_('yes')), self._escape(_('no'))) 1302 ) for phx in phxs 1303 ])
1304 #--------------------------------------------------------
1305 - def _get_variant_problems(self, data=None):
1306 1307 if data is None: 1308 return self._escape(_('template is missing')) 1309 1310 probs = self.pat.emr.get_problems() 1311 1312 return u'\n'.join([ data % p.fields_as_dict(date_format = '%Y %b %d', escape_style = self.__esc_style) for p in probs ])
1313 #--------------------------------------------------------
1314 - def _get_variant_today(self, data='%x'):
1315 return self._escape(gmDateTime.pydt_now_here().strftime(str(data)).decode(gmI18N.get_encoding()))
1316 #--------------------------------------------------------
1317 - def _get_variant_tex_escape(self, data=None):
1318 return gmTools.tex_escape_string(text = data)
1319 #--------------------------------------------------------
1320 - def _get_variant_text_snippet(self, data=None):
1321 data_parts = data.split(u'//') 1322 keyword = data_parts[0] 1323 template = u'%s' 1324 if len(data_parts) > 1: 1325 template = data_parts[1] 1326 1327 expansion = gmKeywordExpansionWidgets.expand_keyword(keyword = keyword, show_list = True) 1328 1329 if expansion is None: 1330 if self.debug: 1331 return self._escape(_('no textual expansion found for keyword <%s>') % keyword) 1332 return u'' 1333 1334 #return template % self._escape(expansion) 1335 return template % expansion
1336 #--------------------------------------------------------
1337 - def _get_variant_data_snippet(self, data=None):
1338 parts = data.split(u'//') 1339 keyword = parts[0] 1340 template = u'%s' 1341 target_mime = None 1342 target_ext = None 1343 if len(parts) > 1: 1344 template = parts[1] 1345 if len(parts) > 2: 1346 target_mime = parts[2].strip() 1347 if len(parts) > 3: 1348 target_ext = parts[3].strip() 1349 if target_ext is None: 1350 if target_mime is not None: 1351 target_ext = gmMimeLib.guess_ext_by_mimetype(mimetype = target_mime) 1352 1353 expansion = gmKeywordExpansion.get_expansion ( 1354 keyword = keyword, 1355 textual_only = False, 1356 binary_only = True 1357 ) 1358 if expansion is None: 1359 if self.debug: 1360 return self._escape(_('no binary expansion found for keyword <%s>') % keyword) 1361 return u'' 1362 1363 filename = expansion.export_to_file() 1364 if filename is None: 1365 if self.debug: 1366 return self._escape(_('cannot export data of binary expansion keyword <%s>') % keyword) 1367 return u'' 1368 1369 if expansion['is_encrypted']: 1370 pwd = wx.GetPasswordFromUser ( 1371 message = _('Enter your GnuPG passphrase for decryption of [%s]') % expansion['keyword'], 1372 caption = _('GnuPG passphrase prompt'), 1373 default_value = u'' 1374 ) 1375 filename = gmTools.gpg_decrypt_file(filename = filename, passphrase = pwd) 1376 if filename is None: 1377 if self.debug: 1378 return self._escape(_('cannot decrypt data of binary expansion keyword <%s>') % keyword) 1379 return u'' 1380 1381 target_fname = gmTools.get_unique_filename ( 1382 prefix = '%s-converted-' % os.path.splitext(filename)[0], 1383 suffix = target_ext 1384 ) 1385 if not gmMimeLib.convert_file(filename = filename, target_mime = target_mime, target_filename = target_fname): 1386 if self.debug: 1387 return self._escape(_('cannot convert data of binary expansion keyword <%s>') % keyword) 1388 # hoping that the target can cope: 1389 return template % filename 1390 1391 return template % target_fname
1392 #--------------------------------------------------------
1393 - def _get_variant_free_text(self, data=u'tex//'):
1394 # <data>: 1395 # format: tex (only, currently) 1396 # message: shown in input dialog, must not contain "//" or "::" 1397 1398 data_parts = data.split('//') 1399 format = data_parts[0] 1400 if len(data_parts) > 1: 1401 msg = data_parts[1] 1402 else: 1403 msg = _('generic text') 1404 1405 dlg = gmGuiHelpers.cMultilineTextEntryDlg ( 1406 None, 1407 -1, 1408 title = _('Replacing <free_text> placeholder'), 1409 msg = _('Below you can enter free text.\n\n [%s]') % msg 1410 ) 1411 dlg.enable_user_formatting = True 1412 decision = dlg.ShowModal() 1413 1414 if decision != wx.ID_SAVE: 1415 dlg.Destroy() 1416 if self.debug: 1417 return self._escape(_('Text input cancelled by user.')) 1418 return u'' 1419 1420 text = dlg.value.strip() 1421 if dlg.is_user_formatted: 1422 dlg.Destroy() 1423 return text 1424 1425 dlg.Destroy() 1426 1427 # if format in [u'tex', u'latex']: 1428 # return gmTools.tex_escape_string(text = text) 1429 # return text 1430 1431 return self._escape(text)
1432 #--------------------------------------------------------
1433 - def _get_variant_bill(self, data=None):
1434 try: 1435 bill = self.__cache['bill'] 1436 except KeyError: 1437 from Gnumed.wxpython import gmBillingWidgets 1438 bill = gmBillingWidgets.manage_bills(patient = self.pat) 1439 if bill is None: 1440 if self.debug: 1441 return self._escape(_('no bill selected')) 1442 return u'' 1443 self.__cache['bill'] = bill 1444 1445 return data % bill.fields_as_dict(date_format = '%Y %B %d', escape_style = self.__esc_style)
1446 #--------------------------------------------------------
1447 - def _get_variant_bill_item(self, data=None):
1448 try: 1449 bill = self.__cache['bill'] 1450 except KeyError: 1451 from Gnumed.wxpython import gmBillingWidgets 1452 bill = gmBillingWidgets.manage_bills(patient = self.pat) 1453 if bill is None: 1454 if self.debug: 1455 return self._escape(_('no bill selected')) 1456 return u'' 1457 self.__cache['bill'] = bill 1458 1459 return u'\n'.join([ data % i.fields_as_dict(date_format = '%Y %B %d', escape_style = self.__esc_style) for i in bill.bill_items ])
1460 #-------------------------------------------------------- 1461 # internal helpers 1462 #--------------------------------------------------------
1463 - def _escape(self, text=None):
1464 if self.__esc_func is None: 1465 return text 1466 return self.__esc_func(text)
1467 #=====================================================================
1468 -class cMacroPrimitives:
1469 """Functions a macro can legally use. 1470 1471 An instance of this class is passed to the GNUmed scripting 1472 listener. Hence, all actions a macro can legally take must 1473 be defined in this class. Thus we achieve some screening for 1474 security and also thread safety handling. 1475 """ 1476 #-----------------------------------------------------------------
1477 - def __init__(self, personality = None):
1478 if personality is None: 1479 raise gmExceptions.ConstructorError, 'must specify personality' 1480 self.__personality = personality 1481 self.__attached = 0 1482 self._get_source_personality = None 1483 self.__user_done = False 1484 self.__user_answer = 'no answer yet' 1485 self.__pat = gmPerson.gmCurrentPatient() 1486 1487 self.__auth_cookie = str(random.random()) 1488 self.__pat_lock_cookie = str(random.random()) 1489 self.__lock_after_load_cookie = str(random.random()) 1490 1491 _log.info('slave mode personality is [%s]', personality)
1492 #----------------------------------------------------------------- 1493 # public API 1494 #-----------------------------------------------------------------
1495 - def attach(self, personality = None):
1496 if self.__attached: 1497 _log.error('attach with [%s] rejected, already serving a client', personality) 1498 return (0, _('attach rejected, already serving a client')) 1499 if personality != self.__personality: 1500 _log.error('rejecting attach to personality [%s], only servicing [%s]' % (personality, self.__personality)) 1501 return (0, _('attach to personality [%s] rejected') % personality) 1502 self.__attached = 1 1503 self.__auth_cookie = str(random.random()) 1504 return (1, self.__auth_cookie)
1505 #-----------------------------------------------------------------
1506 - def detach(self, auth_cookie=None):
1507 if not self.__attached: 1508 return 1 1509 if auth_cookie != self.__auth_cookie: 1510 _log.error('rejecting detach() with cookie [%s]' % auth_cookie) 1511 return 0 1512 self.__attached = 0 1513 return 1
1514 #-----------------------------------------------------------------
1515 - def force_detach(self):
1516 if not self.__attached: 1517 return 1 1518 self.__user_done = False 1519 # FIXME: use self.__sync_cookie for syncing with user interaction 1520 wx.CallAfter(self._force_detach) 1521 return 1
1522 #-----------------------------------------------------------------
1523 - def version(self):
1524 ver = _cfg.get(option = u'client_version') 1525 return "GNUmed %s, %s $Revision: 1.51 $" % (ver, self.__class__.__name__)
1526 #-----------------------------------------------------------------
1527 - def shutdown_gnumed(self, auth_cookie=None, forced=False):
1528 """Shuts down this client instance.""" 1529 if not self.__attached: 1530 return 0 1531 if auth_cookie != self.__auth_cookie: 1532 _log.error('non-authenticated shutdown_gnumed()') 1533 return 0 1534 wx.CallAfter(self._shutdown_gnumed, forced) 1535 return 1
1536 #-----------------------------------------------------------------
1537 - def raise_gnumed(self, auth_cookie = None):
1538 """Raise ourselves to the top of the desktop.""" 1539 if not self.__attached: 1540 return 0 1541 if auth_cookie != self.__auth_cookie: 1542 _log.error('non-authenticated raise_gnumed()') 1543 return 0 1544 return "cMacroPrimitives.raise_gnumed() not implemented"
1545 #-----------------------------------------------------------------
1546 - def get_loaded_plugins(self, auth_cookie = None):
1547 if not self.__attached: 1548 return 0 1549 if auth_cookie != self.__auth_cookie: 1550 _log.error('non-authenticated get_loaded_plugins()') 1551 return 0 1552 gb = gmGuiBroker.GuiBroker() 1553 return gb['horstspace.notebook.gui'].keys()
1554 #-----------------------------------------------------------------
1555 - def raise_notebook_plugin(self, auth_cookie = None, a_plugin = None):
1556 """Raise a notebook plugin within GNUmed.""" 1557 if not self.__attached: 1558 return 0 1559 if auth_cookie != self.__auth_cookie: 1560 _log.error('non-authenticated raise_notebook_plugin()') 1561 return 0 1562 # FIXME: use semaphore 1563 wx.CallAfter(gmPlugin.raise_notebook_plugin, a_plugin) 1564 return 1
1565 #-----------------------------------------------------------------
1566 - def load_patient_from_external_source(self, auth_cookie = None):
1567 """Load external patient, perhaps create it. 1568 1569 Callers must use get_user_answer() to get status information. 1570 It is unsafe to proceed without knowing the completion state as 1571 the controlled client may be waiting for user input from a 1572 patient selection list. 1573 """ 1574 if not self.__attached: 1575 return (0, _('request rejected, you are not attach()ed')) 1576 if auth_cookie != self.__auth_cookie: 1577 _log.error('non-authenticated load_patient_from_external_source()') 1578 return (0, _('rejected load_patient_from_external_source(), not authenticated')) 1579 if self.__pat.locked: 1580 _log.error('patient is locked, cannot load from external source') 1581 return (0, _('current patient is locked')) 1582 self.__user_done = False 1583 wx.CallAfter(self._load_patient_from_external_source) 1584 self.__lock_after_load_cookie = str(random.random()) 1585 return (1, self.__lock_after_load_cookie)
1586 #-----------------------------------------------------------------
1587 - def lock_loaded_patient(self, auth_cookie = None, lock_after_load_cookie = None):
1588 if not self.__attached: 1589 return (0, _('request rejected, you are not attach()ed')) 1590 if auth_cookie != self.__auth_cookie: 1591 _log.error('non-authenticated lock_load_patient()') 1592 return (0, _('rejected lock_load_patient(), not authenticated')) 1593 # FIXME: ask user what to do about wrong cookie 1594 if lock_after_load_cookie != self.__lock_after_load_cookie: 1595 _log.warning('patient lock-after-load request rejected due to wrong cookie [%s]' % lock_after_load_cookie) 1596 return (0, 'patient lock-after-load request rejected, wrong cookie provided') 1597 self.__pat.locked = True 1598 self.__pat_lock_cookie = str(random.random()) 1599 return (1, self.__pat_lock_cookie)
1600 #-----------------------------------------------------------------
1601 - def lock_into_patient(self, auth_cookie = None, search_params = None):
1602 if not self.__attached: 1603 return (0, _('request rejected, you are not attach()ed')) 1604 if auth_cookie != self.__auth_cookie: 1605 _log.error('non-authenticated lock_into_patient()') 1606 return (0, _('rejected lock_into_patient(), not authenticated')) 1607 if self.__pat.locked: 1608 _log.error('patient is already locked') 1609 return (0, _('already locked into a patient')) 1610 searcher = gmPersonSearch.cPatientSearcher_SQL() 1611 if type(search_params) == types.DictType: 1612 idents = searcher.get_identities(search_dict=search_params) 1613 raise StandardError("must use dto, not search_dict") 1614 else: 1615 idents = searcher.get_identities(search_term=search_params) 1616 if idents is None: 1617 return (0, _('error searching for patient with [%s]/%s') % (search_term, search_dict)) 1618 if len(idents) == 0: 1619 return (0, _('no patient found for [%s]/%s') % (search_term, search_dict)) 1620 # FIXME: let user select patient 1621 if len(idents) > 1: 1622 return (0, _('several matching patients found for [%s]/%s') % (search_term, search_dict)) 1623 if not gmPatSearchWidgets.set_active_patient(patient = idents[0]): 1624 return (0, _('cannot activate patient [%s] (%s/%s)') % (str(idents[0]), search_term, search_dict)) 1625 self.__pat.locked = True 1626 self.__pat_lock_cookie = str(random.random()) 1627 return (1, self.__pat_lock_cookie)
1628 #-----------------------------------------------------------------
1629 - def unlock_patient(self, auth_cookie = None, unlock_cookie = None):
1630 if not self.__attached: 1631 return (0, _('request rejected, you are not attach()ed')) 1632 if auth_cookie != self.__auth_cookie: 1633 _log.error('non-authenticated unlock_patient()') 1634 return (0, _('rejected unlock_patient, not authenticated')) 1635 # we ain't locked anyways, so succeed 1636 if not self.__pat.locked: 1637 return (1, '') 1638 # FIXME: ask user what to do about wrong cookie 1639 if unlock_cookie != self.__pat_lock_cookie: 1640 _log.warning('patient unlock request rejected due to wrong cookie [%s]' % unlock_cookie) 1641 return (0, 'patient unlock request rejected, wrong cookie provided') 1642 self.__pat.locked = False 1643 return (1, '')
1644 #-----------------------------------------------------------------
1645 - def assume_staff_identity(self, auth_cookie = None, staff_name = "Dr.Jekyll", staff_creds = None):
1646 if not self.__attached: 1647 return 0 1648 if auth_cookie != self.__auth_cookie: 1649 _log.error('non-authenticated select_identity()') 1650 return 0 1651 return "cMacroPrimitives.assume_staff_identity() not implemented"
1652 #-----------------------------------------------------------------
1653 - def get_user_answer(self):
1654 if not self.__user_done: 1655 return (0, 'still waiting') 1656 self.__user_done = False 1657 return (1, self.__user_answer)
1658 #----------------------------------------------------------------- 1659 # internal API 1660 #-----------------------------------------------------------------
1661 - def _force_detach(self):
1662 msg = _( 1663 'Someone tries to forcibly break the existing\n' 1664 'controlling connection. This may or may not\n' 1665 'have legitimate reasons.\n\n' 1666 'Do you want to allow breaking the connection ?' 1667 ) 1668 can_break_conn = gmGuiHelpers.gm_show_question ( 1669 aMessage = msg, 1670 aTitle = _('forced detach attempt') 1671 ) 1672 if can_break_conn: 1673 self.__user_answer = 1 1674 else: 1675 self.__user_answer = 0 1676 self.__user_done = True 1677 if can_break_conn: 1678 self.__pat.locked = False 1679 self.__attached = 0 1680 return 1
1681 #-----------------------------------------------------------------
1682 - def _shutdown_gnumed(self, forced=False):
1683 top_win = wx.GetApp().GetTopWindow() 1684 if forced: 1685 top_win.Destroy() 1686 else: 1687 top_win.Close()
1688 #-----------------------------------------------------------------
1690 patient = gmPatSearchWidgets.get_person_from_external_sources(search_immediately = True, activate_immediately = True) 1691 if patient is not None: 1692 self.__user_answer = 1 1693 else: 1694 self.__user_answer = 0 1695 self.__user_done = True 1696 return 1
1697 #===================================================================== 1698 # main 1699 #===================================================================== 1700 if __name__ == '__main__': 1701 1702 if len(sys.argv) < 2: 1703 sys.exit() 1704 1705 if sys.argv[1] != 'test': 1706 sys.exit() 1707 1708 gmI18N.activate_locale() 1709 gmI18N.install_domain() 1710 1711 #--------------------------------------------------------
1712 - def test_placeholders():
1713 handler = gmPlaceholderHandler() 1714 handler.debug = True 1715 1716 for placeholder in ['a', 'b']: 1717 print handler[placeholder] 1718 1719 pat = gmPersonSearch.ask_for_patient() 1720 if pat is None: 1721 return 1722 1723 gmPatSearchWidgets.set_active_patient(patient = pat) 1724 1725 print 'DOB (YYYY-MM-DD):', handler['date_of_birth::%Y-%m-%d'] 1726 1727 app = wx.PyWidgetTester(size = (200, 50)) 1728 for placeholder in known_placeholders: 1729 print placeholder, "=", handler[placeholder] 1730 1731 ph = 'progress_notes::ap' 1732 print '%s: %s' % (ph, handler[ph])
1733 #--------------------------------------------------------
1734 - def test_new_variant_placeholders():
1735 1736 tests = [ 1737 # should work: 1738 '$<lastname>$', 1739 '$<lastname::::3>$', 1740 '$<name::%(title)s %(firstnames)s%(preferred)s%(lastnames)s>$', 1741 1742 # should fail: 1743 'lastname', 1744 '$<lastname', 1745 '$<lastname::', 1746 '$<lastname::>$', 1747 '$<lastname::abc>$', 1748 '$<lastname::abc::>$', 1749 '$<lastname::abc::3>$', 1750 '$<lastname::abc::xyz>$', 1751 '$<lastname::::>$', 1752 '$<lastname::::xyz>$', 1753 1754 '$<date_of_birth::%Y-%m-%d>$', 1755 '$<date_of_birth::%Y-%m-%d::3>$', 1756 '$<date_of_birth::%Y-%m-%d::>$', 1757 1758 # should work: 1759 '$<adr_location::home::35>$', 1760 '$<gender_mapper::male//female//other::5>$', 1761 '$<current_meds::==> %(brand)s %(preparation)s (%(substance)s) <==\n::50>$', 1762 '$<allergy_list::%(descriptor)s, >$', 1763 '$<current_meds_table::latex//by-brand>$' 1764 1765 # 'firstname', 1766 # 'title', 1767 # 'date_of_birth', 1768 # 'progress_notes', 1769 # 'soap', 1770 # 'soap_s', 1771 # 'soap_o', 1772 # 'soap_a', 1773 # 'soap_p', 1774 1775 # 'soap', 1776 # 'progress_notes', 1777 # 'date_of_birth' 1778 ] 1779 1780 # tests = [ 1781 # '$<latest_vaccs_table::latex>$' 1782 # ] 1783 1784 pat = gmPersonSearch.ask_for_patient() 1785 if pat is None: 1786 return 1787 1788 gmPatSearchWidgets.set_active_patient(patient = pat) 1789 1790 handler = gmPlaceholderHandler() 1791 handler.debug = True 1792 1793 for placeholder in tests: 1794 print placeholder, "=>", handler[placeholder] 1795 print "--------------" 1796 raw_input()
1797 1798 # print 'DOB (YYYY-MM-DD):', handler['date_of_birth::%Y-%m-%d'] 1799 1800 # app = wx.PyWidgetTester(size = (200, 50)) 1801 # for placeholder in known_placeholders: 1802 # print placeholder, "=", handler[placeholder] 1803 1804 # ph = 'progress_notes::ap' 1805 # print '%s: %s' % (ph, handler[ph]) 1806 1807 #--------------------------------------------------------
1808 - def test_scripting():
1809 from Gnumed.pycommon import gmScriptingListener 1810 import xmlrpclib 1811 listener = gmScriptingListener.cScriptingListener(macro_executor = cMacroPrimitives(personality='unit test'), port=9999) 1812 1813 s = xmlrpclib.ServerProxy('http://localhost:9999') 1814 print "should fail:", s.attach() 1815 print "should fail:", s.attach('wrong cookie') 1816 print "should work:", s.version() 1817 print "should fail:", s.raise_gnumed() 1818 print "should fail:", s.raise_notebook_plugin('test plugin') 1819 print "should fail:", s.lock_into_patient('kirk, james') 1820 print "should fail:", s.unlock_patient() 1821 status, conn_auth = s.attach('unit test') 1822 print "should work:", status, conn_auth 1823 print "should work:", s.version() 1824 print "should work:", s.raise_gnumed(conn_auth) 1825 status, pat_auth = s.lock_into_patient(conn_auth, 'kirk, james') 1826 print "should work:", status, pat_auth 1827 print "should fail:", s.unlock_patient(conn_auth, 'bogus patient unlock cookie') 1828 print "should work", s.unlock_patient(conn_auth, pat_auth) 1829 data = {'firstname': 'jame', 'lastnames': 'Kirk', 'gender': 'm'} 1830 status, pat_auth = s.lock_into_patient(conn_auth, data) 1831 print "should work:", status, pat_auth 1832 print "should work", s.unlock_patient(conn_auth, pat_auth) 1833 print s.detach('bogus detach cookie') 1834 print s.detach(conn_auth) 1835 del s 1836 1837 listener.shutdown()
1838 #--------------------------------------------------------
1839 - def test_placeholder_regex():
1840 1841 import re as regex 1842 1843 tests = [ 1844 ' $<lastname>$ ', 1845 ' $<lastname::::3>$ ', 1846 1847 # should fail: 1848 '$<date_of_birth::%Y-%m-%d>$', 1849 '$<date_of_birth::%Y-%m-%d::3>$', 1850 '$<date_of_birth::%Y-%m-%d::>$', 1851 1852 '$<adr_location::home::35>$', 1853 '$<gender_mapper::male//female//other::5>$', 1854 '$<current_meds::==> %(brand)s %(preparation)s (%(substance)s) <==\\n::50>$', 1855 '$<allergy_list::%(descriptor)s, >$', 1856 1857 '\\noindent Patient: $<lastname>$, $<firstname>$', 1858 '$<allergies::%(descriptor)s & %(l10n_type)s & {\\footnotesize %(reaction)s} \tabularnewline \hline >$', 1859 '$<current_meds:: \item[%(substance)s] {\\footnotesize (%(brand)s)} %(preparation)s %(amount)s%(unit)s: %(schedule)s >$' 1860 ] 1861 1862 tests = [ 1863 1864 'junk $<lastname::::3>$ junk', 1865 'junk $<lastname::abc::3>$ junk', 1866 'junk $<lastname::abc>$ junk', 1867 'junk $<lastname>$ junk', 1868 1869 'junk $<lastname>$ junk $<firstname>$ junk', 1870 'junk $<lastname::abc>$ junk $<fiststname::abc>$ junk', 1871 'junk $<lastname::abc::3>$ junk $<firstname::abc::3>$ junk', 1872 'junk $<lastname::::3>$ junk $<firstname::::3>$ junk' 1873 1874 ] 1875 1876 print "testing placeholder regex:", default_placeholder_regex 1877 print "" 1878 1879 for t in tests: 1880 print 'line: "%s"' % t 1881 print "placeholders:" 1882 for p in regex.findall(default_placeholder_regex, t, regex.IGNORECASE): 1883 print ' => "%s"' % p 1884 print " "
1885 #--------------------------------------------------------
1886 - def test_placeholder():
1887 1888 phs = [ 1889 #u'emr_journal::soapu //%(clin_when)s %(modified_by)s %(soap_cat)s %(narrative)s//1000 days::', 1890 #u'free_text::tex//placeholder test::9999', 1891 #u'soap_for_encounters:://::9999', 1892 #u'soap_p', 1893 #u'encounter_list::%(started)s: %(assessment_of_encounter)s::30', 1894 #u'patient_comm::homephone::1234', 1895 #u'$<patient_address::work::1234>$', 1896 #u'adr_region::home::1234', 1897 #u'adr_country::fehlt::1234', 1898 #u'adr_subunit::fehlt::1234', 1899 #u'adr_suburb::fehlt-auch::1234', 1900 #u'external_id::Starfleet Serial Number//Star Fleet Central Staff Office::1234', 1901 #u'primary_praxis_provider', 1902 #u'current_provider', 1903 #u'current_provider_external_id::Starfleet Serial Number//Star Fleet Central Staff Office::1234', 1904 #u'current_provider_external_id::LANR//LÄK::1234' 1905 #u'primary_praxis_provider_external_id::LANR//LÄK::1234' 1906 #u'form_name_long::::1234', 1907 #u'form_name_long::::5', 1908 #u'form_name_long::::', 1909 #u'form_version::::5', 1910 #u'$<current_meds::\item %(brand)s %(preparation)s (%(substance)s) from %(started)s for %(duration)s as %(schedule)s until %(discontinued)s\\n::250>$', 1911 #u'$<vaccination_history::%(date_given)s: %(vaccine)s [%(batch_no)s] %(l10n_indications)s::250>$', 1912 #u'$<date_of_birth::%Y %B %d::20>$', 1913 #u'$<patient_tags::Tag "%(l10n_description)s": %(comment)s//\\n- ::250>$', 1914 #u'$<PHX::%(description)s\n side: %(laterality)s, active: %(is_active)s, relevant: %(clinically_relevant)s, caused death: %(is_cause_of_death)s//\n//%Y %B %d//latex::250>$', 1915 #u'$<patient_photo::\includegraphics[width=60mm]{%s}//image/png//.png::250>$', 1916 #u'$<data_snippet::binary_test_snippet//path=<%s>//image/png//.png::250>$', 1917 #u'$<data_snippet::autograph-LMcC//path=<%s>//image/jpg//.jpg::250>$', 1918 #u'$<current_meds::%s ($<lastname::::50>$)//select::>$', 1919 #u'$<current_meds::%s//select::>$', 1920 #u'$<soap_by_issue::soapu //%Y %b %d//%s::>$', 1921 #u'$<soap_by_episode::soapu //%Y %b %d//%s::>$', 1922 #u'$<documents::select//description//document %(clin_when)s: %(l10n_type)s// file: %(fullpath)s (<some path>/%(name)s)//~/gnumed/export/::>$', 1923 #u'$<soap::soapu //%s::9999>$', 1924 #u'$<soap::soapu //%(soap_cat)s: %(date)s | %(provider)s | %(narrative)s::9999>$' 1925 #u'$<test_results:://%c::>$' 1926 u'$<test_results::%(unified_abbrev)s: %(unified_val)s %(val_unit)s//%c::>$' 1927 ] 1928 1929 handler = gmPlaceholderHandler() 1930 handler.debug = True 1931 1932 gmStaff.set_current_provider_to_logged_on_user() 1933 pat = gmPersonSearch.ask_for_patient() 1934 if pat is None: 1935 return 1936 1937 gmPatSearchWidgets.set_active_patient(patient = pat) 1938 1939 app = wx.PyWidgetTester(size = (200, 50)) 1940 #handler.set_placeholder('form_name_long', 'ein Testformular') 1941 for ph in phs: 1942 print ph 1943 print "result:" 1944 print '%s' % handler[ph]
1945 #handler.unset_placeholder('form_name_long') 1946 #--------------------------------------------------------
1947 - def test():
1948 pat = gmPersonSearch.ask_for_patient() 1949 if pat is None: 1950 sys.exit() 1951 gmPerson.set_active_patient(patient = pat) 1952 from Gnumed.wxpython import gmMedicationWidgets 1953 gmMedicationWidgets.manage_substance_intakes()
1954 #--------------------------------------------------------
1955 - def test_show_phs():
1956 show_placeholders()
1957 #-------------------------------------------------------- 1958 1959 #test_placeholders() 1960 #test_new_variant_placeholders() 1961 #test_scripting() 1962 #test_placeholder_regex() 1963 #test() 1964 test_placeholder() 1965 #test_show_phs() 1966 1967 #===================================================================== 1968