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