Package Gnumed :: Package business :: Module gmExportArea
[frames] | no frames]

Source Code for Module Gnumed.business.gmExportArea

  1  """GNUmed export area 
  2   
  3  Think shopping cart in a web shop. 
  4   
  5  This is where you want to put documents for further 
  6  processing by you or someone else, like your secretary. 
  7  """ 
  8  #============================================================ 
  9  __license__ = "GPL v2 or later" 
 10  __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>" 
 11   
 12   
 13  import sys 
 14  import logging 
 15  import shutil 
 16  import os 
 17  import io 
 18   
 19   
 20  if __name__ == '__main__': 
 21          sys.path.insert(0, '../../') 
 22          from Gnumed.pycommon import gmI18N 
 23          gmI18N.activate_locale() 
 24          gmI18N.install_domain() 
 25  from Gnumed.pycommon import gmTools 
 26  from Gnumed.pycommon import gmBusinessDBObject 
 27  from Gnumed.pycommon import gmPG2 
 28  from Gnumed.pycommon import gmMimeLib 
 29  from Gnumed.pycommon import gmDateTime 
 30  from Gnumed.pycommon import gmCfg2 
 31   
 32  from Gnumed.business import gmDocuments 
 33  from Gnumed.business import gmKeywordExpansion 
 34   
 35   
 36  _log = logging.getLogger('gm.exp_area') 
 37   
 38  PRINT_JOB_DESIGNATION = 'print' 
 39   
 40  #============================================================ 
 41  # export area item handling 
 42  #------------------------------------------------------------ 
 43  _SQL_get_export_items = "SELECT * FROM clin.v_export_items WHERE %s" 
 44   
