| 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 (
519 description || ' (' || preparation || ')' || 'coalesce(' [' || atc_code || ']', '')
520 ) AS brand
521 FROM ref.branded_drug
522 WHERE description %(fragment_condition)s
523 ORDER BY brand
524 LIMIT 50"""
525
526 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
527 mp.setThresholds(2, 3, 4)
528 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
529 self.SetToolTipString(_('The brand name of the drug the patient is taking.'))
530 self.matcher = mp
531 self.selection_only = False
532
533 #============================================================
534 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
535
536 -class cCurrentMedicationEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
537
539
540 try:
541 data = kwargs['substance']
542 del kwargs['substance']
543 except KeyError:
544 data = None
545
546 wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl.__init__(self, *args, **kwargs)
547 gmEditArea.cGenericEditAreaMixin.__init__(self)
548 self.mode = 'new'
549 self.data = data
550 if data is not None:
551 self.mode = 'edit'
552
553 self.__init_ui()
554 #----------------------------------------------------------------
556
557 # adjust phrasewheels
558
559 self._PRW_brand.add_callback_on_lose_focus(callback = self._on_leave_brand)
560 #----------------------------------------------------------------
562 emr = gmPerson.gmCurrentPatient().get_emr()
563
564 state = emr.allergy_state
565 if state['last_confirmed'] is None:
566 confirmed = _('never')
567 else:
568 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
569 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
570 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
571 msg += u'\n'
572
573 for allergy in emr.get_allergies():
574 msg += u'%s (%s, %s): %s\n' % (
575 allergy['descriptor'],
576 allergy['l10n_type'],
577 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
578 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
579 )
580
581 self._LBL_allergies.SetLabel(msg)
582 #----------------------------------------------------------------
584
585 if self._PRW_brand.GetData() is None:
586 self._TCTRL_brand_ingredients.SetValue(u'')
587 if self.data is None:
588 return
589 if self.data['pk_brand'] is None:
590 return
591 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand'])
592
593 brand = gmMedication.cBrandedDrug(aPK_obj = self._PRW_brand.GetData())
594
595 if self.data is None:
596 self._PRW_preparation.SetText(brand['preparation'], None)
597 else:
598 self._PRW_preparation.SetText (
599 gmTools.coalesce(self.data['preparation'], brand['preparation']),
600 self.data['preparation']
601 )
602
603 comps = brand.components
604
605 if comps is None:
606 return
607
608 if len(comps) == 0:
609 return
610
611 comps = u' / '.join([ u'%s%s' % (c['description'], gmTools.coalesce(c['atc_code'], u'', u' (%s)')) for c in comps ])
612 self._TCTRL_brand_ingredients.SetValue(comps)
613 #----------------------------------------------------------------
614 # generic Edit Area mixin API
615 #----------------------------------------------------------------
617
618 validity = True
619
620 if self._PRW_substance.GetValue().strip() == u'':
621 self._PRW_substance.display_as_valid(False)
622 validity = False
623 else:
624 self._PRW_substance.display_as_valid(True)
625
626 if self._PRW_preparation.GetValue().strip() == u'':
627 self._PRW_preparation.display_as_valid(False)
628 validity = False
629 else:
630 self._PRW_preparation.display_as_valid(True)
631
632 if self._CHBOX_approved.IsChecked():
633 if self._PRW_episode.GetValue().strip() == u'':
634 self._PRW_episode.display_as_valid(False)
635 validity = False
636 else:
637 self._PRW_episode.display_as_valid(True)
638
639 if self._CHBOX_approved.IsChecked() is True:
640 self._PRW_duration.display_as_valid(True)
641 else:
642 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
643 self._PRW_duration.display_as_valid(True)
644 else:
645 if gmDateTime.str2interval(self._PRW_duration.GetValue()) is None:
646 self._PRW_duration.display_as_valid(False)
647 validity = False
648 else:
649 self._PRW_duration.display_as_valid(True)
650
651 end = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
652 if end is not None:
653 start = self._DP_started.GetValue(as_pydt = True)
654 if start > end:
655 self._DP_started.display_as_valid(False)
656 self._DP_discontinued.display_as_valid(False)
657 validity = False
658 else:
659 self._DP_started.display_as_valid(True)
660 self._DP_discontinued.display_as_valid(True)
661
662 if validity is False:
663 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save substance intake. Invalid or missing essential input.'))
664
665 return validity
666 #----------------------------------------------------------------
668
669 emr = gmPerson.gmCurrentPatient().get_emr()
670
671 # 1) create substance intake entry
672 if self._PRW_substance.GetData() is None:
673 subst = self._PRW_substance.GetValue().strip()
674 else:
675 # normalize, do not simply re-use name from phrasewheel
676 subst = gmMedication.get_substance_by_pk(pk = self._PRW_substance.GetData())['description']
677
678 intake = emr.add_substance_intake (
679 substance = subst,
680 episode = self._PRW_episode.GetData(can_create = True),
681 preparation = self._PRW_preparation.GetValue()
682 )
683
684 intake['strength'] = self._PRW_strength.GetValue()
685 intake['started'] = self._DP_started.GetValue(as_pydt = True, invalid_as_none = True)
686 intake['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
687 if intake['discontinued'] is None:
688 intake['discontinue_reason'] = None
689 else:
690 intake['discontinue_reason'] = self._PRW_discontinue_reason().GetValue().strip()
691 intake['schedule'] = self._PRW_schedule.GetValue()
692 intake['aim'] = self._PRW_aim.GetValue()
693 intake['notes'] = self._PRW_notes.GetValue()
694 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
695 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
696
697 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
698 intake['duration'] = None
699 else:
700 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
701
702 # 2) create or retrieve brand
703 brand = None
704 pk_brand = self._PRW_brand.GetData()
705
706 # brand pre-selected ?
707 if pk_brand is None:
708 # no, so ...
709 desc = self._PRW_brand.GetValue().strip()
710 if desc != u'':
711 # ... create or get it
712 brand = gmMedication.create_branded_drug (
713 brand_name = desc,
714 preparation = self._PRW_preparation.GetValue().strip(),
715 return_existing = True
716 )
717 pk_brand = brand['pk']
718 else:
719 # yes, so get it
720 brand = gmMedication.cBrandedDrug(aPK_obj = pk_brand)
721
722 # 3) link brand, if available
723 intake['pk_brand'] = pk_brand
724 intake.save()
725
726 # brand neither creatable nor pre-selected
727 if brand is None:
728 self.data = intake
729 return True
730
731 # 4) add substance to brand as component (because
732 # that's effectively what we are saying here)
733 # FIXME: we may want to ask the user here
734 # FIXME: or only do it if there are no components yet
735 if self._PRW_substance.GetData() is None:
736 brand.add_component(substance = self._PRW_substance.GetValue().strip())
737 else:
738 # normalize substance name
739 subst = gmMedication.get_substance_by_pk(pk = self._PRW_substance.GetData())
740 if subst is not None:
741 brand.add_component(substance = subst['description'])
742
743 self.data = intake
744
745 if self._CHBOX_is_allergy.IsChecked():
746 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
747 # open for editing
748 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
749 dlg.ShowModal()
750
751 return True
752 #----------------------------------------------------------------
754
755 if self._PRW_substance.GetData() is None:
756 self.data['pk_substance'] = gmMedication.create_used_substance (
757 substance = self._PRW_substance.GetValue().strip()
758 )['pk']
759 else:
760 self.data['pk_substance'] = self._PRW_substance.GetData()
761
762 self.data['started'] = self._DP_started.GetValue(as_pydt = True, invalid_as_none = True)
763 self.data['discontinued'] = self._DP_discontinued.GetValue(as_pydt = True, invalid_as_none = True)
764 if self.data['discontinued'] is None:
765 self.data['discontinue_reason'] = None
766 else:
767 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
768 self.data['preparation'] = self._PRW_preparation.GetValue()
769 self.data['strength'] = self._PRW_strength.GetValue()
770 self.data['schedule'] = self._PRW_schedule.GetValue()
771 self.data['aim'] = self._PRW_aim.GetValue()
772 self.data['notes'] = self._PRW_notes.GetValue()
773 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
774 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
775 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
776
777 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
778 self.data['duration'] = None
779 else:
780 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
781
782 if self._PRW_brand.GetData() is None:
783 desc = self._PRW_brand.GetValue().strip()
784 if desc != u'':
785 # create or get brand
786 self.data['pk_brand'] = gmMedication.create_branded_drug (
787 brand_name = desc,
788 preparation = self._PRW_preparation.GetValue().strip(),
789 return_existing = True
790 )['pk']
791 else:
792 self.data['pk_brand'] = self._PRW_brand.GetData()
793
794 self.data.save()
795
796 if self._CHBOX_is_allergy.IsChecked():
797 allg = self.data.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
798 # open for editing
799 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
800 dlg.ShowModal()
801
802 return True
803 #----------------------------------------------------------------
805 self._PRW_substance.SetText(u'', None)
806 self._PRW_strength.SetText(u'', None)
807 # self._PRW_preparation.SetText(u'', None)
808 self._PRW_schedule.SetText(u'', None)
809 self._PRW_duration.SetText(u'', None)
810 self._PRW_aim.SetText(u'', None)
811 self._PRW_notes.SetText(u'', None)
812 self._PRW_episode.SetText(u'', None)
813
814 self._CHBOX_long_term.SetValue(False)
815 self._CHBOX_approved.SetValue(True)
816
817 self._DP_started.SetValue(gmDateTime.pydt_now_here())
818 self._DP_discontinued.SetValue(None)
819 self._PRW_discontinue_reason.SetValue(u'')
820
821 self.__refresh_brand_and_components()
822 self.__refresh_allergies()
823
824 self._PRW_substance.SetFocus()
825 #----------------------------------------------------------------
827
828 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance'])
829 self._PRW_strength.SetText(gmTools.coalesce(self.data['strength'], u''), self.data['strength'])
830
831 if self.data['is_long_term']:
832 self._CHBOX_long_term.SetValue(True)
833 self._PRW_duration.Enable(False)
834 self._PRW_duration.SetText(gmTools.u_infinity, None)
835 self._BTN_discontinued_as_planned.Enable(False)
836 else:
837 self._CHBOX_long_term.SetValue(False)
838 self._PRW_duration.Enable(True)
839 self._BTN_discontinued_as_planned.Enable(True)
840 if self.data['duration'] is None:
841 self._PRW_duration.SetText(u'', None)
842 else:
843 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
844 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
845 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
846 self._PRW_episode.SetData(self.data['pk_episode'])
847 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
848
849 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
850
851 self._DP_started.SetValue(self.data['started'])
852 self._DP_discontinued.SetValue(self.data['discontinued'])
853 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
854
855 self.__refresh_brand_and_components()
856 self.__refresh_allergies()
857
858 self._PRW_substance.SetFocus()
859 #----------------------------------------------------------------
862 #----------------------------------------------------------------
863 # event handlers
864 #----------------------------------------------------------------
867 #----------------------------------------------------------------
869 if self._DP_discontinued.GetValue() is None:
870 self._PRW_discontinue_reason.Enable(False)
871 self._CHBOX_is_allergy.Enable(False)
872 else:
873 self._PRW_discontinue_reason.Enable(True)
874 self._CHBOX_is_allergy.Enable(True)
875 #----------------------------------------------------------------
894 #----------------------------------------------------------------
916 #----------------------------------------------------------------
945 #----------------------------------------------------------------
947 if self._CHBOX_long_term.IsChecked() is True:
948 self._PRW_duration.Enable(False)
949 self._BTN_discontinued_as_planned.Enable(False)
950 self._PRW_discontinue_reason.Enable(False)
951 self._CHBOX_is_allergy.Enable(False)
952 else:
953 self._PRW_duration.Enable(True)
954 self._BTN_discontinued_as_planned.Enable(True)
955 self._PRW_discontinue_reason.Enable(True)
956 self._CHBOX_is_allergy.Enable(True)
957
958 self.__refresh_allergies()
959 #----------------------------------------------------------------
967 #============================================================
969 delete_it = gmGuiHelpers.gm_show_question (
970 aMessage = _(
971 'Do you really want to remove this substance intake ?\n'
972 '\n'
973 'It may be prudent to edit the details first so as to\n'
974 'leave behind some indication of why it was deleted.\n'
975 ),
976 aTitle = _('Deleting medication / substance intake')
977 )
978 if not delete_it:
979 return
980
981 gmMedication.delete_substance_intake(substance = substance)
982 #------------------------------------------------------------
984 ea = cCurrentMedicationEAPnl(parent = parent, id = -1, substance = substance)
985 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (substance is not None))
986 dlg.SetTitle(gmTools.coalesce(substance, _('Adding substance intake'), _('Editing substance intake')))
987 if dlg.ShowModal() == wx.ID_OK:
988 dlg.Destroy()
989 return True
990 dlg.Destroy()
991 return False
992 #============================================================
993 # current substances grid
994 #------------------------------------------------------------
996
997 if parent is None:
998 parent = wx.GetApp().GetTopWindow()
999
1000 template = gmFormWidgets.manage_form_templates (
1001 parent = parent,
1002 template_types = ['current medication list']
1003 )
1004 option = u'form_templates.medication_list'
1005
1006 if template is None:
1007 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
1008 return None
1009
1010 if template['engine'] != u'L':
1011 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
1012 return None
1013
1014 dbcfg = gmCfg.cCfgSQL()
1015 dbcfg.set (
1016 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1017 option = option,
1018 value = u'%s - %s' % (template['name_long'], template['external_version'])
1019 )
1020
1021 return template
1022 #------------------------------------------------------------
1024
1025 if parent is None:
1026 parent = wx.GetApp().GetTopWindow()
1027
1028 # 1) get template
1029 dbcfg = gmCfg.cCfgSQL()
1030 option = u'form_templates.medication_list'
1031
1032 template = dbcfg.get2 (
1033 option = option,
1034 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1035 bias = 'user'
1036 )
1037
1038 if template is None:
1039 template = configure_medication_list_template(parent = parent)
1040 if template is None:
1041 gmGuiHelpers.gm_show_error (
1042 aMessage = _('There is no medication list template configured.'),
1043 aTitle = _('Printing medication list')
1044 )
1045 return False
1046 else:
1047 try:
1048 name, ver = template.split(u' - ')
1049 except:
1050 _log.exception('problem splitting medication list template name [%s]', template)
1051 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
1052 return False
1053 template = gmForms.get_form_template(name_long = name, external_version = ver)
1054 if template is None:
1055 gmGuiHelpers.gm_show_error (
1056 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
1057 aTitle = _('Printing medication list')
1058 )
1059 return False
1060
1061 # 2) process template
1062 try:
1063 meds_list = template.instantiate()
1064 except KeyError:
1065 _log.exception('cannot instantiate medication list template [%s]', template)
1066 gmGuiHelpers.gm_show_error (
1067 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
1068 aTitle = _('Printing medication list')
1069 )
1070 return False
1071
1072 ph = gmMacro.gmPlaceholderHandler()
1073 #ph.debug = True
1074 meds_list.substitute_placeholders(data_source = ph)
1075 pdf_name = meds_list.generate_output(cleanup = cleanup)
1076 if cleanup:
1077 meds_list.cleanup()
1078 if pdf_name is None:
1079 gmGuiHelpers.gm_show_error (
1080 aMessage = _('Error generating the medication list.'),
1081 aTitle = _('Printing medication list')
1082 )
1083 return False
1084
1085 # 3) print template
1086 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
1087 if not printed:
1088 gmGuiHelpers.gm_show_error (
1089 aMessage = _('Error printing the medication list.'),
1090 aTitle = _('Printing medication list')
1091 )
1092 return False
1093
1094 pat = gmPerson.gmCurrentPatient()
1095 emr = pat.get_emr()
1096 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1097 emr.add_clin_narrative (
1098 soap_cat = None,
1099 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1100 episode = epi
1101 )
1102
1103 return True
1104 #------------------------------------------------------------
1106 """A grid class for displaying current substance intake.
1107
1108 - does NOT listen to the currently active patient
1109 - thereby it can display any patient at any time
1110 """
1112
1113 wx.grid.Grid.__init__(self, *args, **kwargs)
1114
1115 self.__patient = None
1116 self.__row_data = {}
1117 self.__prev_row = None
1118 self.__prev_tooltip_row = None
1119 self.__prev_cell_0 = None
1120 self.__grouping_mode = u'episode'
1121 self.__filter_show_unapproved = False
1122 self.__filter_show_inactive = False
1123
1124 self.__grouping2col_labels = {
1125 u'episode': [
1126 _('Episode'),
1127 _('Substance'),
1128 _('Dose'),
1129 _('Schedule'),
1130 _('Started'),
1131 _('Duration'),
1132 _('Brand')
1133 ],
1134 u'brand': [
1135 _('Brand'),
1136 _('Schedule'),
1137 _('Substance'),
1138 _('Dose'),
1139 _('Started'),
1140 _('Duration'),
1141 _('Episode')
1142 ]
1143 }
1144
1145 self.__grouping2order_by_clauses = {
1146 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1147 u'brand': u'brand nulls last, substance, started'
1148 }
1149
1150 self.__init_ui()
1151 self.__register_events()
1152 #------------------------------------------------------------
1153 # external API
1154 #------------------------------------------------------------
1156
1157 sel_block_top_left = self.GetSelectionBlockTopLeft()
1158 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1159 sel_cols = self.GetSelectedCols()
1160 sel_rows = self.GetSelectedRows()
1161
1162 selected_cells = []
1163
1164 # individually selected cells (ctrl-click)
1165 selected_cells += self.GetSelectedCells()
1166
1167 # selected rows
1168 selected_cells += list (
1169 (row, col)
1170 for row in sel_rows
1171 for col in xrange(self.GetNumberCols())
1172 )
1173
1174 # selected columns
1175 selected_cells += list (
1176 (row, col)
1177 for row in xrange(self.GetNumberRows())
1178 for col in sel_cols
1179 )
1180
1181 # selection blocks
1182 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1183 selected_cells += [
1184 (row, col)
1185 for row in xrange(top_left[0], bottom_right[0] + 1)
1186 for col in xrange(top_left[1], bottom_right[1] + 1)
1187 ]
1188
1189 return set(selected_cells)
1190 #------------------------------------------------------------
1192 rows = {}
1193
1194 for row, col in self.get_selected_cells():
1195 rows[row] = True
1196
1197 return rows.keys()
1198 #------------------------------------------------------------
1200 return [ self.__row_data[row] for row in self.get_selected_rows() ]
1201 #------------------------------------------------------------
1203
1204 self.empty_grid()
1205
1206 if self.__patient is None:
1207 return
1208
1209 emr = self.__patient.get_emr()
1210 meds = emr.get_current_substance_intake (
1211 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1212 include_unapproved = self.__filter_show_unapproved,
1213 include_inactive = self.__filter_show_inactive
1214 )
1215 if not meds:
1216 return
1217
1218 self.BeginBatch()
1219
1220 # columns
1221 labels = self.__grouping2col_labels[self.__grouping_mode]
1222 if self.__filter_show_unapproved:
1223 self.AppendCols(numCols = len(labels) + 1)
1224 else:
1225 self.AppendCols(numCols = len(labels))
1226 for col_idx in range(len(labels)):
1227 self.SetColLabelValue(col_idx, labels[col_idx])
1228 if self.__filter_show_unapproved:
1229 self.SetColLabelValue(len(labels), u'OK?')
1230 self.SetColSize(len(labels), 40)
1231
1232 self.AppendRows(numRows = len(meds))
1233
1234 # loop over data
1235 for row_idx in range(len(meds)):
1236 med = meds[row_idx]
1237 self.__row_data[row_idx] = med
1238
1239 if med['is_currently_active'] is True:
1240 atcs = []
1241 if med['atc_substance'] is not None:
1242 atcs.append(med['atc_substance'])
1243 # if med['atc_brand'] is not None:
1244 # atcs.append(med['atc_brand'])
1245 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand'])
1246 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],))
1247 if allg not in [None, False]:
1248 attr = self.GetOrCreateCellAttr(row_idx, 0)
1249 if allg['type'] == u'allergy':
1250 attr.SetTextColour('red')
1251 else:
1252 attr.SetTextColour('yellow')
1253 self.SetRowAttr(row_idx, attr)
1254 else:
1255 attr = self.GetOrCreateCellAttr(row_idx, 0)
1256 attr.SetTextColour('grey')
1257 self.SetRowAttr(row_idx, attr)
1258
1259 if self.__grouping_mode == u'episode':
1260 if med['pk_episode'] is None:
1261 self.__prev_cell_0 = None
1262 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1263 else:
1264 if self.__prev_cell_0 != med['episode']:
1265 self.__prev_cell_0 = med['episode']
1266 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
1267
1268 self.SetCellValue(row_idx, 1, med['substance'])
1269 self.SetCellValue(row_idx, 2, gmTools.coalesce(med['strength'], u''))
1270 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1271 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1272
1273 if med['is_long_term']:
1274 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1275 else:
1276 if med['duration'] is None:
1277 self.SetCellValue(row_idx, 5, u'')
1278 else:
1279 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1280
1281 if med['pk_brand'] is None:
1282 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1283 else:
1284 if med['fake_brand']:
1285 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1286 else:
1287 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1288
1289 elif self.__grouping_mode == u'brand':
1290
1291 if med['pk_brand'] is None:
1292 self.__prev_cell_0 = None
1293 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1294 else:
1295 if self.__prev_cell_0 != med['brand']:
1296 self.__prev_cell_0 = med['brand']
1297 if med['fake_brand']:
1298 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1299 else:
1300 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1301
1302 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1303 self.SetCellValue(row_idx, 2, med['substance'])
1304 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['strength'], u''))
1305 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1306
1307 if med['is_long_term']:
1308 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1309 else:
1310 if med['duration'] is None:
1311 self.SetCellValue(row_idx, 5, u'')
1312 else:
1313 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1314
1315 if med['pk_episode'] is None:
1316 self.SetCellValue(row_idx, 6, u'')
1317 else:
1318 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1319
1320 else:
1321 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1322
1323 if self.__filter_show_unapproved:
1324 self.SetCellValue (
1325 row_idx,
1326 len(labels),
1327 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1328 )
1329
1330 #self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1331
1332 self.EndBatch()
1333 #------------------------------------------------------------
1335 self.BeginBatch()
1336 self.ClearGrid()
1337 # Windows cannot do "nothing", it rather decides to assert()
1338 # on thinking it is supposed to do nothing
1339 if self.GetNumberRows() > 0:
1340 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1341 if self.GetNumberCols() > 0:
1342 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1343 self.EndBatch()
1344 self.__row_data = {}
1345 self.__prev_cell_0 = None
1346 #------------------------------------------------------------
1348
1349 if len(self.__row_data) == 0:
1350 return
1351
1352 sel_rows = self.get_selected_rows()
1353 if len(sel_rows) != 1:
1354 return
1355
1356 drug_db = get_drug_database()
1357 if drug_db is None:
1358 return
1359
1360 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1361 #------------------------------------------------------------
1363
1364 if len(self.__row_data) == 0:
1365 return
1366
1367 sel_rows = self.get_selected_rows()
1368
1369 if len(sel_rows) != 1:
1370 return
1371
1372 webbrowser.open (
1373 url = gmMedication.drug2renal_insufficiency_url(search_term = self.get_selected_data()[0]),
1374 new = False,
1375 autoraise = True
1376 )
1377 #------------------------------------------------------------
1379
1380 dbcfg = gmCfg.cCfgSQL()
1381
1382 url = dbcfg.get2 (
1383 option = u'external.urls.report_ADR',
1384 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1385 bias = u'user',
1386 default = u'https://dcgma.org/uaw/meldung.php' # http://www.akdae.de/Arzneimittelsicherheit/UAW-Meldung/UAW-Meldung-online.html
1387 )
1388
1389 webbrowser.open(url = url, new = False, autoraise = True)
1390 #------------------------------------------------------------
1392
1393 if len(self.__row_data) == 0:
1394 return
1395
1396 drug_db = get_drug_database()
1397 if drug_db is None:
1398 return
1399
1400 if len(self.get_selected_rows()) > 1:
1401 drug_db.check_drug_interactions(substances = self.get_selected_data())
1402 else:
1403 drug_db.check_drug_interactions(substances = self.__row_data.values())
1404 #------------------------------------------------------------
1406 edit_intake_of_substance(parent = self, substance = None)
1407 #------------------------------------------------------------
1409
1410 rows = self.get_selected_rows()
1411
1412 if len(rows) == 0:
1413 return
1414
1415 if len(rows) > 1:
1416 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit more than one substance at once.'), beep = True)
1417 return
1418
1419 subst = self.get_selected_data()[0]
1420 edit_intake_of_substance(parent = self, substance = subst)
1421 #------------------------------------------------------------
1423
1424 rows = self.get_selected_rows()
1425
1426 if len(rows) == 0:
1427 return
1428
1429 if len(rows) > 1:
1430 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1431 return
1432
1433 subst = self.get_selected_data()[0]
1434 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1435 #------------------------------------------------------------
1437 rows = self.get_selected_rows()
1438
1439 if len(rows) == 0:
1440 return
1441
1442 if len(rows) > 1:
1443 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create allergy from more than one substance at once.'), beep = True)
1444 return
1445
1446 subst = self.get_selected_data()[0]
1447 if subst['is_currently_active']:
1448 subst['discontinued'] = gmDateTime.pydt_now_here()
1449 if subst['discontinue_reason'] is None:
1450 subst['discontinue_reason'] = _('discontinued due to allergy or intolerance')
1451 subst.save()
1452
1453 emr = self.__patient.get_emr()
1454 allg = subst.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1455 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = self, id = -1)
1456 dlg.ShowModal()
1457 #------------------------------------------------------------
1459 # there could be some filtering/user interaction going on here
1460 _cfg = gmCfg2.gmCfgData()
1461 print_medication_list(parent = self, cleanup = _cfg.get(option = 'debug'))
1462 #------------------------------------------------------------
1464
1465 try:
1466 entry = self.__row_data[row]
1467 except KeyError:
1468 return u' '
1469
1470 emr = self.__patient.get_emr()
1471 atcs = []
1472 if entry['atc_substance'] is not None:
1473 atcs.append(entry['atc_substance'])
1474 # if entry['atc_brand'] is not None:
1475 # atcs.append(entry['atc_brand'])
1476 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],), brand = entry['brand'])
1477 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],))
1478
1479 tt = _('Substance intake entry (%s, %s) [#%s] \n') % (
1480 gmTools.bool2subst (
1481 boolean = entry['is_currently_active'],
1482 true_return = gmTools.bool2subst (
1483 boolean = entry['seems_inactive'],
1484 true_return = _('active, needs check'),
1485 false_return = _('active'),
1486 none_return = _('assumed active')
1487 ),
1488 false_return = _('inactive')
1489 ),
1490 gmTools.bool2subst (
1491 boolean = entry['intake_is_approved_of'],
1492 true_return = _('approved'),
1493 false_return = _('unapproved')
1494 ),
1495 entry['pk_substance_intake']
1496 )
1497
1498 if allg not in [None, False]:
1499 certainty = gmTools.bool2subst(allg['definite'], _('definite'), _('suspected'))
1500 tt += u'\n'
1501 tt += u' !! ---- Cave ---- !!\n'
1502 tt += u' %s (%s): %s (%s)\n' % (
1503 allg['l10n_type'],
1504 certainty,
1505 allg['descriptor'],
1506 gmTools.coalesce(allg['reaction'], u'')[:40]
1507 )
1508 tt += u'\n'
1509
1510 tt += u' ' + _('Substance: %s [#%s]\n') % (entry['substance'], entry['pk_substance'])
1511 tt += u' ' + _('Preparation: %s\n') % entry['preparation']
1512 if entry['strength'] is not None:
1513 tt += u' ' + _('Amount per dose: %s') % entry['strength']
1514 if entry.ddd is not None:
1515 tt += u' (DDD: %s %s)' % (entry.ddd['ddd'], entry.ddd['unit'])
1516 tt += u'\n'
1517 else:
1518 if entry.ddd is not None:
1519 tt += u' DDD: %s %s' % (entry.ddd['ddd'], entry.ddd['unit'])
1520 tt += u'\n'
1521 tt += gmTools.coalesce(entry['atc_substance'], u'', _(' ATC (substance): %s\n'))
1522
1523 tt += u'\n'
1524
1525 tt += gmTools.coalesce (
1526 entry['brand'],
1527 u'',
1528 _(' Brand name: %%s [#%s]\n') % entry['pk_brand']
1529 )
1530 tt += gmTools.coalesce(entry['atc_brand'], u'', _(' ATC (brand): %s\n'))
1531
1532 tt += u'\n'
1533
1534 tt += gmTools.coalesce(entry['schedule'], u'', _(' Regimen: %s\n'))
1535
1536 if entry['is_long_term']:
1537 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity)
1538 else:
1539 if entry['duration'] is None:
1540 duration = u''
1541 else:
1542 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(entry['duration'], gmDateTime.acc_days))
1543
1544 tt += _(' Started %s%s%s\n') % (
1545 entry['started'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
1546 duration,
1547 gmTools.bool2subst(entry['is_long_term'], _(' (long-term)'), _(' (short-term)'), u'')
1548 )
1549
1550 if entry['discontinued'] is not None:
1551 tt += _(' Discontinued %s\n') % (
1552 entry['discontinued'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
1553 )
1554 tt += _(' Reason: %s\n') % entry['discontinue_reason']
1555
1556 tt += u'\n'
1557
1558 tt += gmTools.coalesce(entry['aim'], u'', _(' Aim: %s\n'))
1559 tt += gmTools.coalesce(entry['episode'], u'', _(' Episode: %s\n'))
1560 tt += gmTools.coalesce(entry['notes'], u'', _(' Advice: %s\n'))
1561
1562 tt += u'\n'
1563
1564 tt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % ({
1565 'row_ver': entry['row_version'],
1566 'mod_when': entry['modified_when'].strftime('%c').decode(gmI18N.get_encoding()),
1567 'mod_by': entry['modified_by']
1568 })
1569
1570 return tt
1571 #------------------------------------------------------------
1572 # internal helpers
1573 #------------------------------------------------------------
1575 self.CreateGrid(0, 1)
1576 self.EnableEditing(0)
1577 self.EnableDragGridSize(1)
1578 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
1579
1580 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
1581
1582 self.SetRowLabelSize(0)
1583 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1584 #------------------------------------------------------------
1585 # properties
1586 #------------------------------------------------------------
1589
1593
1594 patient = property(_get_patient, _set_patient)
1595 #------------------------------------------------------------
1598
1602
1603 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
1604 #------------------------------------------------------------
1607
1611
1612 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
1613 #------------------------------------------------------------
1616
1620
1621 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
1622 #------------------------------------------------------------
1623 # event handling
1624 #------------------------------------------------------------
1626 # dynamic tooltips: GridWindow, GridRowLabelWindow, GridColLabelWindow, GridCornerLabelWindow
1627 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1628 #self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
1629 #self.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_col_labels)
1630
1631 # editing cells
1632 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1633 #------------------------------------------------------------
1635 """Calculate where the mouse is and set the tooltip dynamically."""
1636
1637 # Use CalcUnscrolledPosition() to get the mouse position within the
1638 # entire grid including what's offscreen
1639 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1640
1641 # use this logic to prevent tooltips outside the actual cells
1642 # apply to GetRowSize, too
1643 # tot = 0
1644 # for col in xrange(self.NumberCols):
1645 # tot += self.GetColSize(col)
1646 # if xpos <= tot:
1647 # self.tool_tip.Tip = 'Tool tip for Column %s' % (
1648 # self.GetColLabelValue(col))
1649 # break
1650 # else: # mouse is in label area beyond the right-most column
1651 # self.tool_tip.Tip = ''
1652
1653 row, col = self.XYToCell(x, y)
1654
1655 if row == self.__prev_tooltip_row:
1656 return
1657
1658 self.__prev_tooltip_row = row
1659
1660 try:
1661 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1662 except KeyError:
1663 pass
1664 #------------------------------------------------------------
1666 row = evt.GetRow()
1667 data = self.__row_data[row]
1668 edit_intake_of_substance(parent = self, substance = data)
1669 #============================================================
1670 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
1671
1672 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
1673
1674 """Panel holding a grid with current substances. Used as notebook page."""
1675
1677
1678 wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl.__init__(self, *args, **kwargs)
1679 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
1680
1681 self.__register_interests()
1682 #-----------------------------------------------------
1683 # reget-on-paint mixin API
1684 #-----------------------------------------------------
1686 """Populate cells with data from model."""
1687 pat = gmPerson.gmCurrentPatient()
1688 if pat.connected:
1689 self._grid_substances.patient = pat
1690 else:
1691 self._grid_substances.patient = None
1692 return True
1693 #--------------------------------------------------------
1694 # event handling
1695 #--------------------------------------------------------
1697 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1698 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
1699 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
1700 # active_substance_mod_db
1701 # substance_brand_mod_db
1702 #--------------------------------------------------------
1705 #--------------------------------------------------------
1707 self._grid_substances.patient = None
1708 #--------------------------------------------------------
1711 #--------------------------------------------------------
1714 #--------------------------------------------------------
1717 #--------------------------------------------------------
1720 #--------------------------------------------------------
1723 #--------------------------------------------------------
1725 self._grid_substances.grouping_mode = 'episode'
1726 #--------------------------------------------------------
1728 self._grid_substances.grouping_mode = 'brand'
1729 #--------------------------------------------------------
1732 #--------------------------------------------------------
1735 #--------------------------------------------------------
1738 #--------------------------------------------------------
1741 #--------------------------------------------------------
1744 #--------------------------------------------------------
1747 #============================================================
1748 # main
1749 #------------------------------------------------------------
1750 if __name__ == '__main__':
1751
1752 if len(sys.argv) < 2:
1753 sys.exit()
1754
1755 if sys.argv[1] != 'test':
1756 sys.exit()
1757
1758 from Gnumed.pycommon import gmI18N
1759
1760 gmI18N.activate_locale()
1761 gmI18N.install_domain(domain = 'gnumed')
1762
1763 #----------------------------------------
1764 app = wx.PyWidgetTester(size = (600, 600))
1765 app.SetWidget(cATCPhraseWheel, -1)
1766 app.MainLoop()
1767
1768 #============================================================
1769
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Sep 9 04:07:36 2010 | http://epydoc.sourceforge.net |