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