| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed medication/substances handling widgets.
2 """
3 #================================================================
4 __version__ = "$Revision: 1.33 $"
5 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
6
7 import logging, sys, os.path, webbrowser
8
9
10 import wx, wx.grid
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmDispatcher, gmCfg, gmShellAPI, gmTools, gmDateTime
16 from Gnumed.pycommon import gmMatchProvider, gmI18N, gmPrinting, gmCfg2
17 from Gnumed.business import gmPerson, gmATC, gmSurgery, gmMedication, gmForms
18 from Gnumed.wxpython import gmGuiHelpers, gmRegetMixin, gmAuthWidgets, gmEditArea, gmMacro
19 from Gnumed.wxpython import gmCfgWidgets, gmListWidgets, gmPhraseWheel, gmFormWidgets
20 from Gnumed.wxpython import gmAllergyWidgets
21
22
23 _log = logging.getLogger('gm.ui')
24 _log.info(__version__)
25
26 #============================================================
27 # ATC related widgets
28 #============================================================
29
31
32 if parent is None:
33 parent = wx.GetApp().GetTopWindow()
34 #------------------------------------------------------------
35 def refresh(lctrl):
36 atcs = gmATC.get_reference_atcs()
37
38 items = [ [
39 a['atc'],
40 a['term'],
41 u'%s' % gmTools.coalesce(a['ddd'], u''),
42 gmTools.coalesce(a['unit'], u''),
43 gmTools.coalesce(a['administrative_route'], u''),
44 gmTools.coalesce(a['comment'], u''),
45 a['version'],
46 a['lang']
47 ] for a in atcs ]
48 lctrl.set_string_items(items)
49 lctrl.set_data(atcs)
50 #------------------------------------------------------------
51 gmListWidgets.get_choices_from_list (
52 parent = parent,
53 msg = _('\nThe ATC codes as known to GNUmed.\n'),
54 caption = _('Showing ATC codes.'),
55 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
56 single_selection = True,
57 refresh_callback = refresh
58 )
59
60 #============================================================
61
63
64 dlg = wx.FileDialog (
65 parent = None,
66 message = _('Choose an ATC import config file'),
67 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
68 defaultFile = '',
69 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
70 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
71 )
72
73 result = dlg.ShowModal()
74 if result == wx.ID_CANCEL:
75 return
76
77 cfg_file = dlg.GetPath()
78 dlg.Destroy()
79
80 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
81 if conn is None:
82 return False
83
84 wx.BeginBusyCursor()
85
86 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
87 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
88 else:
89 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
90
91 wx.EndBusyCursor()
92 return True
93
94 #============================================================
95
97
99
100 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
101
102 query = u"""
103
104 SELECT DISTINCT ON (label)
105 atc_code,
106 label
107 FROM (
108
109 SELECT
110 code as atc_code,
111 (code || ': ' || term || coalesce(' (' || ddd || unit || ')', ''))
112 AS label
113 FROM ref.atc
114 WHERE
115 term %(fragment_condition)s
116 OR
117 code %(fragment_condition)s
118
119 UNION ALL
120
121 SELECT
122 atc_code,
123 (atc_code || ': ' || description)
124 AS label
125 FROM ref.substance_in_brand
126 WHERE
127 description %(fragment_condition)s
128 OR
129 atc_code %(fragment_condition)s
130
131 UNION ALL
132
133 SELECT
134 atc_code,
135 (atc_code || ': ' || description || ' (' || preparation || ')')
136 AS label
137 FROM ref.branded_drug
138 WHERE
139 description %(fragment_condition)s
140 OR
141 atc_code %(fragment_condition)s
142
143 -- it would be nice to be able to include clin.vacc_indication but that's hard to do in SQL
144
145 ) AS candidates
146
147 ORDER BY label
148 LIMIT 50"""
149
150 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
151 mp.setThresholds(1, 2, 4)
152 # mp.word_separators = '[ \t=+&:@]+'
153 self.SetToolTipString(_('Select an ATC (Anatomical-Therapeutic-Chemical) code.'))
154 self.matcher = mp
155 self.selection_only = True
156
157 #============================================================
158 #============================================================
159
161
162 if parent is None:
163 parent = wx.GetApp().GetTopWindow()
164
165 #------------------------------------------------------------
166 def delete(component):
167 gmMedication.delete_component_from_branded_drug (
168 brand = component['pk_brand'],
169 component = component['pk_substance_in_brand']
170 )
171 return True
172 #------------------------------------------------------------
173 def refresh(lctrl):
174 substs = gmMedication.get_substances_in_brands()
175 items = [ [
176 u'%s%s' % (s['brand'], gmTools.coalesce(s['atc_brand'], u'', u' (%s)')),
177 s['substance'],
178 gmTools.coalesce(s['atc_substance'], u''),
179 s['preparation'],
180 gmTools.coalesce(s['external_code_brand'], u'', u'%%s [%s]' % s['external_code_type_brand']),
181 s['pk_substance_in_brand']
182 ] for s in substs ]
183 lctrl.set_string_items(items)
184 lctrl.set_data(substs)
185 #------------------------------------------------------------
186 msg = _('\nThese are the substances in the drug brands known to GNUmed.\n')
187
188 gmListWidgets.get_choices_from_list (
189 parent = parent,
190 msg = msg,
191 caption = _('Showing drug brand components (substances).'),
192 columns = [_('Brand'), _('Substance'), u'ATC', _('Preparation'), _('Code'), u'#'],
193 single_selection = True,
194 #new_callback = new,
195 #edit_callback = edit,
196 delete_callback = delete,
197 refresh_callback = refresh
198 )
199 #============================================================
201
202 if parent is None:
203 parent = wx.GetApp().GetTopWindow()
204 #------------------------------------------------------------
205 def delete(brand):
206 if brand.is_vaccine:
207 gmGuiHelpers.gm_show_info (
208 aTitle = _('Deleting medication'),
209 aMessage = _(
210 'Cannot delete the medication\n'
211 '\n'
212 ' "%s" (%s)\n'
213 '\n'
214 'because it is a vaccine. Please delete it\n'
215 'from the vaccine management section !\n'
216 ) % (brand['description'], brand['preparation'])
217 )
218 return False
219 gmMedication.delete_branded_drug(brand = brand['pk'])
220 return True
221 #------------------------------------------------------------
222 def new():
223 drug_db = get_drug_database(parent = parent)
224
225 if drug_db is None:
226 return False
227
228 drug_db.import_drugs()
229
230 return True
231 #------------------------------------------------------------
232 def refresh(lctrl):
233 drugs = gmMedication.get_branded_drugs()
234 items = [ [
235 d['description'],
236 d['preparation'],
237 gmTools.coalesce(d['atc_code'], u''),
238 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
239 d['pk']
240 ] for d in drugs ]
241 lctrl.set_string_items(items)
242 lctrl.set_data(drugs)
243 #------------------------------------------------------------
244 msg = _('\nThese are the drug brands known to GNUmed.\n')
245
246 gmListWidgets.get_choices_from_list (
247 parent = parent,
248 msg = msg,
249 caption = _('Showing branded drugs.'),
250 columns = [_('Name'), _('Preparation'), _('ATC'), _('Code'), u'#'],
251 single_selection = True,
252 refresh_callback = refresh,
253 new_callback = new,
254 #edit_callback = edit,
255 delete_callback = delete
256 )
257 #============================================================
259
260 if parent is None:
261 parent = wx.GetApp().GetTopWindow()
262 #------------------------------------------------------------
263 def delete(substance):
264 gmMedication.delete_used_substance(substance = substance['pk'])
265 return True
266 #------------------------------------------------------------
267 def new():
268 drug_db = get_drug_database(parent = parent)
269
270 if drug_db is None:
271 return False
272
273 drug_db.import_drugs()
274
275 return True
276 #------------------------------------------------------------
277 def refresh(lctrl):
278 substs = gmMedication.get_substances_in_use()
279 items = [ [
280 s['description'],
281 gmTools.coalesce(s['atc_code'], u''),
282 s['pk']
283 ] for s in substs ]
284 lctrl.set_string_items(items)
285 lctrl.set_data(substs)
286 #------------------------------------------------------------
287 msg = _('\nThese are the substances currently or previously\nconsumed across all patients.\n')
288
289 gmListWidgets.get_choices_from_list (
290 parent = parent,
291 msg = msg,
292 caption = _('Showing consumed substances.'),
293 columns = [_('Name'), _('ATC'), u'#'],
294 single_selection = True,
295 refresh_callback = refresh,
296 new_callback = new,
297 #edit_callback = edit,
298 delete_callback = delete
299 )
300 #============================================================
301 # generic drug database access
302 #============================================================
304 gmCfgWidgets.configure_string_from_list_option (
305 parent = parent,
306 message = _(
307 '\n'
308 'Please select the default drug data source from the list below.\n'
309 '\n'
310 'Note that to actually use it you need to have the database installed, too.'
311 ),
312 option = 'external.drug_data.default_source',
313 bias = 'user',
314 default_value = None,
315 choices = gmMedication.drug_data_source_interfaces.keys(),
316 columns = [_('Drug data source')],
317 data = gmMedication.drug_data_source_interfaces.keys(),
318 caption = _('Configuring default drug data source')
319 )
320 #============================================================
322 dbcfg = gmCfg.cCfgSQL()
323
324 default_db = dbcfg.get2 (
325 option = 'external.drug_data.default_source',
326 workplace = gmSurgery.gmCurrentPractice().active_workplace,
327 bias = 'workplace'
328 )
329
330 if default_db is None:
331 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True)
332 configure_drug_data_source(parent = parent)
333 default_db = dbcfg.get2 (
334 option = 'external.drug_data.default_source',
335 workplace = gmSurgery.gmCurrentPractice().active_workplace,
336 bias = 'workplace'
337 )
338 if default_db is None:
339 gmGuiHelpers.gm_show_error (
340 aMessage = _('There is no default drug database configured.'),
341 aTitle = _('Jumping to drug database')
342 )
343 return None
344
345 try:
346 return gmMedication.drug_data_source_interfaces[default_db]()
347 except KeyError:
348 _log.error('faulty default drug data source configuration: %s', default_db)
349 return None
350
351 #============================================================
353 dbcfg = gmCfg.cCfgSQL()
354 drug_db = get_drug_database()
355 if drug_db is None:
356 return
357 pat = gmPerson.gmCurrentPatient()
358 if pat.connected:
359 drug_db.patient = pat
360 drug_db.switch_to_frontend(blocking = False)
361
362 #============================================================
364
365 dbcfg = gmCfg.cCfgSQL()
366
367 ifap_cmd = dbcfg.get2 (
368 option = 'external.ifap-win.shell_command',
369 workplace = gmSurgery.gmCurrentPractice().active_workplace,
370 bias = 'workplace',
371 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
372 )
373 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
374 if not found:
375 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
376 return False
377 ifap_cmd = binary
378
379 if import_drugs:
380 transfer_file = os.path.expanduser(dbcfg.get2 (
381 option = 'external.ifap-win.transfer_file',
382 workplace = gmSurgery.gmCurrentPractice().active_workplace,
383 bias = 'workplace',
384 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
385 ))
386 # file must exist for Ifap to write into it
387 try:
388 f = open(transfer_file, 'w+b').close()
389 except IOError:
390 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
391 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
392 return False
393
394 wx.BeginBusyCursor()
395 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
396 wx.EndBusyCursor()
397
398 if import_drugs:
399 # COMMENT: this file must exist PRIOR to invoking IFAP
400 # COMMENT: or else IFAP will not write data into it ...
401 try:
402 csv_file = open(transfer_file, 'rb') # FIXME: encoding
403 except:
404 _log.exception('cannot access [%s]', fname)
405 csv_file = None
406
407 if csv_file is not None:
408 import csv
409 csv_lines = csv.DictReader (
410 csv_file,
411 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
412 delimiter = ';'
413 )
414 pat = gmPerson.gmCurrentPatient()
415 emr = pat.get_emr()
416 # dummy episode for now
417 epi = emr.add_episode(episode_name = _('Current medication'))
418 for line in csv_lines:
419 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
420 line['Packungszahl'].strip(),
421 line['Handelsname'].strip(),
422 line['Form'].strip(),
423 line[u'Packungsgr\xf6\xdfe'].strip(),
424 line['Abpackungsmenge'].strip(),
425 line['Einheit'].strip(),
426 line['Hersteller'].strip(),
427 line['PZN'].strip()
428 )
429 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
430 csv_file.close()
431
432 return True
433
434 #============================================================
435 # current substance intake handling
436 #============================================================
438
440
441 query = u"""
442 SELECT schedule as sched, schedule
443 FROM clin.substance_intake
444 where schedule %(fragment_condition)s
445 ORDER BY sched
446 LIMIT 50"""
447
448 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
449 mp.setThresholds(1, 2, 4)
450 mp.word_separators = '[ \t=+&:@]+'
451 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
452 self.SetToolTipString(_('The schedule for taking this substance.'))
453 self.matcher = mp
454 self.selection_only = False
455 #============================================================
457
459
460 query = u"""
461 (
462 SELECT preparation as prep, preparation
463 FROM ref.branded_drug
464 where preparation %(fragment_condition)s
465 ) union (
466 SELECT preparation as prep, preparation
467 FROM clin.substance_intake
468 where preparation %(fragment_condition)s
469 )
470 order by prep
471 limit 30"""
472
473 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
474 mp.setThresholds(1, 2, 4)
475 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
476 self.SetToolTipString(_('The preparation (form) of the substance the patient is taking.'))
477 self.matcher = mp
478 self.selection_only = False
479 #============================================================
481
483
484 query = u"""
485 (
486 SELECT pk, (coalesce(atc_code || ': ', '') || description) as subst
487 FROM clin.consumed_substance
488 WHERE description %(fragment_condition)s
489 ) union (
490 SELECT NULL, (coalesce(atc_code || ': ', '') || description) as subst
491 FROM ref.substance_in_brand
492 WHERE description %(fragment_condition)s
493 ) union (
494 SELECT NULL, (atc || ': ' || term) as subst
495 FROM ref.v_atc
496 WHERE
497 is_group_code IS FALSE
498 AND
499 term %(fragment_condition)s
500 )
501 order by subst
502 limit 50"""
503
504 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
505 mp.setThresholds(1, 2, 4)
506 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
507 self.SetToolTipString(_('The INN / substance the patient is taking.'))
508 self.matcher = mp
509 self.selection_only = False
510 #============================================================
512
514
515 query = u"""
516 SELECT
517 pk,
518 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
519 AS brand
520 FROM ref.branded_drug
521 WHERE description %(fragment_condition)s
522 ORDER BY brand
523 LIMIT 50"""
524
525 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
526 mp.setThresholds(2, 3, 4)
527 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
528 self.SetToolTipString(_('The brand name of the drug the patient is taking.'))
529 self.matcher = mp
530 self.selection_only = False
531
532 #============================================================
533 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
534
535 -class cCurrentMedicationEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
536
538
539 try:
540 data = kwargs['substance']
541 del kwargs['substance']
542 except KeyError:
543 data = None
544
545 wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl.__init__(self, *args, **kwargs)
546 gmEditArea.cGenericEditAreaMixin.__init__(self)
547 self.mode = 'new'
548 self.data = data
549 if data is not None:
550 self.mode = 'edit'
551
552 self.__init_ui()
553 #----------------------------------------------------------------
555
556 # adjust phrasewheels
557
558 self._PRW_brand.add_callback_on_lose_focus(callback = self._on_leave_brand)
559 #----------------------------------------------------------------
561 emr = gmPerson.gmCurrentPatient().get_emr()
562
563 state = emr.allergy_state
564 if state['last_confirmed'] is None:
565 confirmed = _('never')
566 else:
567 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
568 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
569 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
570 msg += u'\n'
571
572 for allergy in emr.get_allergies():
573 msg += u'%s (%s, %s): %s\n' % (
574 allergy['descriptor'],
575 allergy['l10n_type'],
576 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
577 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
578 )
579
580 self._LBL_allergies.SetLabel(msg)
581 #----------------------------------------------------------------
583
584 if self._PRW_brand.GetData() is None:
585 self._TCTRL_brand_ingredients.SetValue(u'')
586 if self.data is None:
587 return
588 if self.data['pk_brand'] is None:
589 return
590 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand'])
591
592 brand = gmMedication.cBrandedDrug(aPK_obj = self._PRW_brand.GetData())
593
594 if self.data is None:
595 self._PRW_preparation.SetText(brand['preparation'], None)
596 else:
597 self._PRW_preparation.SetText (
598 gmTools.coalesce(self.data['preparation'], brand['preparation']),
599 self.data['preparation']
600 )
601
602 comps = brand.components
603
604 if comps is None:
605 return
606
607 if len(comps) == 0:
608 return
609
610 comps = u' / '.join([ u'%s%s' % (c['description'], gmTools.coalesce(c['atc_code'], u'', u' (%s)')) for c in comps ])
611 self._TCTRL_brand_ingredients.SetValue(comps)
612 #----------------------------------------------------------------
613 # generic Edit Area mixin API
614 #----------------------------------------------------------------
616
617 validity = True
618
619 if self._PRW_substance.GetValue().strip() == u'':
620 self._PRW_substance.display_as_valid(False)
621 validity = False
622 else:
623 self._PRW_substance.display_as_valid(True)
624
625 if self._PRW_preparation.GetValue().strip() == u'':
626 self._PRW_preparation.display_as_valid(False)
627 validity = False
628 else:
629 self._PRW_preparation.display_as_valid(True)
630
631 if self._CHBOX_approved.IsChecked():
632 if self._PRW_episode.GetValue().strip() == u'':
633 self._PRW_episode.display_as_valid(False)
634 validity = False
635 else:
636 self._PRW_episode.display_as_valid(True)
637
638 if self._CHBOX_approved.IsChecked() is True:
639 self._PRW_duration.display_as_valid(True)
640 else:
641 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
642 self._PRW_duration.display_as_valid(True)
643 else:
644 if gmDateTime.str2interval(self._PRW_duration.GetValue()) is None:
645 self._PRW_duration.display_as_valid(False)
646 validity = False
647 else:
648 self._PRW_duration.display_as_valid(True)
649
650 end = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
651 if end is not None:
652 start = self._DP_started.GetValue(as_pydt = True)
653 if start > end:
654 self._DP_started.display_as_valid(False)
655 self._DP_discontinued.display_as_valid(False)
656 validity = False
657 else:
658 self._DP_started.display_as_valid(True)
659 self._DP_discontinued.display_as_valid(True)
660
661 if validity is False:
662 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save substance intake. Invalid or missing essential input.'))
663
664 return validity
665 #----------------------------------------------------------------
667
668 emr = gmPerson.gmCurrentPatient().get_emr()
669
670 # 1) create substance intake entry
671 if self._PRW_substance.GetData() is None:
672 subst = self._PRW_substance.GetValue().strip()
673 else:
674 # normalize, do not simply re-use name from phrasewheel
675 subst = gmMedication.get_substance_by_pk(pk = self._PRW_substance.GetData())['description']
676
677 intake = emr.add_substance_intake (
678 substance = subst,
679 episode = self._PRW_episode.GetData(can_create = True),
680 preparation = self._PRW_preparation.GetValue()
681 )
682
683 intake['strength'] = self._PRW_strength.GetValue()
684 intake['started'] = self._DP_started.GetValue(as_pydt = True, invalid_as_none = True)
685 intake['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
686 if intake['discontinued'] is None:
687 intake['discontinue_reason'] = None
688 else:
689 intake['discontinue_reason'] = self._PRW_discontinue_reason().GetValue().strip()
690 intake['schedule'] = self._PRW_schedule.GetValue()
691 intake['aim'] = self._PRW_aim.GetValue()
692 intake['notes'] = self._PRW_notes.GetValue()
693 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
694 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
695
696 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
697 intake['duration'] = None
698 else:
699 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
700
701 # 2) create or retrieve brand
702 brand = None
703 pk_brand = self._PRW_brand.GetData()
704
705 # brand pre-selected ?
706 if pk_brand is None:
707 # no, so ...
708 desc = self._PRW_brand.GetValue().strip()
709 if desc != u'':
710 # ... create or get it
711 brand = gmMedication.create_branded_drug (
712 brand_name = desc,
713 preparation = self._PRW_preparation.GetValue().strip(),
714 return_existing = True
715 )
716 pk_brand = brand['pk']
717 else:
718 # yes, so get it
719 brand = gmMedication.cBrandedDrug(aPK_obj = pk_brand)
720
721 # 3) link brand, if available
722 intake['pk_brand'] = pk_brand
723 intake.save()
724
725 # brand neither creatable nor pre-selected
726 if brand is None:
727 self.data = intake
728 return True
729
730 # 4) add substance to brand as component (because
731 # that's effectively what we are saying here)
732 # FIXME: we may want to ask the user here
733 # FIXME: or only do it if there are no components yet
734 if self._PRW_substance.GetData() is None:
735 brand.add_component(substance = self._PRW_substance.GetValue().strip())
736 else:
737 # normalize substance name
738 subst = gmMedication.get_substance_by_pk(pk = self._PRW_substance.GetData())
739 if subst is not None:
740 brand.add_component(substance = subst['description'])
741
742 self.data = intake
743
744 if self._CHBOX_is_allergy.IsChecked():
745 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
746 # open for editing
747 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
748 dlg.ShowModal()
749
750 return True
751 #----------------------------------------------------------------
753
754 if self._PRW_substance.GetData() is None:
755 self.data['pk_substance'] = gmMedication.create_used_substance (
756 substance = self._PRW_substance.GetValue().strip()
757 )['pk']
758 else:
759 self.data['pk_substance'] = self._PRW_substance.GetData()
760
761 self.data['started'] = self._DP_started.GetValue(as_pydt = True, invalid_as_none = True)
762 self.data['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
763 if self.data['discontinued'] is None:
764 self.data['discontinue_reason'] = None
765 else:
766 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
767 self.data['preparation'] = self._PRW_preparation.GetValue()
768 self.data['strength'] = self._PRW_strength.GetValue()
769 self.data['schedule'] = self._PRW_schedule.GetValue()
770 self.data['aim'] = self._PRW_aim.GetValue()
771 self.data['notes'] = self._PRW_notes.GetValue()
772 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
773 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
774 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
775
776 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
777 self.data['duration'] = None
778 else:
779 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
780
781 if self._PRW_brand.GetData() is None:
782 desc = self._PRW_brand.GetValue().strip()
783 if desc != u'':
784 # create or get brand
785 self.data['pk_brand'] = gmMedication.create_branded_drug (
786 brand_name = desc,
787 preparation = self._PRW_preparation.GetValue().strip(),
788 return_existing = True
789 )['pk']
790 else:
791 self.data['pk_brand'] = self._PRW_brand.GetData()
792
793 self.data.save()
794
795 if self._CHBOX_is_allergy.IsChecked():
796 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
797 # open for editing
798 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
799 dlg.ShowModal()
800
801 return True
802 #----------------------------------------------------------------
804 self._PRW_substance.SetText(u'', None)
805 self._PRW_strength.SetText(u'', None)
806 # self._PRW_preparation.SetText(u'', None)
807 self._PRW_schedule.SetText(u'', None)
808 self._PRW_duration.SetText(u'', None)
809 self._PRW_aim.SetText(u'', None)
810 self._PRW_notes.SetText(u'', None)
811 self._PRW_episode.SetText(u'', None)
812
813 self._CHBOX_long_term.SetValue(False)
814 self._CHBOX_approved.SetValue(True)
815
816 self._DP_started.SetValue(gmDateTime.pydt_now_here())
817 self._DP_discontinued.SetValue(None)
818 self._PRW_discontinue_reason.SetValue(u'')
819
820 self.__refresh_brand_and_components()
821 self.__refresh_allergies()
822
823 self._PRW_substance.SetFocus()
824 #----------------------------------------------------------------
826
827 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance'])
828 self._PRW_strength.SetText(gmTools.coalesce(self.data['strength'], u''), self.data['strength'])
829
830 if self.data['is_long_term']:
831 self._CHBOX_long_term.SetValue(True)
832 self._PRW_duration.Enable(False)
833 self._PRW_duration.SetText(gmTools.u_infinity, None)
834 self._BTN_discontinued_as_planned.Enable(False)
835 else:
836 self._CHBOX_long_term.SetValue(False)
837 self._PRW_duration.Enable(True)
838 self._BTN_discontinued_as_planned.Enable(True)
839 if self.data['duration'] is None:
840 self._PRW_duration.SetText(u'', None)
841 else:
842 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
843 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
844 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
845 self._PRW_episode.SetData(self.data['pk_episode'])
846 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
847
848 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
849
850 self._DP_started.SetValue(self.data['started'])
851 self._DP_discontinued.SetValue(self.data['discontinued'])
852 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
853
854 self.__refresh_brand_and_components()
855 self.__refresh_allergies()
856
857 self._PRW_substance.SetFocus()
858 #----------------------------------------------------------------
861 #----------------------------------------------------------------
862 # event handlers
863 #----------------------------------------------------------------
866 #----------------------------------------------------------------
868 if self._DP_discontinued.GetValue() is None:
869 self._PRW_discontinue_reason.Enable(False)
870 self._CHBOX_is_allergy.Enable(False)
871 else:
872 self._PRW_discontinue_reason.Enable(True)
873 self._CHBOX_is_allergy.Enable(True)
874 #----------------------------------------------------------------
893 #----------------------------------------------------------------
915 #----------------------------------------------------------------
944 #----------------------------------------------------------------
946 if self._CHBOX_long_term.IsChecked() is True:
947 self._PRW_duration.Enable(False)
948 self._BTN_discontinued_as_planned.Enable(False)
949 self._PRW_discontinue_reason.Enable(False)
950 self._CHBOX_is_allergy.Enable(False)
951 else:
952 self._PRW_duration.Enable(True)
953 self._BTN_discontinued_as_planned.Enable(True)
954 self._PRW_discontinue_reason.Enable(True)
955 self._CHBOX_is_allergy.Enable(True)
956
957 self.__refresh_allergies()
958 #----------------------------------------------------------------
966 #============================================================
968 delete_it = gmGuiHelpers.gm_show_question (
969 aMessage = _(
970 'Do you really want to remove this substance intake ?\n'
971 '\n'
972 'It may be prudent to edit the details first so as to\n'
973 'leave behind some indication of why it was deleted.\n'
974 ),
975 aTitle = _('Deleting medication / substance intake')
976 )
977 if not delete_it:
978 return
979
980 gmMedication.delete_substance_intake(substance = substance)
981 #------------------------------------------------------------
983 ea = cCurrentMedicationEAPnl(parent = parent, id = -1, substance = substance)
984 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (substance is not None))
985 dlg.SetTitle(gmTools.coalesce(substance, _('Adding substance intake'), _('Editing substance intake')))
986 if dlg.ShowModal() == wx.ID_OK:
987 dlg.Destroy()
988 return True
989 dlg.Destroy()
990 return False
991 #============================================================
992 # current substances grid
993 #------------------------------------------------------------
995
996 if parent is None:
997 parent = wx.GetApp().GetTopWindow()
998
999 template = gmFormWidgets.manage_form_templates (
1000 parent = parent,
1001 template_types = ['current medication list']
1002 )
1003 option = u'form_templates.medication_list'
1004
1005 if template is None:
1006 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
1007 return None
1008
1009 if template['engine'] != u'L':
1010 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
1011 return None
1012
1013 dbcfg = gmCfg.cCfgSQL()
1014 dbcfg.set (
1015 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1016 option = option,
1017 value = u'%s - %s' % (template['name_long'], template['external_version'])
1018 )
1019
1020 return template
1021 #------------------------------------------------------------
1023
1024 if parent is None:
1025 parent = wx.GetApp().GetTopWindow()
1026
1027 # 1) get template
1028 dbcfg = gmCfg.cCfgSQL()
1029 option = u'form_templates.medication_list'
1030
1031 template = dbcfg.get2 (
1032 option = option,
1033 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1034 bias = 'user'
1035 )
1036
1037 if template is None:
1038 template = configure_medication_list_template(parent = parent)
1039 if template is None:
1040 gmGuiHelpers.gm_show_error (
1041 aMessage = _('There is no medication list template configured.'),
1042 aTitle = _('Printing medication list')
1043 )
1044 return False
1045 else:
1046 try:
1047 name, ver = template.split(u' - ')
1048 except:
1049 _log.exception('problem splitting medication list template name [%s]', template)
1050 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
1051 return False
1052 template = gmForms.get_form_template(name_long = name, external_version = ver)
1053 if template is None:
1054 gmGuiHelpers.gm_show_error (
1055 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
1056 aTitle = _('Printing medication list')
1057 )
1058 return False
1059
1060 # 2) process template
1061 try:
1062 meds_list = template.instantiate()
1063 except KeyError:
1064 _log.exception('cannot instantiate medication list template [%s]', template)
1065 gmGuiHelpers.gm_show_error (
1066 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
1067 aTitle = _('Printing medication list')
1068 )
1069 return False
1070
1071 ph = gmMacro.gmPlaceholderHandler()
1072 #ph.debug = True
1073 meds_list.substitute_placeholders(data_source = ph)
1074 pdf_name = meds_list.generate_output(cleanup = cleanup)
1075 if cleanup:
1076 meds_list.cleanup()
1077 if pdf_name is None:
1078 gmGuiHelpers.gm_show_error (
1079 aMessage = _('Error generating the medication list.'),
1080 aTitle = _('Printing medication list')
1081 )
1082 return False
1083
1084 # 3) print template
1085 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
1086 if not printed:
1087 gmGuiHelpers.gm_show_error (
1088 aMessage = _('Error printing the medication list.'),
1089 aTitle = _('Printing medication list')
1090 )
1091 return False
1092
1093 pat = gmPerson.gmCurrentPatient()
1094 emr = pat.get_emr()
1095 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1096 emr.add_clin_narrative (
1097 soap_cat = None,
1098 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1099 episode = epi
1100 )
1101
1102 return True
1103 #------------------------------------------------------------
1105 """A grid class for displaying current substance intake.
1106
1107 - does NOT listen to the currently active patient
1108 - thereby it can display any patient at any time
1109 """
1111
1112 wx.grid.Grid.__init__(self, *args, **kwargs)
1113
1114 self.__patient = None
1115 self.__row_data = {}
1116 self.__prev_row = None
1117 self.__prev_tooltip_row = None
1118 self.__prev_cell_0 = None
1119 self.__grouping_mode = u'episode'
1120 self.__filter_show_unapproved = False
1121 self.__filter_show_inactive = False
1122
1123 self.__grouping2col_labels = {
1124 u'episode': [
1125 _('Episode'),
1126 _('Substance'),
1127 _('Dose'),
1128 _('Schedule'),
1129 _('Started'),
1130 _('Duration'),
1131 _('Brand')
1132 ],
1133 u'brand': [
1134 _('Brand'),
1135 _('Schedule'),
1136 _('Substance'),
1137 _('Dose'),
1138 _('Started'),
1139 _('Duration'),
1140 _('Episode')
1141 ]
1142 }
1143
1144 self.__grouping2order_by_clauses = {
1145 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1146 u'brand': u'brand nulls last, substance, started'
1147 }
1148
1149 self.__init_ui()
1150 self.__register_events()
1151 #------------------------------------------------------------
1152 # external API
1153 #------------------------------------------------------------
1155
1156 sel_block_top_left = self.GetSelectionBlockTopLeft()
1157 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1158 sel_cols = self.GetSelectedCols()
1159 sel_rows = self.GetSelectedRows()
1160
1161 selected_cells = []
1162
1163 # individually selected cells (ctrl-click)
1164 selected_cells += self.GetSelectedCells()
1165
1166 # selected rows
1167 selected_cells += list (
1168 (row, col)
1169 for row in sel_rows
1170 for col in xrange(self.GetNumberCols())
1171 )
1172
1173 # selected columns
1174 selected_cells += list (
1175 (row, col)
1176 for row in xrange(self.GetNumberRows())
1177 for col in sel_cols
1178 )
1179
1180 # selection blocks
1181 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1182 selected_cells += [
1183 (row, col)
1184 for row in xrange(top_left[0], bottom_right[0] + 1)
1185 for col in xrange(top_left[1], bottom_right[1] + 1)
1186 ]
1187
1188 return set(selected_cells)
1189 #------------------------------------------------------------
1191 rows = {}
1192
1193 for row, col in self.get_selected_cells():
1194 rows[row] = True
1195
1196 return rows.keys()
1197 #------------------------------------------------------------
1199 return [ self.__row_data[row] for row in self.get_selected_rows() ]
1200 #------------------------------------------------------------
1202
1203 self.empty_grid()
1204
1205 if self.__patient is None:
1206 return
1207
1208 emr = self.__patient.get_emr()
1209 meds = emr.get_current_substance_intake (
1210 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1211 include_unapproved = self.__filter_show_unapproved,
1212 include_inactive = self.__filter_show_inactive
1213 )
1214 if not meds:
1215 return
1216
1217 self.BeginBatch()
1218
1219 # columns
1220 labels = self.__grouping2col_labels[self.__grouping_mode]
1221 if self.__filter_show_unapproved:
1222 self.AppendCols(numCols = len(labels) + 1)
1223 else:
1224 self.AppendCols(numCols = len(labels))
1225 for col_idx in range(len(labels)):
1226 self.SetColLabelValue(col_idx, labels[col_idx])
1227 if self.__filter_show_unapproved:
1228 self.SetColLabelValue(len(labels), u'OK?')
1229 self.SetColSize(len(labels), 40)
1230
1231 self.AppendRows(numRows = len(meds))
1232
1233 # loop over data
1234 for row_idx in range(len(meds)):
1235 med = meds[row_idx]
1236 self.__row_data[row_idx] = med
1237
1238 if med['is_currently_active'] is True:
1239 atcs = []
1240 if med['atc_substance'] is not None:
1241 atcs.append(med['atc_substance'])
1242 # if med['atc_brand'] is not None:
1243 # atcs.append(med['atc_brand'])
1244 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand'])
1245 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],))
1246 if allg not in [None, False]:
1247 attr = self.GetOrCreateCellAttr(row_idx, 0)
1248 if allg['type'] == u'allergy':
1249 attr.SetTextColour('red')
1250 else:
1251 attr.SetTextColour('yellow')
1252 self.SetRowAttr(row_idx, attr)
1253 else:
1254 attr = self.GetOrCreateCellAttr(row_idx, 0)
1255 attr.SetTextColour('grey')
1256 self.SetRowAttr(row_idx, attr)
1257
1258 if self.__grouping_mode == u'episode':
1259 if med['pk_episode'] is None:
1260 self.__prev_cell_0 = None
1261 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1262 else:
1263 if self.__prev_cell_0 != med['episode']:
1264 self.__prev_cell_0 = med['episode']
1265 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
1266
1267 self.SetCellValue(row_idx, 1, med['substance'])
1268 self.SetCellValue(row_idx, 2, gmTools.coalesce(med['strength'], u''))
1269 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1270 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1271
1272 if med['is_long_term']:
1273 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1274 else:
1275 if med['duration'] is None:
1276 self.SetCellValue(row_idx, 5, u'')
1277 else:
1278 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1279
1280 if med['pk_brand'] is None:
1281 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1282 else:
1283 if med['fake_brand']:
1284 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1285 else:
1286 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1287
1288 elif self.__grouping_mode == u'brand':
1289
1290 if med['pk_brand'] is None:
1291 self.__prev_cell_0 = None
1292 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1293 else:
1294 if self.__prev_cell_0 != med['brand']:
1295 self.__prev_cell_0 = med['brand']
1296 if med['fake_brand']:
1297 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1298 else:
1299 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1300
1301 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1302 self.SetCellValue(row_idx, 2, med['substance'])
1303 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['strength'], u''))
1304 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1305
1306 if med['is_long_term']:
1307 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1308 else:
1309 if med['duration'] is None:
1310 self.SetCellValue(row_idx, 5, u'')
1311 else:
1312 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1313
1314 if med['pk_episode'] is None:
1315 self.SetCellValue(row_idx, 6, u'')
1316 else:
1317 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1318
1319 else:
1320 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1321
1322 if self.__filter_show_unapproved:
1323 self.SetCellValue (
1324 row_idx,
1325 len(labels),
1326 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1327 )
1328
1329 #self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1330
1331 self.EndBatch()
1332 #------------------------------------------------------------
1334 self.BeginBatch()
1335 self.ClearGrid()
1336 # Windows cannot do "nothing", it rather decides to assert()
1337 # on thinking it is supposed to do nothing
1338 if self.GetNumberRows() > 0:
1339 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1340 if self.GetNumberCols() > 0:
1341 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1342 self.EndBatch()
1343 self.__row_data = {}
1344 self.__prev_cell_0 = None
1345 #------------------------------------------------------------
1347
1348 if len(self.__row_data) == 0:
1349 return
1350
1351 sel_rows = self.get_selected_rows()
1352 if len(sel_rows) != 1:
1353 return
1354
1355 drug_db = get_drug_database()
1356 if drug_db is None:
1357 return
1358
1359 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1360 #------------------------------------------------------------
1362
1363 if len(self.__row_data) == 0:
1364 return
1365
1366 sel_rows = self.get_selected_rows()
1367
1368 if len(sel_rows) != 1:
1369 return
1370
1371 webbrowser.open (
1372 url = gmMedication.drug2renal_insufficiency_url(search_term = self.get_selected_data()[0]),
1373 new = False,
1374 autoraise = True
1375 )
1376 #------------------------------------------------------------
1378
1379 dbcfg = gmCfg.cCfgSQL()
1380
1381 url = dbcfg.get2 (
1382 option = u'external.urls.report_ADR',
1383 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1384 bias = u'user',
1385 default = u'https://dcgma.org/uaw/meldung.php' # http://www.akdae.de/Arzneimittelsicherheit/UAW-Meldung/UAW-Meldung-online.html
1386 )
1387
1388 webbrowser.open(url = url, new = False, autoraise = True)
1389 #------------------------------------------------------------
1391
1392 if len(self.__row_data) == 0:
1393 return
1394
1395 drug_db = get_drug_database()
1396 if drug_db is None:
1397 return
1398
1399 if len(self.get_selected_rows()) > 1:
1400 drug_db.check_drug_interactions(substances = self.get_selected_data())
1401 else:
1402 drug_db.check_drug_interactions(substances = self.__row_data.values())
1403 #------------------------------------------------------------
1405 edit_intake_of_substance(parent = self, substance = None)
1406 #------------------------------------------------------------
1408
1409 rows = self.get_selected_rows()
1410
1411 if len(rows) == 0:
1412 return
1413
1414 if len(rows) > 1:
1415 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit more than one substance at once.'), beep = True)
1416 return
1417
1418 subst = self.get_selected_data()[0]
1419 edit_intake_of_substance(parent = self, substance = subst)
1420 #------------------------------------------------------------
1422
1423 rows = self.get_selected_rows()
1424
1425 if len(rows) == 0:
1426 return
1427
1428 if len(rows) > 1:
1429 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1430 return
1431
1432 subst = self.get_selected_data()[0]
1433 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1434 #------------------------------------------------------------
1436 rows = self.get_selected_rows()
1437
1438 if len(rows) == 0:
1439 return
1440
1441 if len(rows) > 1:
1442 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create allergy from more than one substance at once.'), beep = True)
1443 return
1444
1445 subst = self.get_selected_data()[0]
1446 if subst['is_currently_active']:
1447 subst['discontinued'] = gmDateTime.pydt_now_here()
1448 if subst['discontinue_reason'] is None:
1449 subst['discontinue_reason'] = _('discontinued due to allergy or intolerance')
1450 subst.save()
1451
1452 emr = self.__patient.get_emr()
1453 allg = subst.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1454 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
1455 dlg.ShowModal()
1456 #------------------------------------------------------------
1458 # there could be some filtering/user interaction going on here
1459 _cfg = gmCfg2.gmCfgData()
1460 print_medication_list(parent = self, cleanup = _cfg.get(option = 'debug'))
1461 #------------------------------------------------------------
1463
1464 try:
1465 entry = self.__row_data[row]
1466 except KeyError:
1467 return u' '
1468
1469 emr = self.__patient.get_emr()
1470 atcs = []
1471 if entry['atc_substance'] is not None:
1472 atcs.append(entry['atc_substance'])
1473 # if entry['atc_brand'] is not None:
1474 # atcs.append(entry['atc_brand'])
1475 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],), brand = entry['brand'])
1476 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],))
1477
1478 tt = _('Substance intake entry (%s, %s) [#%s] \n') % (
1479 gmTools.bool2subst (
1480 boolean = entry['is_currently_active'],
1481 true_return = gmTools.bool2subst (
1482 boolean = entry['seems_inactive'],
1483 true_return = _('active, needs check'),
1484 false_return = _('active'),
1485 none_return = _('assumed active')
1486 ),
1487 false_return = _('inactive')
1488 ),
1489 gmTools.bool2subst (
1490 boolean = entry['intake_is_approved_of'],
1491 true_return = _('approved'),
1492 false_return = _('unapproved')
1493 ),
1494 entry['pk_substance_intake']
1495 )
1496
1497 if allg not in [None, False]:
1498 certainty = gmTools.bool2subst(allg['definite'], _('definite'), _('suspected'))
1499 tt += u'\n'
1500 tt += u' !! ---- Cave ---- !!\n'
1501 tt += u' %s (%s): %s (%s)\n' % (
1502 allg['l10n_type'],
1503 certainty,
1504 allg['descriptor'],
1505 gmTools.coalesce(allg['reaction'], u'')[:40]
1506 )
1507 tt += u'\n'
1508
1509 tt += u' ' + _('Substance: %s [#%s]\n') % (entry['substance'], entry['pk_substance'])
1510 tt += u' ' + _('Preparation: %s\n') % entry['preparation']
1511 if entry['strength'] is not None:
1512 tt += u' ' + _('Amount per dose: %s') % entry['strength']
1513 if entry.ddd is not None:
1514 tt += u' (DDD: %s %s)' % (entry.ddd['ddd'], entry.ddd['unit'])
1515 tt += u'\n'
1516 else:
1517 if entry.ddd is not None:
1518 tt += u' DDD: %s %s' % (entry.ddd['ddd'], entry.ddd['unit'])
1519 tt += u'\n'
1520 tt += gmTools.coalesce(entry['atc_substance'], u'', _(' ATC (substance): %s\n'))
1521
1522 tt += u'\n'
1523
1524 tt += gmTools.coalesce (
1525 entry['brand'],
1526 u'',
1527 _(' Brand name: %%s [#%s]\n') % entry['pk_brand']
1528 )
1529 tt += gmTools.coalesce(entry['atc_brand'], u'', _(' ATC (brand): %s\n'))
1530
1531 tt += u'\n'
1532
1533 tt += gmTools.coalesce(entry['schedule'], u'', _(' Regimen: %s\n'))
1534
1535 if entry['is_long_term']:
1536 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity)
1537 else:
1538 if entry['duration'] is None:
1539 duration = u''
1540 else:
1541 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(entry['duration'], gmDateTime.acc_days))
1542
1543 tt += _(' Started %s%s%s\n') % (
1544 entry['started'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
1545 duration,
1546 gmTools.bool2subst(entry['is_long_term'], _(' (long-term)'), _(' (short-term)'), u'')
1547 )
1548
1549 if entry['discontinued'] is not None:
1550 tt += _(' Discontinued %s\n') % (
1551 entry['discontinued'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
1552 )
1553 tt += _(' Reason: %s\n') % entry['discontinue_reason']
1554
1555 tt += u'\n'
1556
1557 tt += gmTools.coalesce(entry['aim'], u'', _(' Aim: %s\n'))
1558 tt += gmTools.coalesce(entry['episode'], u'', _(' Episode: %s\n'))
1559 tt += gmTools.coalesce(entry['notes'], u'', _(' Advice: %s\n'))
1560
1561 tt += u'\n'
1562
1563 tt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % ({
1564 'row_ver': entry['row_version'],
1565 'mod_when': entry['modified_when'].strftime('%c').decode(gmI18N.get_encoding()),
1566 'mod_by': entry['modified_by']
1567 })
1568
1569 return tt
1570 #------------------------------------------------------------
1571 # internal helpers
1572 #------------------------------------------------------------
1574 self.CreateGrid(0, 1)
1575 self.EnableEditing(0)
1576 self.EnableDragGridSize(1)
1577 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
1578
1579 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
1580
1581 self.SetRowLabelSize(0)
1582 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1583 #------------------------------------------------------------
1584 # properties
1585 #------------------------------------------------------------
1588
1592
1593 patient = property(_get_patient, _set_patient)
1594 #------------------------------------------------------------
1597
1601
1602 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
1603 #------------------------------------------------------------
1606
1610
1611 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
1612 #------------------------------------------------------------
1615
1619
1620 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
1621 #------------------------------------------------------------
1622 # event handling
1623 #------------------------------------------------------------
1625 # dynamic tooltips: GridWindow, GridRowLabelWindow, GridColLabelWindow, GridCornerLabelWindow
1626 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1627 #self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
1628 #self.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_col_labels)
1629
1630 # editing cells
1631 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1632 #------------------------------------------------------------
1634 """Calculate where the mouse is and set the tooltip dynamically."""
1635
1636 # Use CalcUnscrolledPosition() to get the mouse position within the
1637 # entire grid including what's offscreen
1638 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1639
1640 # use this logic to prevent tooltips outside the actual cells
1641 # apply to GetRowSize, too
1642 # tot = 0
1643 # for col in xrange(self.NumberCols):
1644 # tot += self.GetColSize(col)
1645 # if xpos <= tot:
1646 # self.tool_tip.Tip = 'Tool tip for Column %s' % (
1647 # self.GetColLabelValue(col))
1648 # break
1649 # else: # mouse is in label area beyond the right-most column
1650 # self.tool_tip.Tip = ''
1651
1652 row, col = self.XYToCell(x, y)
1653
1654 if row == self.__prev_tooltip_row:
1655 return
1656
1657 self.__prev_tooltip_row = row
1658
1659 try:
1660 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1661 except KeyError:
1662 pass
1663 #------------------------------------------------------------
1665 row = evt.GetRow()
1666 data = self.__row_data[row]
1667 edit_intake_of_substance(parent = self, substance = data)
1668 #============================================================
1669 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
1670
1671 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
1672
1673 """Panel holding a grid with current substances. Used as notebook page."""
1674
1676
1677 wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl.__init__(self, *args, **kwargs)
1678 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1679
1680 self.__register_interests()
1681 #-----------------------------------------------------
1682 # reget-on-paint mixin API
1683 #-----------------------------------------------------
1685 """Populate cells with data from model."""
1686 pat = gmPerson.gmCurrentPatient()
1687 if pat.connected:
1688 self._grid_substances.patient = pat
1689 else:
1690 self._grid_substances.patient = None
1691 return True
1692 #--------------------------------------------------------
1693 # event handling
1694 #--------------------------------------------------------
1696 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1697 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
1698 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
1699 # active_substance_mod_db
1700 # substance_brand_mod_db
1701 #--------------------------------------------------------
1704 #--------------------------------------------------------
1706 self._grid_substances.patient = None
1707 #--------------------------------------------------------
1710 #--------------------------------------------------------
1713 #--------------------------------------------------------
1716 #--------------------------------------------------------
1719 #--------------------------------------------------------
1722 #--------------------------------------------------------
1724 self._grid_substances.grouping_mode = 'episode'
1725 #--------------------------------------------------------
1727 self._grid_substances.grouping_mode = 'brand'
1728 #--------------------------------------------------------
1731 #--------------------------------------------------------
1734 #--------------------------------------------------------
1737 #--------------------------------------------------------
1740 #--------------------------------------------------------
1743 #--------------------------------------------------------
1746 #============================================================
1747 # main
1748 #------------------------------------------------------------
1749 if __name__ == '__main__':
1750
1751 if len(sys.argv) < 2:
1752 sys.exit()
1753
1754 if sys.argv[1] != 'test':
1755 sys.exit()
1756
1757 from Gnumed.pycommon import gmI18N
1758
1759 gmI18N.activate_locale()
1760 gmI18N.install_domain(domain = 'gnumed')
1761
1762 #----------------------------------------
1763 app = wx.PyWidgetTester(size = (600, 600))
1764 app.SetWidget(cATCPhraseWheel, -1)
1765 app.MainLoop()
1766
1767 #============================================================
1768
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Fri Oct 1 04:04:55 2010 | http://epydoc.sourceforge.net |