45 -class cExportItem(gmBusinessDBObject.cBusinessDBObject):
46 """Represents an item in the export area table""" 47 48 _cmd_fetch_payload = _SQL_get_export_items % "pk_export_item = %s" 49 _cmds_store_payload = [ 50 """UPDATE clin.export_item SET 51 fk_identity = %(pk_identity)s, 52 created_by = gm.nullify_empty_string(%(created_by)s), 53 created_when = %(created_when)s, 54 designation = gm.nullify_empty_string(%(designation)s), 55 description = gm.nullify_empty_string(%(description)s), 56 fk_doc_obj = %(pk_doc_obj)s, 57 data = CASE 58 WHEN %(pk_doc_obj)s IS NULL THEN coalesce(data, 'to be replaced by real data') 59 ELSE NULL 60 END, 61 filename = CASE 62 WHEN %(pk_doc_obj)s IS NULL THEN gm.nullify_empty_string(%(filename)s) 63 ELSE NULL 64 END 65 WHERE 66 pk = %(pk_export_item)s 67 AND 68 xmin = %(xmin_export_item)s 69 """, 70 _SQL_get_export_items % 'pk_export_item = %(pk_export_item)s' 71 ] 72 _updatable_fields = [ 73 'pk_identity', 74 'created_when', 75 'designation', 76 'description', 77 'pk_doc_obj', 78 'filename' 79 ] 80 #--------------------------------------------------------
81 - def __init__(self, aPK_obj=None, row=None, link_obj=None):
82 super(cExportItem, self).__init__(aPK_obj = aPK_obj, row = row, link_obj = link_obj) 83 # force auto-healing if need be 84 if self._payload[self._idx['pk_identity_raw_needs_update']]: 85 _log.warning ( 86 'auto-healing export item [%s] from identity [%s] to [%s] because of document part [%s] seems necessary', 87 self._payload[self._idx['pk_export_item']], 88 self._payload[self._idx['pk_identity_raw']], 89 self._payload[self._idx['pk_identity']], 90 self._payload[self._idx['pk_doc_obj']] 91 ) 92 if self._payload[self._idx['pk_doc_obj']] is None: 93 _log.error('however, .fk_doc_obj is NULL, which should not happen, leaving things alone for manual inspection') 94 return 95 # only flag ourselves as modified, do not actually 96 # modify any values, better safe than sorry 97 self._is_modified = True 98 self.save() 99 self.refetch_payload(ignore_changes = False, link_obj = link_obj)
100 101 #-------------------------------------------------------- 102 # def format(self): 103 # return u'%s' % self 104 #--------------------------------------------------------
105 - def update_data_from_file(self, filename=None):
106 # sanity check 107 if not (os.access(filename, os.R_OK) and os.path.isfile(filename)): 108 _log.error('[%s] is not a readable file' % filename) 109 return False 110 111 cmd = """ 112 UPDATE clin.export_item SET 113 data = %(data)s::bytea, 114 fk_doc_obj = NULL, 115 filename = gm.nullify_empty_string(%(fname)s) 116 WHERE pk = %(pk)s""" 117 args = {'pk': self.pk_obj, 'fname': filename} 118 if not gmPG2.file2bytea(query = cmd, filename = filename, args = args): 119 return False 120 121 # must update XMIN now ... 122 self.refetch_payload() 123 return True
124 125 #--------------------------------------------------------
126 - def save_to_file(self, aChunkSize=0, filename=None, directory=None):
127 128 # data linked from archive 129 if self._payload[self._idx['pk_doc_obj']] is not None: 130 part = self.document_part 131 if filename is None: 132 filename = part.get_useful_filename ( 133 make_unique = False, 134 directory = directory, 135 include_gnumed_tag = False, 136 date_before_type = True, 137 name_first = False 138 ) 139 return part.save_to_file ( 140 aChunkSize = aChunkSize, 141 filename = filename, 142 ignore_conversion_problems = True, 143 adjust_extension = True 144 ) 145 146 # data in export area table 147 if filename is None: 148 filename = self.get_useful_filename(directory = directory) 149 150 success = gmPG2.bytea2file ( 151 data_query = { 152 'cmd': 'SELECT substring(data from %(start)s for %(size)s) FROM clin.export_item WHERE pk = %(pk)s', 153 'args': {'pk': self.pk_obj} 154 }, 155 filename = filename, 156 chunk_size = aChunkSize, 157 data_size = self._payload[self._idx['size']] 158 ) 159 if not success: 160 return None 161 162 if filename.endswith('.dat'): 163 return gmMimeLib.adjust_extension_by_mimetype(filename) 164 165 return filename
166 167 #--------------------------------------------------------
168 - def display_via_mime(self, chunksize=0, block=None):
169 170 if self._payload[self._idx['pk_doc_obj']] is not None: 171 return self.document_part.display_via_mime(chunksize = chunksize, block = block) 172 173 fname = self.save_to_file(aChunkSize = chunksize) 174 if fname is None: 175 return False, '' 176 177 success, msg = gmMimeLib.call_viewer_on_file(fname, block = block) 178 if not success: 179 return False, msg 180 181 return True, ''
182 183 #--------------------------------------------------------
184 - def get_useful_filename(self, patient=None, directory=None):
185 patient_part = '' 186 if patient is not None: 187 patient_part = '-%s' % patient.subdir_name 188 189 # preserve original filename extension if available 190 suffix = '.dat' 191 if self._payload[self._idx['filename']] is not None: 192 tmp, suffix = os.path.splitext ( 193 gmTools.fname_sanitize(self._payload[self._idx['filename']]).lower() 194 ) 195 if suffix == '': 196 suffix = '.dat' 197 198 fname = gmTools.get_unique_filename ( 199 prefix = 'gm-export_item%s-' % patient_part, 200 suffix = suffix, 201 tmp_dir = directory 202 ) 203 204 return fname
205 206 #-------------------------------------------------------- 207 # properties 208 #--------------------------------------------------------
209 - def _get_doc_part(self):
210 if self._payload[self._idx['pk_doc_obj']] is None: 211 return None 212 return gmDocuments.cDocumentPart(aPK_obj = self._payload[self._idx['pk_doc_obj']])
213 214 document_part = property(_get_doc_part, lambda x:x) 215 216 #--------------------------------------------------------
217 - def _get_is_print_job(self):
218 return self._payload[self._idx['designation']] == PRINT_JOB_DESIGNATION
219
220 - def _set_is_print_job(self, is_print_job):
221 desig = gmTools.bool2subst(is_print_job, PRINT_JOB_DESIGNATION, None, None) 222 if self._payload[self._idx['designation']] == desig: 223 return 224 self['designation'] = desig 225 self.save()
226 227 is_print_job = property(_get_is_print_job, _set_is_print_job)
228 229 #------------------------------------------------------------
230 -def get_export_items(order_by=None, pk_identity=None, designation=None):
231 232 args = { 233 'pat': pk_identity, 234 'desig': gmTools.coalesce(designation, PRINT_JOB_DESIGNATION) 235 } 236 where_parts = [] 237 if pk_identity is not None: 238 where_parts.append('pk_identity = %(pat)s') 239 # note that invalidly linked items will be 240 # auto-healed when instantiated 241 if designation is None: 242 where_parts.append("designation IS DISTINCT FROM %(desig)s") 243 else: 244 where_parts.append('designation = %(desig)s') 245 246 if order_by is None: 247 order_by = '' 248 else: 249 order_by = ' ORDER BY %s' % order_by 250 251 cmd = (_SQL_get_export_items % ' AND '.join(where_parts)) + order_by 252 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 253 254 return [ cExportItem(row = {'data': r, 'idx': idx, 'pk_field': 'pk_export_item'}) for r in rows ]
255 256 #------------------------------------------------------------
257 -def get_print_jobs(order_by=None, pk_identity=None):
258 return get_export_items(order_by = order_by, pk_identity = pk_identity, designation = PRINT_JOB_DESIGNATION)
259 260 #------------------------------------------------------------
261 -def create_export_item(description=None, pk_identity=None, pk_doc_obj=None, filename=None):
262 263 args = { 264 'desc': description, 265 'pk_obj': pk_doc_obj, 266 'pk_pat': pk_identity, 267 'fname': filename 268 } 269 cmd = """ 270 INSERT INTO clin.export_item ( 271 description, 272 fk_doc_obj, 273 fk_identity, 274 data, 275 filename 276 ) VALUES ( 277 gm.nullify_empty_string(%(desc)s), 278 %(pk_obj)s, 279 %(pk_pat)s, 280 (CASE 281 WHEN %(pk_obj)s IS NULL THEN %(fname)s::bytea 282 ELSE NULL::bytea 283 END), 284 (CASE 285 WHEN %(pk_obj)s IS NULL THEN gm.nullify_empty_string(%(fname)s) 286 ELSE NULL 287 END) 288 ) 289 RETURNING pk 290 """ 291 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True, get_col_idx = False) 292 293 return cExportItem(aPK_obj = rows[0]['pk'])
294 295 #------------------------------------------------------------
296 -def delete_export_item(pk_export_item=None):
297 args = {'pk': pk_export_item} 298 cmd = "DELETE FROM clin.export_item WHERE pk = %(pk)s" 299 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 300 return True
301 302 #============================================================ 303 _html_start = """<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 304 "http://www.w3.org/TR/html4/loose.dtd"> 305 <html> 306 <head> 307 <meta http-equiv="content-type" content="text/html; charset=UTF-8"> 308 <link rel="icon" type="image/x-icon" href="gnumed.ico"> 309 <title>%(html_title_header)s %(html_title_patient)s</title> 310 </head> 311 <body> 312 313 <h1>%(title)s</h1> 314 315 <p> 316 %(pat_name)s<br> 317 %(pat_dob)s 318 </p> 319 320 <p><img src="%(mugshot_url)s" alt="%(mugshot_alt)s" title="%(mugshot_title)s" width="200" border="2"></p> 321 322 <h2>%(docs_title)s</h2> 323 324 <ul> 325 <li><a href="./">%(browse_root)s</a></li> 326 <li><a href="documents/">%(browse_docs)s</a></li> 327 %(browse_dicomdir)s 328 %(run_dicom_viewer)s 329 </ul> 330 331 <ul> 332 """ 333 334 # <li><a href="documents/filename-1.ext">document 1 description</a></li> 335 336 _html_list_item = """ <li><a href="documents/%s">%s</a></li> 337 """ 338 339 _html_end = """ 340 </ul> 341 342 <p> 343 %(date)s<br> 344 %(branch)s @ %(praxis)s 345 %(adr)s 346 </p> 347 348 (<a href="http://www.gnumed.de">GNUmed</a> version %(gm_ver)s) 349 350 </body> 351 </html> 352 """ 353 354 355 _autorun_inf = ( # needs \r\n for Windows 356 '[AutoRun.Amd64]\r\n' # 64 bit 357 'label=%(label)s\r\n' # patient name/DOB 358 'shellexecute=index.html\r\n' 359 'action=%(action)s\r\n' # % _('Browse patient data') 360 '%(icon)s\r\n' # "icon=gnumed.ico" or "" 361 'UseAutoPlay=1\r\n' 362 '\r\n' 363 '[AutoRun]\r\n' # 32 bit 364 'label=%(label)s\r\n' # patient name/DOB 365 'shellexecute=index.html\r\n' 366 'action=%(action)s\r\n' # % _('Browse patient data') 367 '%(icon)s\r\n' # "icon=gnumed.ico" or "" 368 'UseAutoPlay=1\r\n' 369 '\r\n' 370 '[Content]\r\n' 371 'PictureFiles=yes\r\n' 372 'VideoFiles=yes\r\n' 373 'MusicFiles=no\r\n' 374 '\r\n' 375 '[IgnoreContentPaths]\r\n' 376 '\documents\r\n' 377 '\r\n' 378 '[unused]\r\n' 379 'open=requires explicit executable\r\n' 380 ) 381 382 383 _cd_inf = ( 384 '[Patient Info]\r\n' # needs \r\n for Windows 385 'PatientName=%s, %s\r\n' 386 'Gender=%s\r\n' 387 'BirthDate=%s\r\n' 388 'CreationDate=%s\r\n' 389 'PID=%s\r\n' 390 'EMR=GNUmed\r\n' 391 'Version=%s\r\n' 392 '#StudyDate=\r\n' 393 '#VNRInfo=<body part>\r\n' 394 '\r\n' 395 '# name format: lastnames, firstnames\r\n' 396 '# date format: YYYY-MM-DD (ISO 8601)\r\n' 397 '# gender format: %s\r\n' 398 ) 399 400 _README = """This is a patient data bundle created by the GNUmed Electronic Medical Record. 401 402 Patient: %s 403 404 Please display <index.html> to browse patient data. 405 406 Individual documents are stored under 407 408 ./documents/ 409 """ 410 411 #------------------------------------------------------------
412 -class cExportArea(object):
413
414 - def __init__(self, pk_identity):
415 self.__pk_identity = pk_identity
416 417 #--------------------------------------------------------
418 - def add_form(self, form=None, designation=None):
419 420 if len(form.final_output_filenames) == 0: 421 return True 422 423 items = [] 424 for fname in form.final_output_filenames: 425 item = self.add_file(filename = fname) 426 if item is None: 427 for prev_item in items: 428 delete_export_item(pk_export_item = prev_item['pk_export_item']) 429 return False 430 items.append(item) 431 item['description'] = _('form: %s %s (%s)') % (form.template['name_long'], form.template['external_version'], fname) 432 item['designation'] = designation 433 item.save() 434 435 return True
436 #--------------------------------------------------------
437 - def add_forms(self, forms=None, designation=None):
438 all_ok = True 439 for form in forms: 440 all_ok = all_ok and self.add_form(form = form, designation = designation) 441 442 return all_ok
443 #--------------------------------------------------------
444 - def add_file(self, filename=None, hint=None):
445 try: 446 open(filename).close() 447 except Exception: 448 _log.exception('cannot open file <%s>', filename) 449 return None 450 451 file_md5 = gmTools.file2md5(filename = filename, return_hex = True) 452 existing_item = self.md5_exists(md5 = file_md5, include_document_parts = False) 453 if existing_item is not None: 454 _log.debug('md5 match (%s): %s already in export area', file_md5, filename) 455 return existing_item 456 457 path, basename = os.path.split(filename) 458 item = create_export_item ( 459 description = '%s: %s (%s/)' % ( 460 gmTools.coalesce(hint, _('file'), '%s'), 461 basename, 462 path 463 ), 464 pk_identity = self.__pk_identity, 465 filename = filename 466 ) 467 468 if item.update_data_from_file(filename = filename): 469 return item 470 471 delete_export_item(pk_export_item = item['pk_export_item']) 472 return None
473 474 #--------------------------------------------------------
475 - def add_files(self, filenames=None, hint=None):
476 all_ok = True 477 for fname in filenames: 478 all_ok = all_ok and (self.add_file(filename = fname, hint = hint) is not None) 479 480 return all_ok
481 482 #--------------------------------------------------------
483 - def add_documents(self, documents=None):
484 for doc in documents: 485 doc_tag = _('%s (%s)%s') % ( 486 doc['l10n_type'], 487 gmDateTime.pydt_strftime(doc['clin_when'], '%Y %b %d'), 488 gmTools.coalesce(doc['comment'], '', ' "%s"') 489 ) 490 for obj in doc.parts: 491 if self.document_part_item_exists(pk_part = obj['pk_obj']): 492 continue 493 f_ext = '' 494 if obj['filename'] is not None: 495 f_ext = os.path.splitext(obj['filename'])[1].strip('.').strip() 496 if f_ext != '': 497 f_ext = ' .' + f_ext.upper() 498 obj_tag = _('part %s (%s%s)%s') % ( 499 obj['seq_idx'], 500 gmTools.size2str(obj['size']), 501 f_ext, 502 gmTools.coalesce(obj['obj_comment'], '', ' "%s"') 503 ) 504 create_export_item ( 505 description = '%s - %s' % (doc_tag, obj_tag), 506 pk_doc_obj = obj['pk_obj'] 507 )
508 509 #--------------------------------------------------------
510 - def document_part_item_exists(self, pk_part=None):
511 cmd = "SELECT EXISTS (SELECT 1 FROM clin.export_item WHERE fk_doc_obj = %(pk_obj)s)" 512 args = {'pk_obj': pk_part} 513 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 514 return rows[0][0]
515 516 #--------------------------------------------------------
517 - def md5_exists(self, md5=None, include_document_parts=False):
518 where_parts = [ 519 'pk_identity = %(pat)s', 520 'md5_sum = %(md5)s' 521 ] 522 args = { 523 'pat': self.__pk_identity, 524 'md5': md5 525 } 526 527 if not include_document_parts: 528 where_parts.append('pk_doc_obj IS NULL') 529 530 cmd = _SQL_get_export_items % ' AND '.join(where_parts) 531 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 532 533 if len(rows) == 0: 534 return None 535 536 r = rows[0] 537 return cExportItem(row = {'data': r, 'idx': idx, 'pk_field': 'pk_export_item'})
538 539 #--------------------------------------------------------
540 - def dump_items_to_disk(self, base_dir=None, items=None):
541 if items is None: 542 items = self.items 543 544 if len(items) == 0: 545 return None 546 547 if base_dir is None: 548 from Gnumed.business.gmPerson import cPatient 549 pat = cPatient(aPK_obj = self.__pk_identity) 550 base_dir = gmTools.mk_sandbox_dir(prefix = 'exp-%s-' % pat.subdir_name) 551 _log.debug('dumping export items to: %s', base_dir) 552 553 gmTools.mkdir(base_dir) 554 for item in items: 555 item.save_to_file(directory = base_dir) 556 return base_dir
557 558 #--------------------------------------------------------
559 - def export(self, base_dir=None, items=None, expand_compressed=False):
560 561 if items is None: 562 items = self.items 563 564 if len(items) == 0: 565 return None 566 567 media_base_dir = base_dir 568 569 from Gnumed.business.gmPerson import cPatient 570 pat = cPatient(aPK_obj = self.__pk_identity) 571 if media_base_dir is None: 572 media_base_dir = gmTools.mk_sandbox_dir(prefix = 'exp-%s-' % pat.subdir_name) 573 _log.debug('patient media base dir: %s', media_base_dir) 574 575 doc_dir = os.path.join(media_base_dir, r'documents') 576 if os.path.isdir(doc_dir): 577 index_existing_docs = True 578 else: 579 index_existing_docs = False 580 gmTools.mkdir(doc_dir) 581 582 _html_start_data = { 583 'html_title_header': _('Patient data for'), 584 'html_title_patient': gmTools.html_escape_string(pat.get_description_gender(with_nickname = False) + ', ' + _('born') + ' ' + pat.get_formatted_dob('%Y %B %d')), 585 'title': _('Patient data export'), 586 'pat_name': gmTools.html_escape_string(pat.get_description_gender(with_nickname = False)), 587 'pat_dob': gmTools.html_escape_string(_('born') + ' ' + pat.get_formatted_dob('%Y %B %d')), 588 'mugshot_url': 'documents/no-such-file.png', 589 'mugshot_alt': _('no patient photograph available'), 590 'mugshot_title': '', 591 'docs_title': _('Documents'), 592 'browse_root': _('browse storage medium'), 593 'browse_docs': _('browse documents area'), 594 'browse_dicomdir': '', 595 'run_dicom_viewer': '' 596 } 597 598 mugshot = pat.document_folder.latest_mugshot 599 if mugshot is not None: 600 _html_start_data['mugshot_url'] = mugshot.save_to_file(directory = doc_dir, adjust_extension = True) 601 _html_start_data['mugshot_alt'] =_('patient photograph from %s') % gmDateTime.pydt_strftime(mugshot['date_generated'], '%B %Y') 602 _html_start_data['mugshot_title'] = gmDateTime.pydt_strftime(mugshot['date_generated'], '%B %Y') 603 604 if 'DICOMDIR' in os.listdir(media_base_dir): 605 _html_start_data['browse_dicomdir'] = '<li><a href="./DICOMDIR">%s</a></li>' % _('show DICOMDIR file') 606 # copy DWV into target dir 607 dwv_src_dir = os.path.join(gmTools.gmPaths().local_base_dir, 'dwv4export') 608 if not os.path.isdir(dwv_src_dir): 609 dwv_src_dir = os.path.join(gmTools.gmPaths().system_app_data_dir, 'dwv4export') 610 if os.path.isdir(dwv_src_dir): 611 dwv_target_dir = os.path.join(media_base_dir, 'dwv') 612 gmTools.rmdir(dwv_target_dir) 613 try: 614 shutil.copytree(dwv_src_dir, dwv_target_dir) 615 _html_start_data['run_dicom_viewer'] = '<li><a href="./dwv/viewers/mobile-local/index.html">%s</a></li>' % _('run Radiology Images (DICOM) Viewer') 616 except (shutil.Error, OSError): 617 _log.exception('cannot include DWV, skipping') 618 619 # index.html 620 # - header 621 idx_fname = os.path.join(media_base_dir, 'index.html') 622 idx_file = io.open(idx_fname, mode = 'wt', encoding = 'utf8') 623 idx_file.write(_html_start % _html_start_data) 624 # - middle (side effect ! -> exports items into files ...) 625 existing_docs = os.listdir(doc_dir) # get them now, or else we will include the to-be-exported items 626 # - export items 627 for item in items: 628 item_path = item.save_to_file(directory = doc_dir) 629 item_fname = os.path.split(item_path)[1] 630 idx_file.write(_html_list_item % ( 631 item_fname, 632 gmTools.html_escape_string(item['description']) 633 )) 634 # - preexisting documents 635 for doc_fname in existing_docs: 636 idx_file.write(_html_list_item % ( 637 doc_fname, 638 gmTools.html_escape_string(_('other: %s') % doc_fname) 639 )) 640 # - footer 641 _cfg = gmCfg2.gmCfgData() 642 from Gnumed.business.gmPraxis import gmCurrentPraxisBranch 643 prax = gmCurrentPraxisBranch() 644 lines = [] 645 adr = prax.branch.org_unit.address 646 if adr is not None: 647 lines.extend(adr.format()) 648 for comm in prax.branch.org_unit.comm_channels: 649 if comm['is_confidential'] is True: 650 continue 651 lines.append('%s: %s' % ( 652 comm['l10n_comm_type'], 653 comm['url'] 654 )) 655 adr = '' 656 if len(lines) > 0: 657 adr = gmTools.html_escape_string('\n'.join(lines), replace_eol = True, keep_visual_eol = True) 658 _html_end_data = { 659 'branch': gmTools.html_escape_string(prax['branch']), 660 'praxis': gmTools.html_escape_string(prax['praxis']), 661 'date' : gmTools.html_escape_string(gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(), format = '%Y %B %d')), 662 'gm_ver': gmTools.html_escape_string(_cfg.get(option = 'client_version')), 663 #'gm_ver': 'git HEAD', # for testing 664 'adr': adr 665 } 666 idx_file.write(_html_end % _html_end_data) 667 idx_file.close() 668 669 # start.html (just a copy of index.html, really ;-) 670 start_fname = os.path.join(media_base_dir, 'start.html') 671 try: 672 shutil.copy2(idx_fname, start_fname) 673 except Exception: 674 _log.exception('cannot copy %s to %s', idx_fname, start_fname) 675 676 # autorun.inf 677 autorun_dict = {} 678 autorun_dict['label'] = self._compute_autorun_inf_label(pat) 679 autorun_dict['action'] = _('Browse patient data') 680 autorun_dict['icon'] = '' 681 media_icon_kwd = '$$gnumed_patient_media_export_icon' 682 media_icon_kwd_exp = gmKeywordExpansion.get_expansion ( 683 keyword = media_icon_kwd, 684 textual_only = False, 685 binary_only = True 686 ) 687 icon_tmp_file = media_icon_kwd_exp.save_to_file ( 688 target_mime = 'image/x-icon', 689 target_extension = '.ico', 690 ignore_conversion_problems = True 691 ) 692 if icon_tmp_file is None: 693 _log.debug('cannot retrieve <%s>', media_icon_kwd) 694 else: 695 media_icon_fname = os.path.join(media_base_dir, 'gnumed.ico') 696 try: 697 shutil.move(icon_tmp_file, media_icon_fname) 698 autorun_dict['icon'] = 'icon=gnumed.ico' 699 except Exception: 700 _log.exception('cannot move %s to %s', icon_tmp_file, media_icon_fname) 701 autorun_fname = os.path.join(media_base_dir, 'autorun.inf') 702 autorun_file = io.open(autorun_fname, mode = 'wt', encoding = 'cp1252', errors = 'replace') 703 autorun_file.write(_autorun_inf % autorun_dict) 704 autorun_file.close() 705 706 # cd.inf 707 cd_inf_fname = os.path.join(media_base_dir, 'cd.inf') 708 cd_inf_file = io.open(cd_inf_fname, mode = 'wt', encoding = 'utf8') 709 cd_inf_file.write(_cd_inf % ( 710 pat['lastnames'], 711 pat['firstnames'], 712 gmTools.coalesce(pat['gender'], '?'), 713 pat.get_formatted_dob('%Y-%m-%d'), 714 gmDateTime.pydt_strftime(gmDateTime.pydt_now_here(), format = '%Y-%m-%d'), 715 pat.ID, 716 _cfg.get(option = 'client_version'), 717 ' / '.join([ '%s = %s (%s)' % (g['tag'], g['label'], g['l10n_label']) for g in pat.gender_list ]) 718 )) 719 cd_inf_file.close() 720 721 # README 722 readme_fname = os.path.join(media_base_dir, 'README') 723 readme_file = io.open(readme_fname, mode = 'wt', encoding = 'utf8') 724 readme_file.write(_README % ( 725 pat.get_description_gender(with_nickname = False) + ', ' + _('born') + ' ' + pat.get_formatted_dob('%Y %B %d') 726 )) 727 readme_file.close() 728 729 # patient demographics as GDT/XML/VCF 730 pat.export_as_gdt(filename = os.path.join(media_base_dir, 'patient.gdt')) 731 pat.export_as_xml_linuxmednews(filename = os.path.join(media_base_dir, 'patient.xml')) 732 pat.export_as_vcard(filename = os.path.join(media_base_dir, 'patient.vcf')) 733 734 # praxis VCF 735 shutil.move(prax.vcf, os.path.join(media_base_dir, 'praxis.vcf')) 736 737 return media_base_dir
738 739 #--------------------------------------------------------
740 - def _compute_autorun_inf_label(self, patient):
741 LABEL_MAX_LEN = 32 742 dob = patient.get_formatted_dob(format = ' %Y%m%d', none_string = '', honor_estimation = False) 743 if dob == '': 744 gender_template = ' (%s)' 745 else: 746 gender_template = ' %s' 747 gender = gmTools.coalesce(patient['gender'], '', gender_template) 748 name_max_len = LABEL_MAX_LEN - len(gender) - len(dob) # they already include appropriate padding 749 name = patient.active_name 750 last = name['lastnames'].strip() 751 first = name['firstnames'].strip() 752 len_last = len(last) 753 len_first = len(first) 754 while (len_last + len_first + 1) > name_max_len: 755 if len_first > 6: 756 len_first -= 1 757 if first[len_first - 1] == ' ': 758 len_first -= 1 759 continue 760 len_last -= 1 761 if last[len_last - 1] == ' ': 762 len_last -= 1 763 last = last[:len_last].strip().upper() 764 first = first[:len_first].strip() 765 # max 32 chars, supposedly ASCII, but CP1252 likely works pretty well 766 label = (('%s %s%s%s' % (last, first, dob, gender)).strip())[:32] 767 return label
768 769 #-------------------------------------------------------- 770 # properties 771 #--------------------------------------------------------
772 - def get_items(self, designation=None, order_by='designation, description'):
773 return get_export_items(order_by = order_by, pk_identity = self.__pk_identity, designation = designation)
774 775 items = property(get_items, lambda x:x) 776 #--------------------------------------------------------
777 - def get_printouts(self, order_by='designation, description'):
778 return get_print_jobs(order_by = order_by, pk_identity = self.__pk_identity)
779 780 printouts = property(get_printouts, lambda x:x)
781 782 #============================================================ 783 if __name__ == '__main__': 784 785 if len(sys.argv) < 2: 786 sys.exit() 787 788 if sys.argv[1] != 'test': 789 sys.exit() 790 791 from Gnumed.pycommon import gmI18N 792 gmI18N.activate_locale() 793 gmI18N.install_domain() 794 795 from Gnumed.business import gmPraxis 796 797 #---------------------------------------
798 - def test_export_items():
799 # items = get_export_items() 800 # for item in items: 801 # print item.format() 802 import random 803 create_export_item(description = 'description %s' % random.random(), pk_identity = 12, pk_doc_obj = None, filename = 'dummy.dat') 804 items = get_export_items() 805 for item in items: 806 print(item.format()) 807 item['pk_doc_obj'] = 1 808 item.save() 809 print(item)
810 811 #---------------------------------------
812 - def test_export_area():
813 exp = cExportArea(12) 814 #print exp.export_with_meta_data() 815 #print exp.items 816 exp.add_file(sys.argv[2]) 817 prax = gmPraxis.gmCurrentPraxisBranch(branch = gmPraxis.cPraxisBranch(1)) 818 print(prax) 819 print(prax.branch) 820 print(exp.export())
821 822 #---------------------------------------
823 - def test_label():
824 825 from Gnumed.business.gmPerson import cPatient 826 from Gnumed.business.gmPersonSearch import ask_for_patient 827 828 #while ask_for_patient() is not None: 829 pat_min = 1 830 pat_max = 100 831 try: 832 pat_min = int(sys.argv[2]) 833 pat_max = int(sys.argv[3]) 834 except: 835 pass 836 cPatient(aPK_obj = pat_min) 837 f = io.open('x-auto_inf_labels.txt', mode = 'w', encoding = 'utf8') 838 f.write('--------------------------------\n') 839 f.write('12345678901234567890123456789012\n') 840 f.write('--------------------------------\n') 841 for pat_id in range(pat_min, pat_max): 842 try: 843 exp_area = cExportArea(pat_id) 844 pat = cPatient(aPK_obj = pat_id) 845 except: 846 continue 847 f.write(exp_area._compute_autorun_inf_label(pat) + '\n') 848 f.close() 849 return
850 851 #--------------------------------------- 852 #test_export_items() 853 #test_export_area() 854 test_label() 855 856 sys.exit(0) 857 858 #============================================================ 859 # CDROM "run.bat": 860 # 861 #@echo off 862 # 863 #if defined ProgramFiles(x86) ( 864 # ::64-bit 865 # start /B x64\mdicom.exe /scan . 866 #) else ( 867 # ::32-bit 868 # start /B win32\mdicom.exe /scan . 869 #) 870 # 871 #-------------------------------------------------- 872