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

Source Code for Module Gnumed.business.gmMedDoc

   1  """This module encapsulates a document stored in a GNUmed database. 
   2   
   3  @copyright: GPL 
   4  """ 
   5  #============================================================ 
   6  # $Source: /cvsroot/gnumed/gnumed/gnumed/client/business/gmMedDoc.py,v $ 
   7  # $Id: gmMedDoc.py,v 1.118 2009/09/01 22:14:44 ncq Exp $ 
   8  __version__ = "$Revision: 1.118 $" 
   9  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
  10   
  11  import sys, os, shutil, os.path, types, time, logging 
  12  from cStringIO import StringIO 
  13   
  14   
  15  if __name__ == '__main__': 
  16          sys.path.insert(0, '../../') 
  17  from Gnumed.pycommon import gmExceptions, gmBusinessDBObject, gmPG2, gmTools, gmMimeLib 
  18   
  19   
  20  _log = logging.getLogger('gm.docs') 
  21  _log.info(__version__) 
  22   
  23  MUGSHOT=26 
  24  #============================================================ 
25 -class cDocumentFolder:
26 """Represents a folder with medical documents for a single patient.""" 27
28 - def __init__(self, aPKey = None):
29 """Fails if 30 31 - patient referenced by aPKey does not exist 32 """ 33 self.pk_patient = aPKey # == identity.pk == primary key 34 if not self._pkey_exists(): 35 raise gmExceptions.ConstructorError, "No patient with PK [%s] in database." % aPKey 36 37 # register backend notification interests 38 # (keep this last so we won't hang on threads when 39 # failing this constructor for other reasons ...) 40 # if not self._register_interests(): 41 # raise gmExceptions.ConstructorError, "cannot register signal interests" 42 43 _log.debug('instantiated document folder for patient [%s]' % self.pk_patient)
44 #--------------------------------------------------------
45 - def cleanup(self):
46 pass
47 #-------------------------------------------------------- 48 # internal helper 49 #--------------------------------------------------------
50 - def _pkey_exists(self):
51 """Does this primary key exist ? 52 53 - true/false/None 54 """ 55 # patient in demographic database ? 56 rows, idx = gmPG2.run_ro_queries(queries = [ 57 {'cmd': u"select exists(select pk from dem.identity where pk = %s)", 'args': [self.pk_patient]} 58 ]) 59 if not rows[0][0]: 60 _log.error("patient [%s] not in demographic database" % self.pk_patient) 61 return None 62 return True
63 #-------------------------------------------------------- 64 # API 65 #--------------------------------------------------------
66 - def get_latest_mugshot(self):
67 cmd = u"select pk_obj from blobs.v_latest_mugshot where pk_patient=%s" 68 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_patient]}]) 69 if len(rows) == 0: 70 _log.info('no mugshots available for patient [%s]' % self.pk_patient) 71 return None 72 mugshot = cMedDocPart(aPK_obj=rows[0][0]) 73 return mugshot
74 #--------------------------------------------------------
75 - def get_mugshot_list(self, latest_only=True):
76 if latest_only: 77 cmd = u"select pk_doc, pk_obj from blobs.v_latest_mugshot where pk_patient=%s" 78 else: 79 cmd = u""" 80 select 81 vdm.pk_doc as pk_doc, 82 dobj.pk as pk_obj 83 from 84 blobs.v_doc_med vdm 85 blobs.doc_obj dobj 86 where 87 vdm.pk_type = (select pk from blobs.doc_type where name = 'patient photograph') 88 and vdm.pk_patient = %s 89 and dobj.fk_doc = vdm.pk_doc 90 """ 91 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_patient]}]) 92 return rows
93 #--------------------------------------------------------
94 - def get_doc_list(self, doc_type=None):
95 """return flat list of document IDs""" 96 97 args = { 98 'ID': self.pk_patient, 99 'TYP': doc_type 100 } 101 102 cmd = u""" 103 select vdm.pk_doc 104 from blobs.v_doc_med vdm 105 where 106 vdm.pk_patient = %%(ID)s 107 %s 108 order by vdm.clin_when""" 109 110 if doc_type is None: 111 cmd = cmd % u'' 112 else: 113 try: 114 int(doc_type) 115 cmd = cmd % u'and vdm.pk_type = %(TYP)s' 116 except (TypeError, ValueError): 117 cmd = cmd % u'and vdm.pk_type = (select pk from blobs.doc_type where name = %(TYP)s)' 118 119 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 120 doc_ids = [] 121 for row in rows: 122 doc_ids.append(row[0]) 123 return doc_ids
124 #--------------------------------------------------------
125 - def get_documents(self, doc_type=None, episodes=None, encounter=None):
126 """Return list of documents.""" 127 doc_ids = self.get_doc_list(doc_type=doc_type) 128 129 docs = [] 130 for doc_id in doc_ids: 131 try: 132 docs.append(cMedDoc(aPK_obj=doc_id)) 133 except gmExceptions.ConstructorError: 134 _log.exception('document error on [%s] for patient [%s]' % (doc_id, self.pk_patient)) 135 continue 136 137 if episodes is not None: 138 docs = [ d for d in docs if d['pk_episode'] in episodes ] 139 140 if encounter is not None: 141 docs = [ d for d in docs if d['pk_encounter'] == encounter ] 142 143 return docs
144 #--------------------------------------------------------
145 - def add_document(self, document_type=None, encounter=None, episode=None):
146 return create_document(document_type = document_type, encounter = encounter, episode = episode)
147 #============================================================
148 -class cMedDocPart(gmBusinessDBObject.cBusinessDBObject):
149 """Represents one part of a medical document.""" 150 151 _cmd_fetch_payload = u"""select * from blobs.v_obj4doc_no_data where pk_obj=%s""" 152 _cmds_store_payload = [ 153 u"""update blobs.doc_obj set 154 seq_idx = %(seq_idx)s, 155 comment = gm.nullify_empty_string(%(obj_comment)s), 156 filename = gm.nullify_empty_string(%(filename)s), 157 fk_intended_reviewer = %(pk_intended_reviewer)s 158 where 159 pk=%(pk_obj)s and 160 xmin=%(xmin_doc_obj)s""", 161 u"""select xmin_doc_obj from blobs.v_obj4doc_no_data where pk_obj = %(pk_obj)s""" 162 ] 163 _updatable_fields = [ 164 'seq_idx', 165 'obj_comment', 166 'pk_intended_reviewer', 167 'filename' 168 ] 169 #-------------------------------------------------------- 170 # retrieve data 171 #--------------------------------------------------------
172 - def export_to_file(self, aTempDir = None, aChunkSize = 0, filename=None):
173 174 if self._payload[self._idx['size']] == 0: 175 return None 176 177 if filename is None: 178 suffix = None 179 # preserve original filename extension if available 180 if self._payload[self._idx['filename']] is not None: 181 name, suffix = os.path.splitext(self._payload[self._idx['filename']]) 182 suffix = suffix.strip() 183 if suffix == u'': 184 suffix = None 185 # get unique filename 186 filename = gmTools.get_unique_filename ( 187 prefix = 'gm-doc_obj-page_%s-' % self._payload[self._idx['seq_idx']], 188 suffix = suffix, 189 tmp_dir = aTempDir 190 ) 191 192 success = gmPG2.bytea2file ( 193 data_query = { 194 'cmd': u'SELECT substring(data from %(start)s for %(size)s) FROM blobs.doc_obj WHERE pk=%(pk)s', 195 'args': {'pk': self.pk_obj} 196 }, 197 filename = filename, 198 chunk_size = aChunkSize, 199 data_size = self._payload[self._idx['size']] 200 ) 201 202 if success: 203 return filename 204 205 return None
206 #--------------------------------------------------------
207 - def get_reviews(self):
208 cmd = u""" 209 select 210 reviewer, 211 reviewed_when, 212 is_technically_abnormal, 213 clinically_relevant, 214 is_review_by_responsible_reviewer, 215 is_your_review, 216 coalesce(comment, '') 217 from blobs.v_reviewed_doc_objects 218 where pk_doc_obj = %s 219 order by 220 is_your_review desc, 221 is_review_by_responsible_reviewer desc, 222 reviewed_when desc 223 """ 224 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 225 return rows
226 #--------------------------------------------------------
227 - def get_containing_document(self):
228 return cMedDoc(aPK_obj = self._payload[self._idx['pk_doc']])
229 #-------------------------------------------------------- 230 # store data 231 #--------------------------------------------------------
232 - def update_data_from_file(self, fname=None):
233 # sanity check 234 if not (os.access(fname, os.R_OK) and os.path.isfile(fname)): 235 _log.error('[%s] is not a readable file' % fname) 236 return False 237 238 gmPG2.file2bytea ( 239 query = u"UPDATE blobs.doc_obj SET data=%(data)s::bytea WHERE pk=%(pk)s", 240 filename = fname, 241 args = {'pk': self.pk_obj} 242 ) 243 244 # must update XMIN now ... 245 self.refetch_payload() 246 return True
247 #--------------------------------------------------------
248 - def set_reviewed(self, technically_abnormal=None, clinically_relevant=None):
249 # row already there ? 250 cmd = u""" 251 select pk 252 from blobs.reviewed_doc_objs 253 where 254 fk_reviewed_row = %s and 255 fk_reviewer = (select pk from dem.staff where db_user=current_user)""" 256 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 257 258 # INSERT needed 259 if len(rows) == 0: 260 cols = [ 261 u"fk_reviewer", 262 u"fk_reviewed_row", 263 u"is_technically_abnormal", 264 u"clinically_relevant" 265 ] 266 vals = [ 267 u'%(fk_row)s', 268 u'%(abnormal)s', 269 u'%(relevant)s' 270 ] 271 args = { 272 'fk_row': self.pk_obj, 273 'abnormal': technically_abnormal, 274 'relevant': clinically_relevant 275 } 276 cmd = u""" 277 insert into blobs.reviewed_doc_objs ( 278 %s 279 ) values ( 280 (select pk from dem.staff where db_user=current_user), 281 %s 282 )""" % (', '.join(cols), ', '.join(vals)) 283 284 # UPDATE needed 285 if len(rows) == 1: 286 pk_row = rows[0][0] 287 args = { 288 'abnormal': technically_abnormal, 289 'relevant': clinically_relevant, 290 'pk_row': pk_row 291 } 292 cmd = u""" 293 update blobs.reviewed_doc_objs set 294 is_technically_abnormal = %(abnormal)s, 295 clinically_relevant = %(relevant)s 296 where 297 pk=%(pk_row)s""" 298 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 299 300 return True
301 #--------------------------------------------------------
302 - def set_as_active_photograph(self):
303 if self._payload[self._idx['type']] != u'patient photograph': 304 return False 305 # set seq_idx to current max + 1 306 rows, idx = gmPG2.run_ro_queries ( 307 queries = [{ 308 'cmd': u'select coalesce(max(seq_idx)+1, 1) from blobs.doc_obj where fk_doc=%(doc_id)s', 309 'args': {'doc_id': self._payload[self._idx['pk_doc']]} 310 }] 311 ) 312 self._payload[self._idx['seq_idx']] = rows[0][0] 313 self._is_modified = True 314 self.save_payload()
315 #--------------------------------------------------------
316 - def display_via_mime(self, tmpdir=None, chunksize=0, block=None):
317 318 fname = self.export_to_file(aTempDir = tmpdir, aChunkSize = chunksize) 319 if fname is None: 320 return False, '' 321 322 success, msg = gmMimeLib.call_viewer_on_file(fname, block = block) 323 if not success: 324 return False, msg 325 326 return True, ''
327 #============================================================
328 -class cMedDoc(gmBusinessDBObject.cBusinessDBObject):
329 """Represents one medical document.""" 330 331 _cmd_fetch_payload = u"""select * from blobs.v_doc_med where pk_doc=%s""" 332 _cmds_store_payload = [ 333 u"""update blobs.doc_med set 334 fk_type = %(pk_type)s, 335 fk_episode = %(pk_episode)s, 336 clin_when = %(clin_when)s, 337 comment = gm.nullify_empty_string(%(comment)s), 338 ext_ref = gm.nullify_empty_string(%(ext_ref)s) 339 where 340 pk = %(pk_doc)s and 341 xmin = %(xmin_doc_med)s""", 342 u"""select xmin_doc_med from blobs.v_doc_med where pk_doc = %(pk_doc)s""" 343 ] 344 345 _updatable_fields = [ 346 'pk_type', 347 'comment', 348 'clin_when', 349 'ext_ref', 350 'pk_episode' 351 ] 352 #--------------------------------------------------------
353 - def get_descriptions(self, max_lng=250):
354 """Get document descriptions. 355 356 - will return a list of rows 357 """ 358 if max_lng is None: 359 cmd = u"SELECT pk, text FROM blobs.doc_desc WHERE fk_doc = %s" 360 else: 361 cmd = u"SELECT pk, substring(text from 1 for %s) FROM blobs.doc_desc WHERE fk_doc=%%s" % max_lng 362 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 363 return rows
364 #--------------------------------------------------------
365 - def add_description(self, description=None):
366 cmd = u"insert into blobs.doc_desc (fk_doc, text) values (%s, %s)" 367 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj, description]}]) 368 return True
369 #--------------------------------------------------------
370 - def update_description(self, pk=None, description=None):
371 cmd = u"update blobs.doc_desc set text = %(desc)s where fk_doc = %(doc)s and pk = %(pk_desc)s" 372 gmPG2.run_rw_queries(queries = [ 373 {'cmd': cmd, 'args': {'doc': self.pk_obj, 'pk_desc': pk, 'desc': description}} 374 ]) 375 return True
376 #--------------------------------------------------------
377 - def delete_description(self, pk=None):
378 cmd = u"delete from blobs.doc_desc where fk_doc = %(doc)s and pk = %(desc)s" 379 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'doc': self.pk_obj, 'desc': pk}}]) 380 return True
381 #--------------------------------------------------------
382 - def get_parts(self):
383 cmd = u"select pk_obj from blobs.v_obj4doc_no_data where pk_doc=%s" 384 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 385 parts = [] 386 for row in rows: 387 try: 388 parts.append(cMedDocPart(aPK_obj=row[0])) 389 except ConstructorError, msg: 390 _log.exception(msg) 391 continue 392 return parts
393 #--------------------------------------------------------
394 - def add_part(self, file=None):
395 """Add a part to the document.""" 396 # create dummy part 397 cmd = u""" 398 insert into blobs.doc_obj ( 399 fk_doc, fk_intended_reviewer, data, seq_idx 400 ) VALUES ( 401 %(doc_id)s, 402 (select pk_staff from dem.v_staff where db_user=CURRENT_USER), 403 ''::bytea, 404 (select coalesce(max(seq_idx)+1, 1) from blobs.doc_obj where fk_doc=%(doc_id)s) 405 )""" 406 rows, idx = gmPG2.run_rw_queries ( 407 queries = [ 408 {'cmd': cmd, 'args': {'doc_id': self.pk_obj}}, 409 {'cmd': u"select currval('blobs.doc_obj_pk_seq')"} 410 ], 411 return_data = True 412 ) 413 # init document part instance 414 pk_part = rows[0][0] 415 new_part = cMedDocPart(aPK_obj = pk_part) 416 if not new_part.update_data_from_file(fname=file): 417 _log.error('cannot import binary data from [%s] into document part' % file) 418 gmPG2.run_rw_queries ( 419 queries = [ 420 {'cmd': u"delete from blobs.doc_obj where pk = %s", 'args': [pk_part]} 421 ] 422 ) 423 return None 424 return new_part
425 #--------------------------------------------------------
426 - def add_parts_from_files(self, files=None, reviewer=None):
427 428 new_parts = [] 429 430 for filename in files: 431 new_part = self.add_part(file=filename) 432 if new_part is None: 433 msg = 'cannot instantiate document part object' 434 _log.error(msg) 435 return (False, msg, filename) 436 new_parts.append(new_part) 437 438 new_part['filename'] = filename 439 new_part['pk_intended_reviewer'] = reviewer # None == Null 440 441 success, data = new_part.save_payload() 442 if not success: 443 msg = 'cannot set reviewer to [%s]' % reviewer 444 _log.error(msg) 445 _log.error(str(data)) 446 return (False, msg, filename) 447 448 return (True, '', new_parts)
449 #--------------------------------------------------------
450 - def export_parts_to_files(self, export_dir=None, chunksize=0):
451 fnames = [] 452 for part in self.get_parts(): 453 # FIXME: add guess_extension_from_mimetype 454 fname = os.path.basename(gmTools.coalesce ( 455 part['filename'], 456 u'%s%s%s_%s' % (part['l10n_type'], gmTools.coalesce(part['ext_ref'], '-', '-%s-'), _('part'), part['seq_idx']) 457 )) 458 if export_dir is not None: 459 fname = os.path.join(export_dir, fname) 460 fnames.append(part.export_to_file(aChunkSize = chunksize, filename = fname)) 461 return fnames
462 #--------------------------------------------------------
463 - def has_unreviewed_parts(self):
464 cmd = u"select exists(select 1 from blobs.v_obj4doc_no_data where pk_doc=%s and not reviewed)" 465 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 466 return rows[0][0]
467 #--------------------------------------------------------
468 - def set_reviewed(self, technically_abnormal=None, clinically_relevant=None):
469 # FIXME: this is probably inefficient 470 for part in self.get_parts(): 471 if not part.set_reviewed(technically_abnormal, clinically_relevant): 472 return False 473 return True
474 #--------------------------------------------------------
475 - def set_primary_reviewer(self, reviewer=None):
476 for part in self.get_parts(): 477 part['pk_intended_reviewer'] = reviewer 478 success, data = part.save_payload() 479 if not success: 480 _log.error('cannot set reviewer to [%s]' % reviewer) 481 _log.error(str(data)) 482 return False 483 return True
484 485 #------------------------------------------------------------
486 -def create_document(document_type=None, encounter=None, episode=None):
487 """Returns new document instance or raises an exception. 488 """ 489 cmd1 = u"""insert into blobs.doc_med (fk_type, fk_encounter, fk_episode) VALUES (%(type)s, %(enc)s, %(epi)s)""" 490 cmd2 = u"""select currval('blobs.doc_med_pk_seq')""" 491 rows, idx = gmPG2.run_rw_queries ( 492 queries = [ 493 {'cmd': cmd1, 'args': {'type': document_type, 'enc': encounter, 'epi': episode}}, 494 {'cmd': cmd2} 495 ], 496 return_data = True 497 ) 498 doc_id = rows[0][0] 499 doc = cMedDoc(aPK_obj = doc_id) 500 return doc
501 #------------------------------------------------------------
502 -def search_for_document(patient_id=None, type_id=None):
503 """Searches for documents with the given patient and type ID. 504 505 No type ID returns all documents for the patient. 506 """ 507 # sanity checks 508 if patient_id is None: 509 raise ValueError('need patient id to search for document') 510 511 args = {'pat_id': patient_id, 'type_id': type_id} 512 if type_id is None: 513 cmd = u"SELECT pk_doc from blobs.v_doc_med WHERE pk_patient = %(pat_id)s" 514 else: 515 cmd = u"SELECT pk_doc from blobs.v_doc_med WHERE pk_patient = %(pat_id)s and pk_type = %(type_id)s" 516 517 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 518 519 docs = [] 520 for row in rows: 521 docs.append(cMedDoc(row[0])) 522 return docs
523 #------------------------------------------------------------
524 -def delete_document(document_id=None, encounter_id=None):
525 # will cascade to doc_obj and doc_desc 526 cmd = u"select blobs.delete_document(%(pk)s, %(enc)s)" 527 args = {'pk': document_id, 'enc': encounter_id} 528 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 529 return
530 #------------------------------------------------------------
531 -def reclassify_documents_by_type(original_type=None, target_type=None):
532 533 _log.debug('reclassifying documents by type') 534 _log.debug('original: %s', original_type) 535 _log.debug('target: %s', target_type) 536 537 if target_type['pk_doc_type'] == original_type['pk_doc_type']: 538 return True 539 540 cmd = u""" 541 update blobs.doc_med set 542 fk_type = %(new_type)s 543 where 544 fk_type = %(old_type)s 545 """ 546 args = {u'new_type': target_type['pk_doc_type'], u'old_type': original_type['pk_doc_type']} 547 548 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 549 550 return True
551 552 #============================================================
553 -class cDocumentType(gmBusinessDBObject.cBusinessDBObject):
554 """Represents a document type.""" 555 _cmd_fetch_payload = u"""select * from blobs.v_doc_type where pk_doc_type=%s""" 556 _cmds_store_payload = [ 557 u"""update blobs.doc_type set 558 name = %(type)s 559 where 560 pk=%(pk_obj)s and 561 xmin=%(xmin_doc_type)s""", 562 u"""select xmin_doc_type from blobs.v_doc_type where pk_doc_type = %(pk_obj)s""" 563 ] 564 _updatable_fields = ['type'] 565 #--------------------------------------------------------
566 - def set_translation(self, translation=None):
567 568 if translation.strip() == '': 569 return False 570 571 if translation.strip() == self._payload[self._idx['l10n_type']].strip(): 572 return True 573 574 rows, idx = gmPG2.run_rw_queries ( 575 queries = [ 576 {'cmd': u'select i18n.i18n(%s)', 'args': [self._payload[self._idx['type']]]}, 577 {'cmd': u'select i18n.upd_tx((select i18n.get_curr_lang()), %(orig)s, %(tx)s)', 578 'args': { 579 'orig': self._payload[self._idx['type']], 580 'tx': translation 581 } 582 } 583 ], 584 return_data = True 585 ) 586 if not rows[0][0]: 587 _log.error('cannot set translation to [%s]' % translation) 588 return False 589 590 return self.refetch_payload()
591 592 #------------------------------------------------------------
593 -def get_document_types():
594 rows, idx = gmPG2.run_ro_queries ( 595 queries = [{'cmd': u"SELECT * FROM blobs.v_doc_type"}], 596 get_col_idx = True 597 ) 598 doc_types = [] 599 for row in rows: 600 row_def = { 601 'pk_field': 'pk_doc_type', 602 'idx': idx, 603 'data': row 604 } 605 doc_types.append(cDocumentType(row = row_def)) 606 return doc_types
607 #------------------------------------------------------------
608 -def create_document_type(document_type=None):
609 # check for potential dupes: 610 cmd = u'select pk from blobs.doc_type where name = %s' 611 rows, idx = gmPG2.run_ro_queries ( 612 queries = [{'cmd': cmd, 'args': [document_type]}] 613 ) 614 if len(rows) == 0: 615 cmd1 = u"insert into blobs.doc_type (name) values (%s)" 616 cmd2 = u"select currval('blobs.doc_type_pk_seq')" 617 rows, idx = gmPG2.run_rw_queries ( 618 queries = [ 619 {'cmd': cmd1, 'args': [document_type]}, 620 {'cmd': cmd2} 621 ], 622 return_data = True 623 ) 624 return cDocumentType(aPK_obj = rows[0][0])
625 #------------------------------------------------------------
626 -def delete_document_type(document_type=None):
627 if document_type['is_in_use']: 628 return False 629 gmPG2.run_rw_queries ( 630 queries = [{ 631 'cmd': u'delete from blobs.doc_type where pk=%s', 632 'args': [document_type['pk_doc_type']] 633 }] 634 ) 635 return True
636 #------------------------------------------------------------
637 -def get_ext_ref():
638 """This needs *considerably* more smarts.""" 639 dirname = gmTools.get_unique_filename ( 640 prefix = '', 641 suffix = time.strftime(".%Y%m%d-%H%M%S", time.localtime()) 642 ) 643 # extract name for dir 644 path, doc_ID = os.path.split(dirname) 645 return doc_ID
646 #============================================================ 647 # main 648 #------------------------------------------------------------ 649 if __name__ == '__main__': 650 651 #--------------------------------------------------------
652 - def test_doc_types():
653 654 print "----------------------" 655 print "listing document types" 656 print "----------------------" 657 658 for dt in get_document_types(): 659 print dt 660 661 print "------------------------------" 662 print "testing document type handling" 663 print "------------------------------" 664 665 dt = create_document_type(document_type = 'dummy doc type for unit test 1') 666 print "created:", dt 667 668 dt['type'] = 'dummy doc type for unit test 2' 669 dt.save_payload() 670 print "changed base name:", dt 671 672 dt.set_translation(translation = 'Dummy-Dokumenten-Typ fuer Unit-Test') 673 print "translated:", dt 674 675 print "deleted:", delete_document_type(document_type = dt) 676 677 return
678 #--------------------------------------------------------
679 - def test_adding_doc_part():
680 681 print "-----------------------" 682 print "testing document import" 683 print "-----------------------" 684 685 docs = search_for_document(patient_id=12) 686 doc = docs[0] 687 print "adding to doc:", doc 688 689 fname = sys.argv[1] 690 print "adding from file:", fname 691 part = doc.add_part(file=fname) 692 print "new part:", part 693 694 return
695 #-------------------------------------------------------- 696 from Gnumed.pycommon import gmI18N 697 gmI18N.activate_locale() 698 gmI18N.install_domain() 699 700 test_doc_types() 701 test_adding_doc_part() 702 703 # print get_ext_ref() 704 705 # doc_folder = cDocumentFolder(aPKey=12) 706 707 # photo = doc_folder.get_latest_mugshot() 708 # print type(photo), photo 709 710 # docs = doc_folder.get_documents() 711 # for doc in docs: 712 # print type(doc), doc 713 714 #============================================================ 715 # $Log: gmMedDoc.py,v $ 716 # Revision 1.118 2009/09/01 22:14:44 ncq 717 # - nullify empty strings where useful 718 # 719 # Revision 1.117 2009/07/18 14:06:14 ncq 720 # - fix getting doc IDs list with doc type specified 721 # 722 # Revision 1.116 2009/07/16 11:30:38 ncq 723 # - cleanup 724 # 725 # Revision 1.115 2009/07/15 12:15:04 ncq 726 # - add missing ) in setting trans for doc type 727 # 728 # Revision 1.114 2009/06/04 16:23:40 ncq 729 # - fix fk_type that needs to be pk_type 730 # 731 # Revision 1.113 2009/05/13 13:10:31 ncq 732 # - sort doc retrieval by clin_when 733 # 734 # Revision 1.112 2009/02/18 13:43:38 ncq 735 # - get_unique_filename API change 736 # 737 # Revision 1.111 2009/01/15 11:31:58 ncq 738 # - implement description handling 739 # 740 # Revision 1.110 2009/01/11 19:16:05 ncq 741 # - pseudo method 742 # 743 # Revision 1.109 2009/01/08 16:42:01 ncq 744 # - get_descriptions now includes pks of rows 745 # 746 # Revision 1.108 2008/12/09 23:21:54 ncq 747 # - no more fk_identity in doc_med 748 # - date -> clin_when in doc_med 749 # 750 # Revision 1.107 2008/11/20 18:41:36 ncq 751 # - rename arg in get_documents 752 # 753 # Revision 1.106 2008/10/12 15:14:14 ncq 754 # - use i18n.get_curr_lang 755 # 756 # Revision 1.105 2008/06/26 21:19:15 ncq 757 # - enhance get_documents with episode/encounter filters 758 # 759 # Revision 1.104 2008/05/29 13:26:22 ncq 760 # - add reclassify_documents_by_type 761 # 762 # Revision 1.103 2008/04/11 23:07:22 ncq 763 # - cleanup 764 # 765 # Revision 1.102 2008/02/25 17:31:41 ncq 766 # - logging cleanup 767 # 768 # Revision 1.101 2008/01/30 13:34:50 ncq 769 # - switch to std lib logging 770 # 771 # Revision 1.100 2007/11/05 11:36:29 ncq 772 # - use blobs.delete_document() 773 # 774 # Revision 1.99 2007/10/31 22:06:44 ncq 775 # - delete_document() 776 # 777 # Revision 1.98 2007/10/12 14:15:55 ncq 778 # - cleanup 779 # 780 # Revision 1.97 2007/08/11 23:53:19 ncq 781 # - cleanup 782 # - use gmPG2.bytea2file() 783 # 784 # Revision 1.96 2007/08/09 07:58:44 ncq 785 # - make export_to_file() use gmPG2.bytea2file() 786 # - no more export_to_string() 787 # - comment out __export() 788 # - add display_via_mime() 789 # 790 # Revision 1.95 2007/07/11 21:02:27 ncq 791 # - use gmTools.get_unique_filename() 792 # 793 # Revision 1.94 2007/05/20 01:27:31 ncq 794 # - fix set_translation() - lang needs to go first in i18n.upd_tx() 795 # 796 # Revision 1.93 2007/04/23 01:02:05 ncq 797 # - add set_as_active_photograph() 798 # 799 # Revision 1.92 2007/04/11 14:51:06 ncq 800 # - raising exception on error 801 # 802 # Revision 1.91 2007/03/31 21:18:40 ncq 803 # - apply basename to original filename on save 804 # 805 # Revision 1.90 2007/03/08 16:17:47 ncq 806 # - support blobs.doc_obj.filename 807 # 808 # Revision 1.89 2007/01/10 22:27:53 ncq 809 # - return a list of filenames from export_parts_to_files() 810 # 811 # Revision 1.88 2007/01/07 23:01:26 ncq 812 # - export_to_file(): add filename arg 813 # - export_parts_to_files() 814 # 815 # Revision 1.87 2007/01/06 23:40:49 ncq 816 # - typo in remainder export code in __export 817 # 818 # Revision 1.86 2006/12/11 18:52:11 ncq 819 # - do not delete doc types which are in use 820 # 821 # Revision 1.85 2006/11/20 15:55:41 ncq 822 # - must use return_data when wanting data back from run_rw_queries() 823 # 824 # Revision 1.84 2006/11/06 09:57:39 ncq 825 # - need to return_data to return data 826 # - cannot drop non-user doc types from blobs.doc_type so drop is_user where condition 827 # 828 # Revision 1.83 2006/10/31 17:18:08 ncq 829 # - fix a few programming errors 830 # 831 # Revision 1.82 2006/10/31 16:16:28 ncq 832 # - query strings as unicode 833 # 834 # Revision 1.81 2006/10/08 15:07:11 ncq 835 # - convert to gmPG2 836 # - drop blobs.xlnk_identity support 837 # - use cBusinessDBObject 838 # - adjust queries to schema 839 # 840 # Revision 1.80 2006/09/30 11:38:08 ncq 841 # - remove support for blobs.xlnk_identity 842 # 843 # Revision 1.79 2006/09/28 14:36:10 ncq 844 # - fix search_for_doc(), it used the row, not the value for document instantiation 845 # 846 # Revision 1.78 2006/09/21 19:23:12 ncq 847 # - cast '' to bytea when adding a dummy document part 848 # 849 # Revision 1.77 2006/09/02 21:22:10 ncq 850 # - return new parts from add_parts_from_files() 851 # - cMedDoc.update_data() needs fixing 852 # - forward port test suite improvement and cMedDoc instantiation fix from rel-0-2-patches branch 853 # 854 # Revision 1.76 2006/09/01 14:39:19 ncq 855 # - add FIXME 856 # 857 # Revision 1.75 2006/07/10 21:15:07 ncq 858 # - add cDocumentType 859 # - get_document_types() now returns instances 860 # - add delete_document_type() 861 # - improved testing 862 # 863 # Revision 1.74 2006/07/07 12:06:08 ncq 864 # - return more data from get_document_types() 865 # 866 # Revision 1.73 2006/07/04 21:37:43 ncq 867 # - cleanup 868 # - add create_document_type() 869 # 870 # Revision 1.72 2006/07/01 13:10:13 ncq 871 # - fix __export() re encoding setting 872 # 873 # Revision 1.71 2006/07/01 11:23:35 ncq 874 # - cleanup 875 # 876 # Revision 1.70 2006/06/26 21:37:14 ncq 877 # - properly use explicit encoding setting in put/get 878 # data for document objects 879 # 880 # Revision 1.69 2006/06/21 15:51:48 ncq 881 # - set_intended_reviewer() -> set_primary_reviewer() 882 # 883 # Revision 1.68 2006/06/18 22:43:21 ncq 884 # - missing % 885 # 886 # Revision 1.67 2006/06/18 13:19:55 ncq 887 # - must update XMIN after update_data(_from_file()) 888 # - use run_commit2() instead of run_commit() 889 # 890 # Revision 1.66 2006/06/12 20:48:48 ncq 891 # - add missing cleanup() to folder class 892 # 893 # Revision 1.65 2006/06/07 22:07:14 ncq 894 # - use run_commit2() only to ensure better transaction handling 895 # - fix one suspicious faulty handling of run_commit2() return values 896 # - add a "del new_part" just for good measure 897 # 898 # Revision 1.64 2006/06/07 20:22:01 ncq 899 # - must be pk_intended_reviewer 900 # 901 # Revision 1.63 2006/06/05 21:52:00 ncq 902 # - fix one double % 903 # 904 # Revision 1.62 2006/05/31 09:45:19 ncq 905 # - fix doc part saving/locking - reference to PK was wrong, I wonder how it ever worked 906 # - add get_containing_document() and set_intended_reviewer() to cMedDocPart 907 # - make pk_episode in cMedDoc editable 908 # - some more error checking 909 # 910 # Revision 1.61 2006/05/28 15:25:50 ncq 911 # - add "episode" field to doc_part 912 # 913 # Revision 1.60 2006/05/25 22:11:36 ncq 914 # - use blobs.v_obj4doc_no_data 915 # 916 # Revision 1.59 2006/05/20 18:29:21 ncq 917 # - allow setting reviewer in add_parts_from_files() 918 # 919 # Revision 1.58 2006/05/16 15:47:19 ncq 920 # - various small fixes re setting review status 921 # 922 # Revision 1.57 2006/05/08 16:33:02 ncq 923 # - remove useless order by's 924 # - add cMedDoc.has_unreviewed_parts() 925 # 926 # Revision 1.56 2006/05/01 18:43:50 ncq 927 # - handle encounter/episode in create_document() 928 # 929 # Revision 1.55 2006/02/13 08:11:28 ncq 930 # - doc-wide set_reviewed() must be in cMedDoc, not cDocumentFolder 931 # - add cMedDocPart.get_reviews() 932 # 933 # Revision 1.54 2006/02/05 14:36:01 ncq 934 # - intended reviewer now must be staff, not identity 935 # 936 # Revision 1.53 2006/02/05 14:27:13 ncq 937 # - add doc-wide set_reviewed() wrapper to cMedDoc 938 # - handle review-related fields to cMedDocPart 939 # - add set_reviewed() to cMedDocPart 940 # 941 # Revision 1.52 2006/01/27 22:16:14 ncq 942 # - add reviewed/signed to cMedDocPart 943 # 944 # Revision 1.51 2006/01/22 18:07:34 ncq 945 # - set client encoding to sql_ascii where necessary for blobs handling 946 # 947 # Revision 1.50 2006/01/18 23:07:16 ncq 948 # - cleanup 949 # 950 # Revision 1.49 2006/01/17 22:01:35 ncq 951 # - now really sort by date 952 # 953 # Revision 1.48 2006/01/17 20:20:26 ncq 954 # - implement get_ext_ref() 955 # 956 # Revision 1.47 2006/01/16 19:33:46 ncq 957 # - need to "reset client_encoding" on 8.0, too 958 # 959 # Revision 1.46 2006/01/16 19:23:32 ncq 960 # - use reset_encoding on blobs more generously 961 # 962 # Revision 1.45 2006/01/15 16:12:05 ncq 963 # - explicitely use PgUnQuoteBytea() on the concatenated 964 # string when getting Bytea in pieces 965 # 966 # Revision 1.44 2006/01/15 15:06:42 ncq 967 # - return newest-first from get_doc_list() 968 # 969 # Revision 1.43 2006/01/15 14:58:59 ncq 970 # - return translations from get_document_types() 971 # 972 # Revision 1.42 2006/01/15 14:41:21 ncq 973 # - add missing None in call to run_ro_query() 974 # 975 # Revision 1.41 2006/01/14 23:24:00 shilbert 976 # - return doc_type and coresponding primary key not just doc_type string 977 # 978 # Revision 1.40 2006/01/13 13:48:15 ncq 979 # - brush up adding document parts 980 # 981 # Revision 1.39 2006/01/11 22:43:36 ncq 982 # - yet another missed id -> pk 983 # 984 # Revision 1.38 2006/01/11 13:13:53 ncq 985 # - id -> pk 986 # 987 # Revision 1.37 2006/01/09 22:06:09 ncq 988 # - aPKey -> aPK_obj 989 # 990 # Revision 1.36 2006/01/09 10:42:21 ncq 991 # - yet another missed dem schema qualification 992 # 993 # Revision 1.35 2006/01/01 17:39:39 ncq 994 # - require document type in create_document() 995 # 996 # Revision 1.34 2006/01/01 16:08:08 ncq 997 # - proper scoping of functions 998 # 999 # Revision 1.33 2006/01/01 15:39:50 ncq 1000 # - some missing blobs. 1001 # 1002 # Revision 1.32 2005/12/14 17:00:01 ncq 1003 # - add add_document() and add_description() to cMedDoc 1004 # - fix missing '' 1005 # - add gmMedDoc.get_ext_ref() 1006 # 1007 # Revision 1.31 2005/12/13 21:46:07 ncq 1008 # - enhance cMedDoc.add_part() so it can load data from a file 1009 # - add cMedDoc.add_parts_from_files() 1010 # 1011 # Revision 1.30 2005/11/27 09:23:07 ncq 1012 # - added get_document_types() 1013 # 1014 # Revision 1.29 2005/11/01 08:50:24 ncq 1015 # - blobs are in blobs. schema now 1016 # 1017 # Revision 1.28 2005/02/12 13:56:49 ncq 1018 # - identity.id -> identity.pk 1019 # 1020 # Revision 1.27 2005/01/02 19:55:30 ncq 1021 # - don't need _xmins_refetch_col_pos anymore 1022 # 1023 # Revision 1.26 2004/12/20 16:45:49 ncq 1024 # - gmBusinessDBObject now requires refetching of XMIN after save_payload 1025 # 1026 # Revision 1.25 2004/11/03 22:32:34 ncq 1027 # - support _cmds_lock_rows_for_update in business object base class 1028 # 1029 # Revision 1.24 2004/10/11 19:46:52 ncq 1030 # - properly VOify deriving from cBusinessDBObject 1031 # - cMedObj -> cMedDocPart 1032 # - cDocumentFolder.get_documents() 1033 # - cMedDoc.get_descriptions() where max_lng=None will fetch entire description 1034 # - comments, cleanup 1035 # 1036 # Revision 1.23 2004/09/28 12:20:16 ncq 1037 # - cleanup/robustify 1038 # - add get_latest_mugshot() 1039 # 1040 # Revision 1.22 2004/06/01 07:50:01 ncq 1041 # - error checking, optimizing, cleanup 1042 # - adaptation to ClinItem pending 1043 # 1044 # Revision 1.21 2004/03/20 11:16:16 ncq 1045 # - v_18n_doc_type is no more, use _(doc_type.name) 1046 # 1047 # Revision 1.20 2004/03/07 23:49:54 ncq 1048 # - add cDocumentFolder 1049 # 1050 # Revision 1.19 2004/03/04 19:46:53 ncq 1051 # - switch to package based import: from Gnumed.foo import bar 1052 # 1053 # Revision 1.18 2004/03/03 14:41:49 ncq 1054 # - cleanup 1055 # - FIXME: write gmDocumentRecord_SQL 1056 # 1057 # Revision 1.17 2004/03/03 05:24:01 ihaywood 1058 # patient photograph support 1059 # 1060 # Revision 1.16 2004/02/25 09:46:20 ncq 1061 # - import from pycommon now, not python-common 1062 # 1063 # Revision 1.15 2004/01/26 18:19:55 ncq 1064 # - missing : 1065 # 1066 # Revision 1.14 2004/01/18 21:42:17 ncq 1067 # - extra : removed 1068 # 1069 # Revision 1.13 2003/12/29 16:20:28 uid66147 1070 # - use gmPG.run_ro_query/run_commit instead of caching connections ourselves 1071 # - but do establish our own rw connection even for reads since escaping bytea 1072 # over a client_encoding != C breaks transmitted binaries 1073 # - remove deprecated __get/setitem__ API 1074 # - sane create_document/object helpers 1075 # 1076 # Revision 1.12 2003/11/17 10:56:34 sjtan 1077 # 1078 # synced and commiting. 1079 # 1080 # Revision 1.1 2003/10/23 06:02:38 sjtan 1081 # 1082 # manual edit areas modelled after r.terry's specs. 1083 # 1084 # Revision 1.11 2003/06/27 16:04:13 ncq 1085 # - no ; in SQL 1086 # 1087 # Revision 1.10 2003/06/26 21:26:15 ncq 1088 # - cleanup re (cmd,args) and %s; quoting bug 1089 # 1090 # Revision 1.9 2003/04/20 15:32:15 ncq 1091 # - removed __run_query helper 1092 # - call_viewer_on_file moved to gmMimeLib 1093 # 1094 # Revision 1.8 2003/04/18 22:33:44 ncq 1095 # - load document descriptions from database 1096 # 1097 # Revision 1.7 2003/03/31 01:14:22 ncq 1098 # - fixed KeyError on metadata[] 1099 # 1100 # Revision 1.6 2003/03/30 00:18:32 ncq 1101 # - typo 1102 # 1103 # Revision 1.5 2003/03/25 12:37:20 ncq 1104 # - use gmPG helpers 1105 # - clean up code 1106 # - __update_data/metadata - this worked for moving between databases ! 1107 # 1108 # Revision 1.4 2003/02/26 23:22:04 ncq 1109 # - metadata write support 1110 # 1111