| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf8 -*-
2 """Timeline exporter.
3
4 Copyright: authors
5 """
6 #============================================================
7 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
8 __license__ = 'GPL v2 or later (details at http://www.gnu.org)'
9
10 import sys
11 import logging
12 import codecs
13 import os
14
15
16 if __name__ == '__main__':
17 sys.path.insert(0, '../../')
18 from Gnumed.pycommon import gmTools
19 from Gnumed.pycommon import gmDateTime
20
21
22 _log = logging.getLogger('gm.tl')
23
24 #============================================================
25 xml_start = u"""<?xml version="1.0" encoding="utf-8"?>
26 <timeline>
27 <version>0.17.0</version>
28 <categories>
29 <!-- health issues -->
30 <category>
31 <name>%s</name>
32 <color>255,0,0</color>
33 <font_color>0,0,0</font_color>
34 </category>
35 <!-- episodes -->
36 <category>
37 <name>%s</name>
38 <color>0,255,0</color>
39 <font_color>0,0,0</font_color>
40 </category>
41 <!-- encounters -->
42 <category>
43 <name>%s</name>
44 <color>30,144,255</color>
45 <font_color>0,0,0</font_color>
46 </category>
47 <!-- hospital stays -->
48 <category>
49 <name>%s</name>
50 <color>255,255,0</color>
51 <font_color>0,0,0</font_color>
52 </category>
53 <!-- procedures -->
54 <category>
55 <name>%s</name>
56 <color>160,32,140</color>
57 <font_color>0,0,0</font_color>
58 </category>
59 <!-- documents -->
60 <category>
61 <name>%s</name>
62 <color>255,165,0</color>
63 <font_color>0,0,0</font_color>
64 </category>
65 <!-- vaccinations -->
66 <category>
67 <name>%s</name>
68 <color>144,238,144</color>
69 <font_color>0,0,0</font_color>
70 </category>
71 <!-- substance intake -->
72 <category>
73 <name>%s</name>
74 <color>165,42,42</color>
75 <font_color>0,0,0</font_color>
76 </category>
77 <!-- life events -->
78 <category>
79 <name>%s</name>
80 <color>30,144,255</color>
81 <font_color>0,0,0</font_color>
82 </category>
83 </categories>
84 <events>"""
85
86 xml_end = u"""
87 </events>
88 <view>
89 <displayed_period>
90 <start>%s</start>
91 <end>%s</end>
92 </displayed_period>
93 <hidden_categories>
94 </hidden_categories>
95 </view>
96 </timeline>"""
97
98 #============================================================
101
102 #------------------------------------------------------------
103 # health issues
104 #------------------------------------------------------------
105 __xml_issue_template = u"""
106 <event>
107 <start>%s</start>
108 <end>%s</end>
109 <text>%s</text>
110 <fuzzy>False</fuzzy>
111 <locked>True</locked>
112 <ends_today>%s</ends_today>
113 <category>%s</category>
114 <description>%s
115 </description>
116 </event>"""
117
119 tooltip = issue.format (
120 patient = patient,
121 with_summary = True,
122 with_codes = True,
123 with_episodes = True,
124 with_encounters = False,
125 with_medications = False,
126 with_hospital_stays = False,
127 with_procedures = False,
128 with_family_history = False,
129 with_documents = False,
130 with_tests = False,
131 with_vaccinations = False
132 )
133 safe_start = issue.safe_start_date
134 possible_start = issue.possible_start_date
135 txt = u''
136 if possible_start < safe_start:
137 txt += __xml_issue_template % (
138 format_pydt(possible_start), # start
139 format_pydt(safe_start), # end
140 gmTools.xml_escape_string(u'?[%s]?' % issue['description']), # text
141 u'False', # ends_today
142 _('Health issues'), # category
143 gmTools.xml_escape_string(tooltip) # description
144 )
145 txt += __xml_issue_template % (
146 format_pydt(safe_start), # start
147 format_pydt(issue.end_date), # end
148 gmTools.xml_escape_string(issue['description']), # text
149 gmTools.bool2subst(issue['is_active'], u'True', u'False'), # ends_today
150 _('Health issues'), # category
151 gmTools.xml_escape_string(tooltip) # description
152 )
153 return txt
154 #------------------------------------------------------------
155 # episodes
156 #------------------------------------------------------------
157 __xml_episode_template = u"""
158 <event>
159 <start>%s</start>
160 <end>%s</end>
161 <text>%s</text>
162 <fuzzy>False</fuzzy>
163 <locked>True</locked>
164 <ends_today>%s</ends_today>
165 <category>%s</category>
166 <description>%s
167 </description>
168 </event>"""
169
171 end = gmTools.bool2subst (
172 episode['episode_open'],
173 format_pydt(now),
174 format_pydt(episode.latest_access_date),
175 )
176 return __xml_episode_template % (
177 format_pydt(episode.best_guess_start_date), # start
178 end, # end
179 gmTools.xml_escape_string(episode['description']), # text
180 gmTools.bool2subst(episode['episode_open'], u'True', u'False'), # ends_today
181 _('Episodes'), # category
182 gmTools.xml_escape_string(episode.format ( # description
183 patient = patient,
184 with_summary = True,
185 with_codes = True,
186 with_encounters = True,
187 with_documents = False,
188 with_hospital_stays = False,
189 with_procedures = False,
190 with_family_history = False,
191 with_tests = False,
192 with_vaccinations = False,
193 with_health_issue = True
194 ))
195 )
196
197 #------------------------------------------------------------
198 # encounters
199 #------------------------------------------------------------
200 __xml_encounter_template = u"""
201 <event>
202 <start>%s</start>
203 <end>%s</end>
204 <text>%s</text>
205 <fuzzy>False</fuzzy>
206 <locked>True</locked>
207 <ends_today>False</ends_today>
208 <category>%s</category>
209 <description>%s
210 </description>
211 </event>"""
212
214 return __xml_encounter_template % (
215 format_pydt(encounter['started']),
216 format_pydt(encounter['last_affirmed']),
217 #u'(%s)' % encounter['pk_episode'],
218 gmTools.xml_escape_string(format_pydt(encounter['started'], format = '%b %d')),
219 _('Encounters'), # category
220 gmTools.xml_escape_string(encounter.format (
221 patient = patient,
222 with_soap = True,
223 with_docs = False,
224 with_tests = False,
225 fancy_header = False,
226 with_vaccinations = False,
227 with_co_encountlet_hints = False,
228 with_rfe_aoe = True,
229 with_family_history = False
230 ))
231 )
232
233 #------------------------------------------------------------
234 # hospital stays
235 #------------------------------------------------------------
236 __xml_hospital_stay_template = u"""
237 <event>
238 <start>%s</start>
239 <end>%s</end>
240 <text>%s</text>
241 <fuzzy>False</fuzzy>
242 <locked>True</locked>
243 <ends_today>False</ends_today>
244 <category>%s</category>
245 <description>%s
246 </description>
247 </event>"""
248
250 end = stay['discharge']
251 if end is None:
252 end = now
253 return __xml_hospital_stay_template % (
254 format_pydt(stay['admission']),
255 format_pydt(end),
256 gmTools.xml_escape_string(stay['hospital']),
257 _('Hospital stays'), # category
258 gmTools.xml_escape_string(stay.format())
259 )
260
261 #------------------------------------------------------------
262 # procedures
263 #------------------------------------------------------------
264 __xml_procedure_template = u"""
265 <event>
266 <start>%s</start>
267 <end>%s</end>
268 <text>%s</text>
269 <fuzzy>False</fuzzy>
270 <locked>True</locked>
271 <ends_today>False</ends_today>
272 <category>%s</category>
273 <description>%s
274 </description>
275 </event>"""
276
278 if proc['is_ongoing']:
279 end = now
280 else:
281 if proc['clin_end'] is None:
282 end = proc['clin_when']
283 else:
284 end = proc['clin_end']
285 return __xml_procedure_template % (
286 format_pydt(proc['clin_when']),
287 format_pydt(end),
288 gmTools.xml_escape_string(proc['performed_procedure']),
289 _('Procedures'),
290 gmTools.xml_escape_string(proc.format (
291 include_episode = True,
292 include_codes = True
293 ))
294 )
295
296 #------------------------------------------------------------
297 # documents
298 #------------------------------------------------------------
299 __xml_document_template = u"""
300 <event>
301 <start>%s</start>
302 <end>%s</end>
303 <text>%s</text>
304 <fuzzy>False</fuzzy>
305 <locked>True</locked>
306 <ends_today>False</ends_today>
307 <category>%s</category>
308 <description>%s
309 </description>
310 </event>"""
311
313 return __xml_document_template % (
314 format_pydt(doc['clin_when']),
315 format_pydt(doc['clin_when']),
316 gmTools.xml_escape_string(doc['l10n_type']),
317 _('Documents'),
318 gmTools.xml_escape_string(doc.format())
319 )
320
321 #------------------------------------------------------------
322 # vaccinations
323 #------------------------------------------------------------
324 __xml_vaccination_template = u"""
325 <event>
326 <start>%s</start>
327 <end>%s</end>
328 <text>%s</text>
329 <fuzzy>False</fuzzy>
330 <locked>True</locked>
331 <ends_today>False</ends_today>
332 <category>%s</category>
333 <description>%s
334 </description>
335 </event>"""
336
338 return __xml_vaccination_template % (
339 format_pydt(vacc['date_given']),
340 format_pydt(vacc['date_given']),
341 gmTools.xml_escape_string(vacc['vaccine']),
342 _('Vaccinations'),
343 gmTools.xml_escape_string(u'\n'.join(vacc.format (
344 with_indications = True,
345 with_comment = True,
346 with_reaction = True,
347 date_format = '%Y %b %d'
348 )))
349 )
350
351 #------------------------------------------------------------
352 # substance intakt
353 #------------------------------------------------------------
354 __xml_intake_template = u"""
355 <event>
356 <start>%s</start>
357 <end>%s</end>
358 <text>%s</text>
359 <fuzzy>False</fuzzy>
360 <locked>True</locked>
361 <ends_today>False</ends_today>
362 <category>%s</category>
363 <description>%s
364 </description>
365 </event>"""
366
368 if intake['discontinued'] is None:
369 if intake['duration'] is None:
370 if intake['seems_inactive']:
371 end = intake['started']
372 else:
373 end = now
374 else:
375 end = intake['started'] + intake['duration']
376 else:
377 end = intake['discontinued']
378
379 return __xml_intake_template % (
380 format_pydt(intake['started']),
381 format_pydt(end),
382 gmTools.xml_escape_string(intake['substance']),
383 _('Substances'),
384 gmTools.xml_escape_string(intake.format (
385 one_line = False,
386 show_all_brand_components = False
387 ))
388 )
389
390 #------------------------------------------------------------
391 # library entry point
392 #------------------------------------------------------------
394
395 emr = patient.emr
396 global now
397 now = gmDateTime.pydt_now_here()
398
399 if filename is None:
400 timeline_fname = gmTools.get_unique_filename(prefix = u'gm-', suffix = u'.timeline')
401 else:
402 timeline_fname = filename
403 _log.debug('exporting EMR as timeline into [%s]', timeline_fname)
404 timeline = codecs.open(timeline_fname, mode = 'wb', encoding = 'utf8', errors = 'xmlcharrefreplace')
405 timeline.write(xml_start % (
406 _('Health issues'),
407 _('Episodes'),
408 _('Encounters'),
409 _('Hospital stays'),
410 _('Procedures'),
411 _('Documents'),
412 _('Vaccinations'),
413 _('Substances'),
414 _('Life events')
415 ))
416 # birth
417 if patient['dob'] is None:
418 start = now.replace(year = now.year - 100)
419 timeline.write(__xml_encounter_template % (
420 format_pydt(start),
421 format_pydt(start),
422 _('Birth') + u': ?',
423 _('Life events'),
424 _('Date of birth unknown')
425 ))
426 else:
427 start = patient['dob']
428 timeline.write(__xml_encounter_template % (
429 format_pydt(patient['dob']),
430 format_pydt(patient['dob']),
431 _('Birth') + gmTools.bool2subst(patient['dob_is_estimated'], u' (%s)' % gmTools.u_almost_equal_to, u''),
432 _('Life events'),
433 u''
434 ))
435
436 # start of care
437 timeline.write(__xml_encounter_template % (
438 format_pydt(emr.earliest_care_date),
439 format_pydt(emr.earliest_care_date),
440 _('Start of Care'),
441 _('Life events'),
442 _('The earliest recorded event of care in this praxis.')
443 ))
444
445 timeline.write(u'\n<!--\n========================================\n Health issues\n======================================== -->')
446 for issue in emr.health_issues:
447 timeline.write(__format_health_issue_as_timeline_xml(issue, patient, emr))
448
449 timeline.write(u'\n<!--\n========================================\n Episodes\n======================================== -->')
450 for epi in emr.get_episodes(order_by = u'pk_health_issue'):
451 timeline.write(__format_episode_as_timeline_xml(epi, patient))
452
453 timeline.write(u'\n<!--\n========================================\n Encounters\n======================================== -->')
454 for enc in emr.get_encounters(skip_empty = True):
455 timeline.write(__format_encounter_as_timeline_xml(enc, patient))
456
457 timeline.write(u'\n<!--\n========================================\n Hospital stays\n======================================== -->')
458 for stay in emr.hospital_stays:
459 timeline.write(__format_hospital_stay_as_timeline_xml(stay))
460
461 timeline.write(u'\n<!--\n========================================\n Procedures\n======================================== -->')
462 for proc in emr.performed_procedures:
463 timeline.write(__format_procedure_as_timeline_xml(proc))
464
465 timeline.write(u'\n<!--\n========================================\n Vaccinations\n======================================== -->')
466 for vacc in emr.vaccinations:
467 timeline.write(__format_vaccination_as_timeline_xml(vacc))
468
469 timeline.write(u'\n<!--\n========================================\n Substance intakes\n======================================== -->')
470 for intake in emr.get_current_substance_intakes(include_inactive = True, include_unapproved = False):
471 timeline.write(__format_intake_as_timeline_xml(intake))
472
473 timeline.write(u'\n<!--\n========================================\n Documents\n======================================== -->')
474 for doc in patient.document_folder.documents:
475 timeline.write(__format_document_as_timeline_xml(doc))
476
477 # allergies ?
478 # test results ?
479
480 # death
481 if patient['deceased'] is None:
482 end = now
483 else:
484 end = patient['deceased']
485 timeline.write(__xml_encounter_template % (
486 format_pydt(end),
487 format_pydt(end),
488 #u'',
489 _('Death'),
490 _('Life events'),
491 u''
492 ))
493
494 # display range
495 if end.month == 12:
496 # both January and December feature 31 days, so no worry
497 end = end.replace(month = 1)
498 else:
499 # be careful about the target month being
500 # shorter than the source month
501 real_day = end.day
502 target_month = end.month + 1
503 end = end.replace(day = 28)
504 end = end.replace(month = target_month)
505 end = end.replace(day = min(real_day, gmDateTime.gregorian_month_length[target_month]))
506 timeline.write(xml_end % (
507 format_pydt(start),
508 format_pydt(end)
509 ))
510 timeline.close()
511 return timeline_fname
512
513 #------------------------------------------------------------
514 __fake_timeline_start = u"""<?xml version="1.0" encoding="utf-8"?>
515 <timeline>
516 <version>0.20.0</version>
517 <categories>
518 <!-- life events -->
519 <category>
520 <name>%s</name>
521 <color>30,144,255</color>
522 <font_color>0,0,0</font_color>
523 </category>
524 </categories>
525 <events>""" % _('Life events')
526
527 __fake_timeline_body_template = u"""
528 <event>
529 <start>%s</start>
530 <end>%s</end>
531 <text>%s</text>
532 <fuzzy>False</fuzzy>
533 <locked>True</locked>
534 <ends_today>False</ends_today>
535 <!-- category></category -->
536 <description>%s
537 </description>
538 </event>"""
539
541
542 emr = patient.emr
543 global now
544 now = gmDateTime.pydt_now_here()
545
546 if filename is None:
547 timeline_fname = gmTools.get_unique_filename(prefix = u'gm-', suffix = u'.timeline')
548 else:
549 timeline_fname = filename
550
551 _log.debug('creating dummy timeline in [%s]', timeline_fname)
552 timeline = codecs.open(timeline_fname, mode = 'wb', encoding = 'utf8', errors = 'xmlcharrefreplace')
553
554 timeline.write(__fake_timeline_start)
555
556 # birth
557 if patient['dob'] is None:
558 start = now.replace(year = now.year - 100)
559 timeline.write(__xml_encounter_template % (
560 format_pydt(start),
561 format_pydt(start),
562 _('Birth') + u': ?',
563 _('Life events'),
564 _('Date of birth unknown')
565 ))
566 else:
567 start = patient['dob']
568 timeline.write(__xml_encounter_template % (
569 format_pydt(patient['dob']),
570 format_pydt(patient['dob']),
571 _('Birth') + gmTools.bool2subst(patient['dob_is_estimated'], u' (%s)' % gmTools.u_almost_equal_to, u''),
572 _('Life events'),
573 u''
574 ))
575
576 # death
577 if patient['deceased'] is None:
578 end = now
579 else:
580 end = patient['deceased']
581 timeline.write(__xml_encounter_template % (
582 format_pydt(end),
583 format_pydt(end),
584 #u'',
585 _('Death'),
586 _('Life events'),
587 u''
588 ))
589
590 # fake issue
591 timeline.write(__fake_timeline_body_template % (
592 format_pydt(start),
593 format_pydt(end),
594 _('Cannot display timeline.'),
595 _('Cannot display timeline.')
596 ))
597
598 # display range
599 if end.month == 12:
600 # both January and December feature 31 days, so no worry
601 end = end.replace(month = 1)
602 else:
603 # be careful about the target month being
604 # shorter than the source month
605 real_day = end.day
606 target_month = end.month + 1
607 end = end.replace(day = 28)
608 end = end.replace(month = target_month)
609 end = end.replace(day = min(real_day, gmDateTime.gregorian_month_length[target_month]))
610 timeline.write(xml_end % (
611 format_pydt(start),
612 format_pydt(end)
613 ))
614
615 timeline.close()
616 return timeline_fname
617
618 #============================================================
619 # main
620 #------------------------------------------------------------
621 if __name__ == '__main__':
622
623 if len(sys.argv) < 2:
624 sys.exit()
625
626 if sys.argv[1] != "test":
627 sys.exit()
628
629 from Gnumed.pycommon import gmI18N
630 gmI18N.activate_locale()
631 gmI18N.install_domain('gnumed')
632 from Gnumed.business import gmPerson
633 # 14 / 20 / 138 / 58 / 20 / 5
634 pat = gmPerson.gmCurrentPatient(gmPerson.cPatient(aPK_obj = 12))
635 fname = u'~/tmp/gm2tl-%s.timeline' % pat.get_dirname()
636
637 print create_timeline_file(patient = pat, filename = os.path.expanduser(fname))
638
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Jul 12 03:56:40 2013 | http://epydoc.sourceforge.net |