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
27
28 if parent is None:
29 parent = wx.GetApp().GetTopWindow()
30
31 def refresh(lctrl):
32 atcs = gmATC.get_reference_atcs()
33
34 items = [ [
35 a['atc'],
36 a['term'],
37 u'%s' % gmTools.coalesce(a['ddd'], u''),
38 gmTools.coalesce(a['unit'], u''),
39 gmTools.coalesce(a['administrative_route'], u''),
40 gmTools.coalesce(a['comment'], u''),
41 a['version'],
42 a['lang']
43 ] for a in atcs ]
44 lctrl.set_string_items(items)
45 lctrl.set_data(atcs)
46
47 gmListWidgets.get_choices_from_list (
48 parent = parent,
49 msg = _('\nThe ATC codes as known to GNUmed.\n'),
50 caption = _('Showing ATC codes.'),
51 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
52 single_selection = True,
53 refresh_callback = refresh
54 )
55
56
69
70 def refresh(lctrl):
71 substs = gmMedication.get_substances_in_brands()
72 items = [ [
73 u'%s%s' % (s['brand'], gmTools.coalesce(s['atc_brand'], u'', u' (%s)')),
74 s['substance'],
75 gmTools.coalesce(s['atc_substance'], u''),
76 s['preparation'],
77 gmTools.coalesce(s['external_code_brand'], u'', u'%%s [%s]' % s['external_code_type_brand']),
78 s['pk_substance_in_brand']
79 ] for s in substs ]
80 lctrl.set_string_items(items)
81 lctrl.set_data(substs)
82
83 msg = _('\nThese are the substances in the drug brands known to GNUmed.\n')
84
85 gmListWidgets.get_choices_from_list (
86 parent = parent,
87 msg = msg,
88 caption = _('Showing drug brand components (substances).'),
89 columns = [_('Brand'), _('Substance'), u'ATC', _('Preparation'), _('Code'), u'#'],
90 single_selection = True,
91
92
93 delete_callback = delete,
94 refresh_callback = refresh
95 )
96
105
106 def new():
107 drug_db = get_drug_database(parent = parent)
108
109 if drug_db is None:
110 return False
111
112 drug_db.import_drugs()
113
114 return True
115
116 def refresh(lctrl):
117 drugs = gmMedication.get_branded_drugs()
118 items = [ [
119 d['description'],
120 d['preparation'],
121 gmTools.coalesce(d['atc_code'], u''),
122 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
123 d['pk']
124 ] for d in drugs ]
125 lctrl.set_string_items(items)
126 lctrl.set_data(drugs)
127
128 msg = _('\nThese are the drug brands known to GNUmed.\n')
129
130 gmListWidgets.get_choices_from_list (
131 parent = parent,
132 msg = msg,
133 caption = _('Showing branded drugs.'),
134 columns = [_('Name'), _('Preparation'), _('ATC'), _('Code'), u'#'],
135 single_selection = True,
136 refresh_callback = refresh,
137 new_callback = new,
138
139 delete_callback = delete
140 )
141
143
144 if parent is None:
145 parent = wx.GetApp().GetTopWindow()
146
147 def delete(substance):
148 gmMedication.delete_used_substance(substance = substance['pk'])
149 return True
150
151 def new():
152 drug_db = get_drug_database(parent = parent)
153
154 if drug_db is None:
155 return False
156
157 drug_db.import_drugs()
158
159 return True
160
161 def refresh(lctrl):
162 substs = gmMedication.get_substances_in_use()
163 items = [ [
164 s['description'],
165 gmTools.coalesce(s['atc_code'], u''),
166 s['pk']
167 ] for s in substs ]
168 lctrl.set_string_items(items)
169 lctrl.set_data(substs)
170
171 msg = _('\nThese are the substances currently or previously\nconsumed across all patients.\n')
172
173 gmListWidgets.get_choices_from_list (
174 parent = parent,
175 msg = msg,
176 caption = _('Showing consumed substances.'),
177 columns = [_('Name'), _('ATC'), u'#'],
178 single_selection = True,
179 refresh_callback = refresh,
180 new_callback = new,
181
182 delete_callback = delete
183 )
184
185
186
204
234
244
246
247 dbcfg = gmCfg.cCfgSQL()
248
249 ifap_cmd = dbcfg.get2 (
250 option = 'external.ifap-win.shell_command',
251 workplace = gmSurgery.gmCurrentPractice().active_workplace,
252 bias = 'workplace',
253 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
254 )
255 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
256 if not found:
257 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
258 return False
259 ifap_cmd = binary
260
261 if import_drugs:
262 transfer_file = os.path.expanduser(dbcfg.get2 (
263 option = 'external.ifap-win.transfer_file',
264 workplace = gmSurgery.gmCurrentPractice().active_workplace,
265 bias = 'workplace',
266 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
267 ))
268
269 try:
270 f = open(transfer_file, 'w+b').close()
271 except IOError:
272 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
273 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
274 return False
275
276 wx.BeginBusyCursor()
277 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
278 wx.EndBusyCursor()
279
280 if import_drugs:
281
282
283 try:
284 csv_file = open(transfer_file, 'rb')
285 except:
286 _log.exception('cannot access [%s]', fname)
287 csv_file = None
288
289 if csv_file is not None:
290 import csv
291 csv_lines = csv.DictReader (
292 csv_file,
293 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
294 delimiter = ';'
295 )
296 pat = gmPerson.gmCurrentPatient()
297 emr = pat.get_emr()
298
299 epi = emr.add_episode(episode_name = _('Current medication'))
300 for line in csv_lines:
301 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
302 line['Packungszahl'].strip(),
303 line['Handelsname'].strip(),
304 line['Form'].strip(),
305 line[u'Packungsgr\xf6\xdfe'].strip(),
306 line['Abpackungsmenge'].strip(),
307 line['Einheit'].strip(),
308 line['Hersteller'].strip(),
309 line['PZN'].strip()
310 )
311 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
312 csv_file.close()
313
314 return True
315
317
318 dlg = wx.FileDialog (
319 parent = None,
320 message = _('Choose an ATC import config file'),
321 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
322 defaultFile = '',
323 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
324 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
325 )
326
327 result = dlg.ShowModal()
328 if result == wx.ID_CANCEL:
329 return
330
331 cfg_file = dlg.GetPath()
332 dlg.Destroy()
333
334 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
335 if conn is None:
336 return False
337
338 wx.BeginBusyCursor()
339
340 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
341 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
342 else:
343 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
344
345 wx.EndBusyCursor()
346 return True
347
348
349
350
352
354
355 query = u"""
356 SELECT schedule as sched, schedule
357 FROM clin.substance_intake
358 where schedule %(fragment_condition)s
359 ORDER BY sched
360 LIMIT 50"""
361
362 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
363 mp.setThresholds(1, 2, 4)
364 mp.word_separators = '[ \t=+&:@]+'
365 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
366 self.SetToolTipString(_('The schedule for taking this substance.'))
367 self.matcher = mp
368 self.selection_only = False
369
371
373
374 query = u"""
375 (
376 SELECT preparation as prep, preparation
377 FROM ref.branded_drug
378 where preparation %(fragment_condition)s
379 ) union (
380 SELECT preparation as prep, preparation
381 FROM clin.substance_intake
382 where preparation %(fragment_condition)s
383 )
384 order by prep
385 limit 30"""
386
387 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
388 mp.setThresholds(1, 2, 4)
389 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
390 self.SetToolTipString(_('The preparation (form) of the substance the patient is taking.'))
391 self.matcher = mp
392 self.selection_only = False
393
395
397
398 query = u"""
399 (
400 SELECT pk, (coalesce(atc_code || ': ', '') || description) as subst
401 FROM clin.consumed_substance
402 WHERE description %(fragment_condition)s
403 ) union (
404 SELECT NULL, (coalesce(atc_code || ': ', '') || description) as subst
405 FROM ref.substance_in_brand
406 WHERE description %(fragment_condition)s
407 ) union (
408 SELECT NULL, (atc || ': ' || term) as subst
409 FROM ref.v_atc
410 WHERE
411 is_group_code IS FALSE
412 AND
413 term %(fragment_condition)s
414 )
415 order by subst
416 limit 50"""
417
418 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
419 mp.setThresholds(1, 2, 4)
420 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
421 self.SetToolTipString(_('The INN / substance the patient is taking.'))
422 self.matcher = mp
423 self.selection_only = False
424
426
428
429 query = u"""
430 SELECT pk, (coalesce(atc_code || ': ', '') || description || ' (' || preparation || ')') as brand
431 FROM ref.branded_drug
432 WHERE description %(fragment_condition)s
433 ORDER BY brand
434 LIMIT 50"""
435
436 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
437 mp.setThresholds(2, 3, 4)
438 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
439 self.SetToolTipString(_('The brand name of the drug the patient is taking.'))
440 self.matcher = mp
441 self.selection_only = False
442
443
444 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
445
446 -class cCurrentMedicationEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
447
464
470
472 emr = gmPerson.gmCurrentPatient().get_emr()
473
474 state = emr.allergy_state
475 if state['last_confirmed'] is None:
476 confirmed = _('never')
477 else:
478 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
479 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
480 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
481 msg += u'\n'
482
483 for allergy in emr.get_allergies():
484 msg += u'%s (%s, %s): %s\n' % (
485 allergy['descriptor'],
486 allergy['l10n_type'],
487 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
488 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
489 )
490
491 self._LBL_allergies.SetLabel(msg)
492
494
495 if self._PRW_brand.GetData() is None:
496 self._TCTRL_brand_ingredients.SetValue(u'')
497 if self.data is None:
498 return
499 if self.data['pk_brand'] is None:
500 return
501 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand'])
502
503 brand = gmMedication.cBrandedDrug(aPK_obj = self._PRW_brand.GetData())
504
505 if self.data is None:
506 self._PRW_preparation.SetText(brand['preparation'], None)
507 else:
508 self._PRW_preparation.SetText (
509 gmTools.coalesce(self.data['preparation'], brand['preparation']),
510 self.data['preparation']
511 )
512
513 comps = brand.components
514
515 if comps is None:
516 return
517
518 if len(comps) == 0:
519 return
520
521 comps = u' / '.join([ u'%s%s' % (c['description'], gmTools.coalesce(c['atc_code'], u'', u' (%s)')) for c in comps ])
522 self._TCTRL_brand_ingredients.SetValue(comps)
523
524
525
576
662
713
715 self._PRW_substance.SetText(u'', None)
716 self._PRW_strength.SetText(u'', None)
717
718 self._PRW_schedule.SetText(u'', None)
719 self._PRW_duration.SetText(u'', None)
720 self._PRW_aim.SetText(u'', None)
721 self._PRW_notes.SetText(u'', None)
722 self._PRW_episode.SetText(u'', None)
723
724 self._CHBOX_long_term.SetValue(False)
725 self._CHBOX_approved.SetValue(True)
726
727 self._DP_started.SetValue(gmDateTime.pydt_now_here())
728 self._DP_discontinued.SetValue(None)
729 self._PRW_discontinue_reason.SetValue(u'')
730
731 self.__refresh_brand_and_components()
732 self.__refresh_allergies()
733
734 self._PRW_substance.SetFocus()
735
737
738 self._PRW_substance.SetText(self.data['substance'], self.data['pk_substance'])
739 self._PRW_strength.SetText(gmTools.coalesce(self.data['strength'], u''), self.data['strength'])
740
741 if self.data['is_long_term']:
742 self._CHBOX_long_term.SetValue(True)
743 self._PRW_duration.Enable(False)
744 self._PRW_duration.SetText(gmTools.u_infinity, None)
745 self._BTN_discontinued_as_planned.Enable(False)
746 else:
747 self._CHBOX_long_term.SetValue(False)
748 self._PRW_duration.Enable(True)
749 self._BTN_discontinued_as_planned.Enable(True)
750 if self.data['duration'] is None:
751 self._PRW_duration.SetText(u'', None)
752 else:
753 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
754 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
755 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
756 self._PRW_episode.SetData(self.data['pk_episode'])
757 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
758
759 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
760
761 self._DP_started.SetValue(self.data['started'])
762 self._DP_discontinued.SetValue(self.data['discontinued'])
763 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
764
765 self.__refresh_brand_and_components()
766 self.__refresh_allergies()
767
768 self._PRW_substance.SetFocus()
769
771 self._refresh_as_new()
772
773
774
776 self.__refresh_brand_and_components()
777
779 if self._DP_discontinued.GetValue() is None:
780 self._PRW_discontinue_reason.Enable(False)
781 self._CHBOX_is_allergy.Enable(False)
782 else:
783 self._PRW_discontinue_reason.Enable(True)
784 self._CHBOX_is_allergy.Enable(True)
785
804
826
855
857 if self._CHBOX_long_term.IsChecked() is True:
858 self._PRW_duration.Enable(False)
859 self._BTN_discontinued_as_planned.Enable(False)
860 self._PRW_discontinue_reason.Enable(False)
861 self._CHBOX_is_allergy.Enable(False)
862 else:
863 self._PRW_duration.Enable(True)
864 self._BTN_discontinued_as_planned.Enable(True)
865 self._PRW_discontinue_reason.Enable(True)
866 self._CHBOX_is_allergy.Enable(True)
867
868 self.__refresh_allergies()
869
871 if self._CHBOX_is_allergy.IsChecked() is True:
872 val = self._PRW_discontinue_reason.GetValue().strip()
873 if not val.startswith(_('not tolerated:')):
874 self._PRW_discontinue_reason.SetValue(u'%s %s' % (_('not tolerated:'), val))
875
876 self.__refresh_allergies()
877
879 delete_it = gmGuiHelpers.gm_show_question (
880 aMessage = _(
881 'Do you really want to remove this substance intake ?\n'
882 '\n'
883 'It may be prudent to edit the details first so as to\n'
884 'leave behind some indication of why it was deleted.\n'
885 ),
886 aTitle = _('Deleting medication / substance intake')
887 )
888 if not delete_it:
889 return
890
891 gmMedication.delete_substance_intake(substance = substance)
892
902
903
904
932
934
935 if parent is None:
936 parent = wx.GetApp().GetTopWindow()
937
938
939 dbcfg = gmCfg.cCfgSQL()
940 option = u'form_templates.medication_list'
941
942 template = dbcfg.get2 (
943 option = option,
944 workplace = gmSurgery.gmCurrentPractice().active_workplace,
945 bias = 'user'
946 )
947
948 if template is None:
949 template = configure_medication_list_template(parent = parent)
950 if template is None:
951 gmGuiHelpers.gm_show_error (
952 aMessage = _('There is no medication list template configured.'),
953 aTitle = _('Printing medication list')
954 )
955 return False
956 else:
957 try:
958 name, ver = template.split(u' - ')
959 except:
960 _log.exception('problem splitting medication list template name [%s]', template)
961 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
962 return False
963 template = gmForms.get_form_template(name_long = name, external_version = ver)
964 if template is None:
965 gmGuiHelpers.gm_show_error (
966 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
967 aTitle = _('Printing medication list')
968 )
969 return False
970
971
972 try:
973 meds_list = template.instantiate()
974 except KeyError:
975 _log.exception('cannot instantiate medication list template [%s]', template)
976 gmGuiHelpers.gm_show_error (
977 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
978 aTitle = _('Printing medication list')
979 )
980 return False
981
982 ph = gmMacro.gmPlaceholderHandler()
983
984 meds_list.substitute_placeholders(data_source = ph)
985 pdf_name = meds_list.generate_output(cleanup = cleanup)
986 if cleanup:
987 meds_list.cleanup()
988 if pdf_name is None:
989 gmGuiHelpers.gm_show_error (
990 aMessage = _('Error generating the medication list.'),
991 aTitle = _('Printing medication list')
992 )
993 return False
994
995
996 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
997 if not printed:
998 gmGuiHelpers.gm_show_error (
999 aMessage = _('Error printing the medication list.'),
1000 aTitle = _('Printing medication list')
1001 )
1002 return False
1003
1004 pat = gmPerson.gmCurrentPatient()
1005 emr = pat.get_emr()
1006 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1007 emr.add_clin_narrative (
1008 soap_cat = None,
1009 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1010 episode = epi
1011 )
1012
1013 return True
1014
1016 """A grid class for displaying current substance intake.
1017
1018 - does NOT listen to the currently active patient
1019 - thereby it can display any patient at any time
1020 """
1022
1023 wx.grid.Grid.__init__(self, *args, **kwargs)
1024
1025 self.__patient = None
1026 self.__row_data = {}
1027 self.__prev_row = None
1028 self.__prev_tooltip_row = None
1029 self.__prev_cell_0 = None
1030 self.__grouping_mode = u'episode'
1031 self.__filter_show_unapproved = False
1032 self.__filter_show_inactive = False
1033
1034 self.__grouping2col_labels = {
1035 u'episode': [
1036 _('Episode'),
1037 _('Substance'),
1038 _('Dose'),
1039 _('Schedule'),
1040 _('Started'),
1041 _('Duration'),
1042 _('Brand')
1043 ],
1044 u'brand': [
1045 _('Brand'),
1046 _('Schedule'),
1047 _('Substance'),
1048 _('Dose'),
1049 _('Started'),
1050 _('Duration'),
1051 _('Episode')
1052 ]
1053 }
1054
1055 self.__grouping2order_by_clauses = {
1056 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1057 u'brand': u'brand nulls last, substance, started'
1058 }
1059
1060 self.__init_ui()
1061 self.__register_events()
1062
1063
1064
1066
1067 sel_block_top_left = self.GetSelectionBlockTopLeft()
1068 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1069 sel_cols = self.GetSelectedCols()
1070 sel_rows = self.GetSelectedRows()
1071
1072 selected_cells = []
1073
1074
1075 selected_cells += self.GetSelectedCells()
1076
1077
1078 selected_cells += list (
1079 (row, col)
1080 for row in sel_rows
1081 for col in xrange(self.GetNumberCols())
1082 )
1083
1084
1085 selected_cells += list (
1086 (row, col)
1087 for row in xrange(self.GetNumberRows())
1088 for col in sel_cols
1089 )
1090
1091
1092 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1093 selected_cells += [
1094 (row, col)
1095 for row in xrange(top_left[0], bottom_right[0] + 1)
1096 for col in xrange(top_left[1], bottom_right[1] + 1)
1097 ]
1098
1099 return set(selected_cells)
1100
1102 rows = {}
1103
1104 for row, col in self.get_selected_cells():
1105 rows[row] = True
1106
1107 return rows.keys()
1108
1111
1113
1114 self.empty_grid()
1115
1116 if self.__patient is None:
1117 return
1118
1119 emr = self.__patient.get_emr()
1120 meds = emr.get_current_substance_intake (
1121 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1122 include_unapproved = self.__filter_show_unapproved,
1123 include_inactive = self.__filter_show_inactive
1124 )
1125 if not meds:
1126 return
1127
1128 self.BeginBatch()
1129
1130
1131 labels = self.__grouping2col_labels[self.__grouping_mode]
1132 if self.__filter_show_unapproved:
1133 self.AppendCols(numCols = len(labels) + 1)
1134 else:
1135 self.AppendCols(numCols = len(labels))
1136 for col_idx in range(len(labels)):
1137 self.SetColLabelValue(col_idx, labels[col_idx])
1138 if self.__filter_show_unapproved:
1139 self.SetColLabelValue(len(labels), u'OK?')
1140 self.SetColSize(len(labels), 40)
1141
1142 self.AppendRows(numRows = len(meds))
1143
1144
1145 for row_idx in range(len(meds)):
1146 med = meds[row_idx]
1147 self.__row_data[row_idx] = med
1148
1149 if med['is_currently_active'] is True:
1150 atcs = []
1151 if med['atc_substance'] is not None:
1152 atcs.append(med['atc_substance'])
1153 if med['atc_brand'] is not None:
1154 atcs.append(med['atc_brand'])
1155 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand'])
1156 if allg not in [None, False]:
1157 attr = self.GetOrCreateCellAttr(row_idx, 0)
1158 if allg['type'] == u'allergy':
1159 attr.SetTextColour('red')
1160 else:
1161 attr.SetTextColour('yellow')
1162 self.SetRowAttr(row_idx, attr)
1163 else:
1164 attr = self.GetOrCreateCellAttr(row_idx, 0)
1165 attr.SetTextColour('grey')
1166 self.SetRowAttr(row_idx, attr)
1167
1168 if self.__grouping_mode == u'episode':
1169 if med['pk_episode'] is None:
1170 self.__prev_cell_0 = None
1171 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1172 else:
1173 if self.__prev_cell_0 != med['episode']:
1174 self.__prev_cell_0 = med['episode']
1175 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
1176
1177 self.SetCellValue(row_idx, 1, med['substance'])
1178 self.SetCellValue(row_idx, 2, gmTools.coalesce(med['strength'], u''))
1179 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1180 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1181
1182 if med['is_long_term']:
1183 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1184 else:
1185 if med['duration'] is None:
1186 self.SetCellValue(row_idx, 5, u'')
1187 else:
1188 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1189
1190 if med['pk_brand'] is None:
1191 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1192 else:
1193 if med['fake_brand']:
1194 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1195 else:
1196 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1197
1198 elif self.__grouping_mode == u'brand':
1199
1200 if med['pk_brand'] is None:
1201 self.__prev_cell_0 = None
1202 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1203 else:
1204 if self.__prev_cell_0 != med['brand']:
1205 self.__prev_cell_0 = med['brand']
1206 if med['fake_brand']:
1207 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1208 else:
1209 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1210
1211 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1212 self.SetCellValue(row_idx, 2, med['substance'])
1213 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['strength'], u''))
1214 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1215
1216 if med['is_long_term']:
1217 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1218 else:
1219 if med['duration'] is None:
1220 self.SetCellValue(row_idx, 5, u'')
1221 else:
1222 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1223
1224 if med['pk_episode'] is None:
1225 self.SetCellValue(row_idx, 6, u'')
1226 else:
1227 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1228
1229 else:
1230 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1231
1232 if self.__filter_show_unapproved:
1233 self.SetCellValue (
1234 row_idx,
1235 len(labels),
1236 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1237 )
1238
1239
1240
1241 self.EndBatch()
1242
1244 self.BeginBatch()
1245 self.ClearGrid()
1246
1247
1248 if self.GetNumberRows() > 0:
1249 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1250 if self.GetNumberCols() > 0:
1251 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1252 self.EndBatch()
1253 self.__row_data = {}
1254 self.__prev_cell_0 = None
1255
1257
1258 if len(self.__row_data) == 0:
1259 return
1260
1261 sel_rows = self.get_selected_rows()
1262 if len(sel_rows) != 1:
1263 return
1264
1265 drug_db = get_drug_database()
1266 if drug_db is None:
1267 return
1268
1269 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1270
1286
1288
1289 dbcfg = gmCfg.cCfgSQL()
1290
1291 url = dbcfg.get2 (
1292 option = u'external.urls.report_ADR',
1293 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1294 bias = u'user',
1295 default = u'https://dcgma.org/uaw/meldung.php'
1296 )
1297
1298 webbrowser.open(url = url, new = False, autoraise = True)
1299
1313
1316
1330
1332
1333 rows = self.get_selected_rows()
1334
1335 if len(rows) == 0:
1336 return
1337
1338 if len(rows) > 1:
1339 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1340 return
1341
1342 subst = self.get_selected_data()[0]
1343 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1344
1366
1371
1479
1480
1481
1483 self.CreateGrid(0, 1)
1484 self.EnableEditing(0)
1485 self.EnableDragGridSize(1)
1486 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
1487
1488 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
1489
1490 self.SetRowLabelSize(0)
1491 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1492
1493
1494
1496 return self.__patient
1497
1501
1502 patient = property(_get_patient, _set_patient)
1503
1505 return self.__grouping_mode
1506
1510
1511 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
1512
1514 return self.__filter_show_unapproved
1515
1519
1520 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
1521
1523 return self.__filter_show_inactive
1524
1528
1529 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
1530
1531
1532
1534
1535 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1536
1537
1538
1539
1540 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1541
1543 """Calculate where the mouse is and set the tooltip dynamically."""
1544
1545
1546
1547 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561 row, col = self.XYToCell(x, y)
1562
1563 if row == self.__prev_tooltip_row:
1564 return
1565
1566 self.__prev_tooltip_row = row
1567
1568 try:
1569 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1570 except KeyError:
1571 pass
1572
1577
1578 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
1579
1580 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
1581
1582 """Panel holding a grid with current substances. Used as notebook page."""
1583
1590
1591
1592
1601
1602
1603
1605 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1606 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
1607 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
1608
1609
1610
1612 wx.CallAfter(self.__on_pre_patient_selection)
1613
1615 self._grid_substances.patient = None
1616
1619
1622
1625
1628
1631
1634
1637
1640
1643
1646
1649
1652
1655
1656
1657
1658 if __name__ == '__main__':
1659
1660 if len(sys.argv) < 2:
1661 sys.exit()
1662
1663 if sys.argv[1] != 'test':
1664 sys.exit()
1665
1666 from Gnumed.pycommon import gmI18N
1667
1668 gmI18N.activate_locale()
1669 gmI18N.install_domain(domain = 'gnumed')
1670
1671
1672
1673 pass
1674
1675
1676