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

Source Code for Module Gnumed.business.gmDocuments

  1  """This module encapsulates a document stored in a GNUmed database. 
  2   
  3  @copyright: GPL v2 or later 
  4  """ 
  5  #============================================================ 
  6  __version__ = "$Revision: 1.118 $" 
  7  __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>" 
  8   
  9  import sys, os, shutil, os.path, types, time, logging 
 10  from cStringIO import StringIO 
 11  from pprint import pprint 
 12   
 13   
 14  if __name__ == '__main__': 
 15          sys.path.insert(0, '../../') 
 16  from Gnumed.pycommon import gmExceptions 
 17  from Gnumed.pycommon import gmBusinessDBObject 
 18  from Gnumed.pycommon import gmPG2 
 19  from Gnumed.pycommon import gmTools 
 20  from Gnumed.pycommon import gmMimeLib 
 21  from Gnumed.pycommon import gmDateTime 
 22   
 23   
 24  _log = logging.getLogger('gm.docs') 
 25  _log.info(__version__) 
 26   
 27  MUGSHOT=26 
 28  DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE = u'visual progress note' 
 29  DOCUMENT_TYPE_PRESCRIPTION = u'prescription' 
 30  #============================================================ 
31 -class cDocumentFolder:
32 """Represents a folder with medical documents for a single patient.""" 33
34 - def __init__(self, aPKey = None):
35 """Fails if 36 37 - patient referenced by aPKey does not exist 38 """ 39 self.pk_patient = aPKey # == identity.pk == primary key 40 if not self._pkey_exists(): 41 raise gmExceptions.ConstructorError, "No patient with PK [%s] in database." % aPKey 42 43 # register backend notification interests 44 # (keep this last so we won't hang on threads when 45 # failing this constructor for other reasons ...) 46 # if not self._register_interests(): 47 # raise gmExceptions.ConstructorError, "cannot register signal interests" 48 49 _log.debug('instantiated document folder for patient [%s]' % self.pk_patient)
50 #--------------------------------------------------------
51 - def cleanup(self):
52 pass
53 #-------------------------------------------------------- 54 # internal helper 55 #--------------------------------------------------------
56 - def _pkey_exists(self):
57 """Does this primary key exist ? 58 59 - true/false/None 60 """ 61 # patient in demographic database ? 62 rows, idx = gmPG2.run_ro_queries(queries = [ 63 {'cmd': u"select exists(select pk from dem.identity where pk = %s)", 'args': [self.pk_patient]} 64 ]) 65 if not rows[0][0]: 66 _log.error("patient [%s] not in demographic database" % self.pk_patient) 67 return None 68 return True
69 #-------------------------------------------------------- 70 # API 71 #--------------------------------------------------------
73 cmd = u""" 74 SELECT pk_doc 75 FROM blobs.v_doc_med 76 WHERE 77 pk_patient = %(pat)s 78 AND 79 type = %(typ)s 80 AND 81 ext_ref = %(ref)s 82 ORDER BY 83 clin_when DESC 84 LIMIT 1 85 """ 86 args = { 87 'pat': self.pk_patient, 88 'typ': DOCUMENT_TYPE_PRESCRIPTION, 89 'ref': u'FreeDiams' 90 } 91 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 92 if len(rows) == 0: 93 _log.info('no FreeDiams prescription available for patient [%s]' % self.pk_patient) 94 return None 95 prescription = cDocument(aPK_obj = rows[0][0]) 96 return prescription
97 #--------------------------------------------------------
98 - def get_latest_mugshot(self):
99 cmd = u"select pk_obj from blobs.v_latest_mugshot where pk_patient=%s" 100 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_patient]}]) 101 if len(rows) == 0: 102 _log.info('no mugshots available for patient [%s]' % self.pk_patient) 103 return None 104 mugshot = cDocumentPart(aPK_obj=rows[0][0]) 105 return mugshot
106 #--------------------------------------------------------
107 - def get_mugshot_list(self, latest_only=True):
108 if latest_only: 109 cmd = u"select pk_doc, pk_obj from blobs.v_latest_mugshot where pk_patient=%s" 110 else: 111 cmd = u""" 112 select 113 vdm.pk_doc as pk_doc, 114 dobj.pk as pk_obj 115 from 116 blobs.v_doc_med vdm 117 blobs.doc_obj dobj 118 where 119 vdm.pk_type = (select pk from blobs.doc_type where name = 'patient photograph') 120 and vdm.pk_patient = %s 121 and dobj.fk_doc = vdm.pk_doc 122 """ 123 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_patient]}]) 124 return rows
125 #--------------------------------------------------------
126 - def get_doc_list(self, doc_type=None):
127 """return flat list of document IDs""" 128 129 args = { 130 'ID': self.pk_patient, 131 'TYP': doc_type 132 } 133 134 cmd = u""" 135 select vdm.pk_doc 136 from blobs.v_doc_med vdm 137 where 138 vdm.pk_patient = %%(ID)s 139 %s 140 order by vdm.clin_when""" 141 142 if doc_type is None: 143 cmd = cmd % u'' 144 else: 145 try: 146 int(doc_type) 147 cmd = cmd % u'and vdm.pk_type = %(TYP)s' 148 except (TypeError, ValueError): 149 cmd = cmd % u'and vdm.pk_type = (select pk from blobs.doc_type where name = %(TYP)s)' 150 151 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 152 doc_ids = [] 153 for row in rows: 154 doc_ids.append(row[0]) 155 return doc_ids
156 #--------------------------------------------------------
157 - def get_visual_progress_notes(self, episodes=None, encounter=None):
158 return self.get_documents ( 159 doc_type = DOCUMENT_TYPE_VISUAL_PROGRESS_NOTE, 160 episodes = episodes, 161 encounter = encounter 162 )
163 #--------------------------------------------------------
164 - def get_unsigned_documents(self):
165 args = {'pat': self.pk_patient} 166 cmd = _sql_fetch_document_fields % u""" 167 pk_doc IN ( 168 SELECT DISTINCT ON (b_vo.pk_doc) b_vo.pk_doc 169 FROM blobs.v_obj4doc_no_data b_vo 170 WHERE 171 pk_patient = %(pat)s 172 AND 173 reviewed IS FALSE 174 ) 175 ORDER BY clin_when DESC""" 176 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 177 return [ cDocument(row = {'pk_field': 'pk_doc', 'idx': idx, 'data': r}) for r in rows ]
178 #--------------------------------------------------------
179 - def get_documents(self, doc_type=None, episodes=None, encounter=None, order_by=None, exclude_unsigned=False):
180 """Return list of documents.""" 181 182 args = { 183 'pat': self.pk_patient, 184 'type': doc_type, 185 'enc': encounter 186 } 187 where_parts = [u'pk_patient = %(pat)s'] 188 189 if doc_type is not None: 190 try: 191 int(doc_type) 192 where_parts.append(u'pk_type = %(type)s') 193 except (TypeError, ValueError): 194 where_parts.append(u'pk_type = (SELECT pk FROM blobs.doc_type WHERE name = %(type)s)') 195 196 if (episodes is not None) and (len(episodes) > 0): 197 where_parts.append(u'pk_episode IN %(epi)s') 198 args['epi'] = tuple(episodes) 199 200 if encounter is not None: 201 where_parts.append(u'pk_encounter = %(enc)s') 202 203 if exclude_unsigned: 204 where_parts.append(u'pk_doc IN (SELECT b_vo.pk_doc FROM blobs.v_obj4doc_no_data b_vo WHERE b_vo.pk_patient = %(pat)s AND b_vo.reviewed IS TRUE)') 205 206 if order_by is None: 207 order_by = u'ORDER BY clin_when' 208 209 cmd = u"%s\n%s" % (_sql_fetch_document_fields % u' AND '.join(where_parts), order_by) 210 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True) 211 212 return [ cDocument(row = {'pk_field': 'pk_doc', 'idx': idx, 'data': r}) for r in rows ]
213 #--------------------------------------------------------
214 - def add_document(self, document_type=None, encounter=None, episode=None):
215 return create_document(document_type = document_type, encounter = encounter, episode = episode)
216 #============================================================ 217 _sql_fetch_document_part_fields = u"select * from blobs.v_obj4doc_no_data where %s" 218
219 -class cDocumentPart(gmBusinessDBObject.cBusinessDBObject):
220 """Represents one part of a medical document.""" 221 222 _cmd_fetch_payload = _sql_fetch_document_part_fields % u"pk_obj = %s" 223 _cmds_store_payload = [ 224 u"""update blobs.doc_obj set 225 seq_idx = %(seq_idx)s, 226 comment = gm.nullify_empty_string(%(obj_comment)s), 227 filename = gm.nullify_empty_string(%(filename)s), 228 fk_intended_reviewer = %(pk_intended_reviewer)s 229 where 230 pk=%(pk_obj)s and 231 xmin=%(xmin_doc_obj)s""", 232 u"""select xmin_doc_obj from blobs.v_obj4doc_no_data where pk_obj = %(pk_obj)s""" 233 ] 234 _updatable_fields = [ 235 'seq_idx', 236 'obj_comment', 237 'pk_intended_reviewer', 238 'filename' 239 ] 240 #-------------------------------------------------------- 241 # retrieve data 242 #--------------------------------------------------------
243 - def export_to_file(self, aTempDir = None, aChunkSize = 0, filename=None):
244 245 if self._payload[self._idx['size']] == 0: 246 return None 247 248 if filename is None: 249 suffix = None 250 # preserve original filename extension if available 251 if self._payload[self._idx['filename']] is not None: 252 name, suffix = os.path.splitext(self._payload[self._idx['filename']]) 253 suffix = suffix.strip() 254 if suffix == u'': 255 suffix = None 256 # get unique filename 257 filename = gmTools.get_unique_filename ( 258 prefix = 'gm-doc_obj-page_%s-' % self._payload[self._idx['seq_idx']], 259 suffix = suffix, 260 tmp_dir = aTempDir 261 ) 262 263 success = gmPG2.bytea2file ( 264 data_query = { 265 'cmd': u'SELECT substring(data from %(start)s for %(size)s) FROM blobs.doc_obj WHERE pk=%(pk)s', 266 'args': {'pk': self.pk_obj} 267 }, 268 filename = filename, 269 chunk_size = aChunkSize, 270 data_size = self._payload[self._idx['size']] 271 ) 272 273 if success: 274 return filename 275 276 return None
277 #--------------------------------------------------------
278 - def get_reviews(self):
279 cmd = u""" 280 select 281 reviewer, 282 reviewed_when, 283 is_technically_abnormal, 284 clinically_relevant, 285 is_review_by_responsible_reviewer, 286 is_your_review, 287 coalesce(comment, '') 288 from blobs.v_reviewed_doc_objects 289 where pk_doc_obj = %s 290 order by 291 is_your_review desc, 292 is_review_by_responsible_reviewer desc, 293 reviewed_when desc 294 """ 295 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 296 return rows
297 #--------------------------------------------------------
298 - def get_containing_document(self):
299 return cDocument(aPK_obj = self._payload[self._idx['pk_doc']])
300 #-------------------------------------------------------- 301 # store data 302 #--------------------------------------------------------
303 - def update_data_from_file(self, fname=None):
304 # sanity check 305 if not (os.access(fname, os.R_OK) and os.path.isfile(fname)): 306 _log.error('[%s] is not a readable file' % fname) 307 return False 308 309 gmPG2.file2bytea ( 310 query = u"UPDATE blobs.doc_obj SET data=%(data)s::bytea WHERE pk=%(pk)s", 311 filename = fname, 312 args = {'pk': self.pk_obj} 313 ) 314 315 # must update XMIN now ... 316 self.refetch_payload() 317 return True
318 #--------------------------------------------------------
319 - def set_reviewed(self, technically_abnormal=None, clinically_relevant=None):
320 # row already there ? 321 cmd = u""" 322 select pk 323 from blobs.reviewed_doc_objs 324 where 325 fk_reviewed_row = %s and 326 fk_reviewer = (select pk from dem.staff where db_user = current_user)""" 327 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 328 329 # INSERT needed 330 if len(rows) == 0: 331 cols = [ 332 u"fk_reviewer", 333 u"fk_reviewed_row", 334 u"is_technically_abnormal", 335 u"clinically_relevant" 336 ] 337 vals = [ 338 u'%(fk_row)s', 339 u'%(abnormal)s', 340 u'%(relevant)s' 341 ] 342 args = { 343 'fk_row': self.pk_obj, 344 'abnormal': technically_abnormal, 345 'relevant': clinically_relevant 346 } 347 cmd = u""" 348 insert into blobs.reviewed_doc_objs ( 349 %s 350 ) values ( 351 (select pk from dem.staff where db_user=current_user), 352 %s 353 )""" % (', '.join(cols), ', '.join(vals)) 354 355 # UPDATE needed 356 if len(rows) == 1: 357 pk_row = rows[0][0] 358 args = { 359 'abnormal': technically_abnormal, 360 'relevant': clinically_relevant, 361 'pk_row': pk_row 362 } 363 cmd = u""" 364 update blobs.reviewed_doc_objs set 365 is_technically_abnormal = %(abnormal)s, 366 clinically_relevant = %(relevant)s 367 where 368 pk=%(pk_row)s""" 369 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 370 371 return True
372 #--------------------------------------------------------
373 - def set_as_active_photograph(self):
374 if self._payload[self._idx['type']] != u'patient photograph': 375 return False 376 # set seq_idx to current max + 1 377 rows, idx = gmPG2.run_ro_queries ( 378 queries = [{ 379 'cmd': u'select coalesce(max(seq_idx)+1, 1) from blobs.doc_obj where fk_doc=%(doc_id)s', 380 'args': {'doc_id': self._payload[self._idx['pk_doc']]} 381 }] 382 ) 383 self._payload[self._idx['seq_idx']] = rows[0][0] 384 self._is_modified = True 385 self.save_payload()
386 #--------------------------------------------------------
387 - def display_via_mime(self, tmpdir=None, chunksize=0, block=None):
388 389 fname = self.export_to_file(aTempDir = tmpdir, aChunkSize = chunksize) 390 if fname is None: 391 return False, '' 392 393 success, msg = gmMimeLib.call_viewer_on_file(fname, block = block) 394 if not success: 395 return False, msg 396 397 return True, ''
398 #============================================================ 399 _sql_fetch_document_fields = u""" 400 SELECT 401 *, 402 COALESCE ( 403 (SELECT array_agg(seq_idx) FROM blobs.doc_obj b_do WHERE b_do.fk_doc = b_vdm.pk_doc), 404 ARRAY[]::integer[] 405 ) 406 AS seq_idx_list 407 FROM 408 blobs.v_doc_med b_vdm 409 WHERE 410 %s 411 """ 412
413 -class cDocument(gmBusinessDBObject.cBusinessDBObject):
414 """Represents one medical document.""" 415 416 _cmd_fetch_payload = _sql_fetch_document_fields % u"pk_doc = %s" 417 _cmds_store_payload = [ 418 u"""update blobs.doc_med set 419 fk_type = %(pk_type)s, 420 fk_episode = %(pk_episode)s, 421 fk_encounter = %(pk_encounter)s, 422 clin_when = %(clin_when)s, 423 comment = gm.nullify_empty_string(%(comment)s), 424 ext_ref = gm.nullify_empty_string(%(ext_ref)s) 425 where 426 pk = %(pk_doc)s and 427 xmin = %(xmin_doc_med)s""", 428 u"""select xmin_doc_med from blobs.v_doc_med where pk_doc = %(pk_doc)s""" 429 ] 430 431 _updatable_fields = [ 432 'pk_type', 433 'comment', 434 'clin_when', 435 'ext_ref', 436 'pk_episode', 437 'pk_encounter' # mainly useful when moving visual progress notes to their respective encounters 438 ] 439 #--------------------------------------------------------
440 - def refetch_payload(self, ignore_changes=False):
441 try: del self.__has_unreviewed_parts 442 except AttributeError: pass 443 444 return super(cDocument, self).refetch_payload(ignore_changes = ignore_changes)
445 #--------------------------------------------------------
446 - def get_descriptions(self, max_lng=250):
447 """Get document descriptions. 448 449 - will return a list of rows 450 """ 451 if max_lng is None: 452 cmd = u"SELECT pk, text FROM blobs.doc_desc WHERE fk_doc = %s" 453 else: 454 cmd = u"SELECT pk, substring(text from 1 for %s) FROM blobs.doc_desc WHERE fk_doc=%%s" % max_lng 455 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}]) 456 return rows
457 #--------------------------------------------------------
458 - def add_description(self, description=None):
459 cmd = u"insert into blobs.doc_desc (fk_doc, text) values (%s, %s)" 460 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj, description]}]) 461 return True
462 #--------------------------------------------------------
463 - def update_description(self, pk=None, description=None):
464 cmd = u"update blobs.doc_desc set text = %(desc)s where fk_doc = %(doc)s and pk = %(pk_desc)s" 465 gmPG2.run_rw_queries(queries = [ 466 {'cmd': cmd, 'args': {'doc': self.pk_obj, 'pk_desc': pk, 'desc': description}} 467 ]) 468 return True
469 #--------------------------------------------------------
470 - def delete_description(self, pk=None):
471 cmd = u"delete from blobs.doc_desc where fk_doc = %(doc)s and pk = %(desc)s" 472 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'doc': self.pk_obj, 'desc': pk}}]) 473 return True
474 #--------------------------------------------------------
475 - def _get_parts(self):
476 cmd = _sql_fetch_document_part_fields % u"pk_doc = %s" 477 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': [self.pk_obj]}], get_col_idx = True) 478 return [ cDocumentPart(row = {'pk_field': 'pk_obj', 'idx': idx, 'data': r}) for r in rows ]
479 480 parts = property(_get_parts, lambda x:x) 481 #--------------------------------------------------------
482 - def add_part(self, file=None):
483 """Add a part to the document.""" 484 # create dummy part 485 cmd = u""" 486 insert into blobs.doc_obj ( 487 fk_doc, data, seq_idx 488 ) VALUES ( 489 %(doc_id)s, 490 ''::bytea, 491 (select coalesce(max(seq_idx)+1, 1) from blobs.doc_obj where fk_doc=%(doc_id)s) 492 )""" 493 rows, idx = gmPG2.run_rw_queries ( 494 queries = [ 495 {'cmd': cmd, 'args': {'doc_id': self.pk_obj}}, 496 {'cmd': u"select currval('blobs.doc_obj_pk_seq')"} 497 ], 498 return_data = True 499 ) 500 # init document part instance 501 pk_part = rows[0][0] 502 new_part = cDocumentPart(aPK_obj = pk_part) 503 if not new_part.update_data_from_file(fname=file): 504 _log.error('cannot import binary data from [%s] into document part' % file) 505 gmPG2.run_rw_queries ( 506 queries = [ 507 {'cmd': u"delete from blobs.doc_obj where pk = %s", 'args': [pk_part]} 508 ] 509 ) 510 return None 511 new_part['filename'] = file 512 new_part.save_payload() 513 514 return new_part
515 #--------------------------------------------------------
516 - def add_parts_from_files(self, files=None, reviewer=None):
517 518 new_parts = [] 519 520 for filename in files: 521 new_part = self.add_part(file = filename) 522 if new_part is None: 523 msg = 'cannot instantiate document part object' 524 _log.error(msg) 525 return (False, msg, filename) 526 new_parts.append(new_part) 527 528 if reviewer is not None: 529 new_part['pk_intended_reviewer'] = reviewer # None == Null 530 success, data = new_part.save_payload() 531 if not success: 532 msg = 'cannot set reviewer to [%s]' % reviewer 533 _log.error(msg) 534 _log.error(str(data)) 535 return (False, msg, filename) 536 537 return (True, '', new_parts)
538 #--------------------------------------------------------
539 - def export_parts_to_files(self, export_dir=None, chunksize=0):
540 fnames = [] 541 for part in self.parts: 542 # FIXME: add guess_extension_from_mimetype 543 fname = os.path.basename(gmTools.coalesce ( 544 part['filename'], 545 u'%s%s%s_%s' % (part['l10n_type'], gmTools.coalesce(part['ext_ref'], '-', '-%s-'), _('part'), part['seq_idx']) 546 )) 547 if export_dir is not None: 548 fname = os.path.join(export_dir, fname) 549 fnames.append(part.export_to_file(aChunkSize = chunksize, filename = fname)) 550 return fnames
551 #--------------------------------------------------------
553 try: 554 return self.__has_unreviewed_parts 555 except AttributeError: 556 pass 557 558 cmd = u"SELECT EXISTS(SELECT 1 FROM blobs.v_obj4doc_no_data WHERE pk_doc = %(pk)s AND reviewed IS FALSE)" 559 args = {'pk': self.pk_obj} 560 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 561 self.__has_unreviewed_parts = rows[0][0] 562 563 return self.__has_unreviewed_parts
564 565 has_unreviewed_parts = property(_get_has_unreviewed_parts, lambda x:x) 566 #--------------------------------------------------------
567 - def set_reviewed(self, technically_abnormal=None, clinically_relevant=None):
568 # FIXME: this is probably inefficient 569 for part in self.parts: 570 if not part.set_reviewed(technically_abnormal, clinically_relevant): 571 return False 572 return True
573 #--------------------------------------------------------
574 - def set_primary_reviewer(self, reviewer=None):
575 for part in self.parts: 576 part['pk_intended_reviewer'] = reviewer 577 success, data = part.save_payload() 578 if not success: 579 _log.error('cannot set reviewer to [%s]' % reviewer) 580 _log.error(str(data)) 581 return False 582 return True
583 #--------------------------------------------------------
584 - def format(self):
585 part_count = len(self._payload[self._idx['seq_idx_list']]) 586 if part_count == 1: 587 parts = _('1 part') 588 else: 589 parts = _('%s parts') % part_count 590 txt = _( 591 '%s (%s) #%s\n' 592 '\n' 593 ' Created: %s\n' 594 ' Episode: %s\n' 595 '%s' 596 '%s' 597 ) % ( 598 self._payload[self._idx['l10n_type']], 599 parts, 600 self._payload[self._idx['pk_doc']], 601 gmDateTime.pydt_strftime(self._payload[self._idx['clin_when']], format = '%Y %B %d', accuracy = gmDateTime.acc_days), 602 self._payload[self._idx['episode']], 603 gmTools.coalesce(self._payload[self._idx['ext_ref']], u'', _(' External reference: %s\n')), 604 gmTools.coalesce(self._payload[self._idx['comment']], u'', u' %s') 605 ) 606 return txt
607 #------------------------------------------------------------
608 -def create_document(document_type=None, encounter=None, episode=None):
609 """Returns new document instance or raises an exception. 610 """ 611 cmd = u"""INSERT INTO blobs.doc_med (fk_type, fk_encounter, fk_episode) VALUES (%(type)s, %(enc)s, %(epi)s) RETURNING pk""" 612 try: 613 int(document_type) 614 except ValueError: 615 cmd = u""" 616 INSERT INTO blobs.doc_med ( 617 fk_type, 618 fk_encounter, 619 fk_episode 620 ) VALUES ( 621 coalesce ( 622 (SELECT pk from blobs.doc_type bdt where bdt.name = %(type)s), 623 (SELECT pk from blobs.doc_type bdt where _(bdt.name) = %(type)s) 624 ), 625 %(enc)s, 626 %(epi)s 627 ) RETURNING pk""" 628 629 args = {'type': document_type, 'enc': encounter, 'epi': episode} 630 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 631 doc = cDocument(aPK_obj = rows[0][0]) 632 return doc
633 #------------------------------------------------------------
634 -def search_for_document(patient_id=None, type_id=None):
635 """Searches for documents with the given patient and type ID. 636 637 No type ID returns all documents for the patient. 638 """ 639 # sanity checks 640 if patient_id is None: 641 raise ValueError('need patient id to search for document') 642 643 args = {'pat_id': patient_id, 'type_id': type_id} 644 if type_id is None: 645 cmd = u"SELECT pk_doc from blobs.v_doc_med WHERE pk_patient = %(pat_id)s" 646 else: 647 cmd = u"SELECT pk_doc from blobs.v_doc_med WHERE pk_patient = %(pat_id)s and pk_type = %(type_id)s" 648 649 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}]) 650 651 docs = [] 652 for row in rows: 653 docs.append(cDocument(row[0])) 654 return docs
655 #------------------------------------------------------------
656 -def delete_document(document_id=None, encounter_id=None):
657 # will cascade to doc_obj and doc_desc 658 cmd = u"select blobs.delete_document(%(pk)s, %(enc)s)" 659 args = {'pk': document_id, 'enc': encounter_id} 660 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 661 return
662 #------------------------------------------------------------
663 -def reclassify_documents_by_type(original_type=None, target_type=None):
664 665 _log.debug('reclassifying documents by type') 666 _log.debug('original: %s', original_type) 667 _log.debug('target: %s', target_type) 668 669 if target_type['pk_doc_type'] == original_type['pk_doc_type']: 670 return True 671 672 cmd = u""" 673 update blobs.doc_med set 674 fk_type = %(new_type)s 675 where 676 fk_type = %(old_type)s 677 """ 678 args = {u'new_type': target_type['pk_doc_type'], u'old_type': original_type['pk_doc_type']} 679 680 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 681 682 return True
683 684 #============================================================
685 -class cDocumentType(gmBusinessDBObject.cBusinessDBObject):
686 """Represents a document type.""" 687 _cmd_fetch_payload = u"""select * from blobs.v_doc_type where pk_doc_type=%s""" 688 _cmds_store_payload = [ 689 u"""update blobs.doc_type set 690 name = %(type)s 691 where 692 pk=%(pk_obj)s and 693 xmin=%(xmin_doc_type)s""", 694 u"""select xmin_doc_type from blobs.v_doc_type where pk_doc_type = %(pk_obj)s""" 695 ] 696 _updatable_fields = ['type'] 697 #--------------------------------------------------------
698 - def set_translation(self, translation=None):
699 700 if translation.strip() == '': 701 return False 702 703 if translation.strip() == self._payload[self._idx['l10n_type']].strip(): 704 return True 705 706 rows, idx = gmPG2.run_rw_queries ( 707 queries = [ 708 {'cmd': u'select i18n.i18n(%s)', 'args': [self._payload[self._idx['type']]]}, 709 {'cmd': u'select i18n.upd_tx((select i18n.get_curr_lang()), %(orig)s, %(tx)s)', 710 'args': { 711 'orig': self._payload[self._idx['type']], 712 'tx': translation 713 } 714 } 715 ], 716 return_data = True 717 ) 718 if not rows[0][0]: 719 _log.error('cannot set translation to [%s]' % translation) 720 return False 721 722 return self.refetch_payload()
723 724 #------------------------------------------------------------
725 -def get_document_types():
726 rows, idx = gmPG2.run_ro_queries ( 727 queries = [{'cmd': u"SELECT * FROM blobs.v_doc_type"}], 728 get_col_idx = True 729 ) 730 doc_types = [] 731 for row in rows: 732 row_def = { 733 'pk_field': 'pk_doc_type', 734 'idx': idx, 735 'data': row 736 } 737 doc_types.append(cDocumentType(row = row_def)) 738 return doc_types
739 #------------------------------------------------------------
740 -def create_document_type(document_type=None):
741 # check for potential dupes: 742 cmd = u'select pk from blobs.doc_type where name = %s' 743 rows, idx = gmPG2.run_ro_queries ( 744 queries = [{'cmd': cmd, 'args': [document_type]}] 745 ) 746 if len(rows) == 0: 747 cmd1 = u"insert into blobs.doc_type (name) values (%s)" 748 cmd2 = u"select currval('blobs.doc_type_pk_seq')" 749 rows, idx = gmPG2.run_rw_queries ( 750 queries = [ 751 {'cmd': cmd1, 'args': [document_type]}, 752 {'cmd': cmd2} 753 ], 754 return_data = True 755 ) 756 return cDocumentType(aPK_obj = rows[0][0])
757 #------------------------------------------------------------
758 -def delete_document_type(document_type=None):
759 if document_type['is_in_use']: 760 return False 761 gmPG2.run_rw_queries ( 762 queries = [{ 763 'cmd': u'delete from blobs.doc_type where pk=%s', 764 'args': [document_type['pk_doc_type']] 765 }] 766 ) 767 return True
768 #------------------------------------------------------------
769 -def get_ext_ref():
770 """This needs *considerably* more smarts.""" 771 dirname = gmTools.get_unique_filename ( 772 prefix = '', 773 suffix = time.strftime(".%Y%m%d-%H%M%S", time.localtime()) 774 ) 775 # extract name for dir 776 path, doc_ID = os.path.split(dirname) 777 return doc_ID
778 #============================================================ 779 # main 780 #------------------------------------------------------------ 781 if __name__ == '__main__': 782 783 if len(sys.argv) < 2: 784 sys.exit() 785 786 if sys.argv[1] != u'test': 787 sys.exit() 788 789 #--------------------------------------------------------
790 - def test_doc_types():
791 792 print "----------------------" 793 print "listing document types" 794 print "----------------------" 795 796 for dt in get_document_types(): 797 print dt 798 799 print "------------------------------" 800 print "testing document type handling" 801 print "------------------------------" 802 803 dt = create_document_type(document_type = 'dummy doc type for unit test 1') 804 print "created:", dt 805 806 dt['type'] = 'dummy doc type for unit test 2' 807 dt.save_payload() 808 print "changed base name:", dt 809 810 dt.set_translation(translation = 'Dummy-Dokumenten-Typ fuer Unit-Test') 811 print "translated:", dt 812 813 print "deleted:", delete_document_type(document_type = dt) 814 815 return
816 #--------------------------------------------------------
817 - def test_adding_doc_part():
818 819 print "-----------------------" 820 print "testing document import" 821 print "-----------------------" 822 823 docs = search_for_document(patient_id=12) 824 doc = docs[0] 825 print "adding to doc:", doc 826 827 fname = sys.argv[1] 828 print "adding from file:", fname 829 part = doc.add_part(file=fname) 830 print "new part:", part 831 832 return
833 #--------------------------------------------------------
834 - def test_get_documents():
835 doc_folder = cDocumentFolder(aPKey=12) 836 837 #photo = doc_folder.get_latest_mugshot() 838 #print type(photo), photo 839 840 docs = doc_folder.get_documents() 841 for doc in docs: 842 print type(doc), doc 843 print doc.parts
844 #pprint(gmBusinessDBObject.jsonclasshintify(docs)) 845 #-------------------------------------------------------- 846 from Gnumed.pycommon import gmI18N 847 gmI18N.activate_locale() 848 gmI18N.install_domain() 849 850 #test_doc_types() 851 #test_adding_doc_part() 852 test_get_documents() 853 854 # print get_ext_ref() 855 856 #============================================================ 857