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.SetData(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 self._PRW_substance.SetText(u'', None)
774 self._PRW_strength.SetText(u'', None)
775 self._PRW_notes.SetText(u'', None)
776
777 self.__refresh_brand_and_components()
778 self.__refresh_allergies()
779
780 self._PRW_substance.SetFocus()
781
782
783
785 self.__refresh_brand_and_components()
786
788 if self._DP_discontinued.GetValue() is None:
789 self._PRW_discontinue_reason.Enable(False)
790 self._CHBOX_is_allergy.Enable(False)
791 else:
792 self._PRW_discontinue_reason.Enable(True)
793 self._CHBOX_is_allergy.Enable(True)
794
813
835
864
866 if self._CHBOX_long_term.IsChecked() is True:
867 self._PRW_duration.Enable(False)
868 self._BTN_discontinued_as_planned.Enable(False)
869 self._PRW_discontinue_reason.Enable(False)
870 self._CHBOX_is_allergy.Enable(False)
871 else:
872 self._PRW_duration.Enable(True)
873 self._BTN_discontinued_as_planned.Enable(True)
874 self._PRW_discontinue_reason.Enable(True)
875 self._CHBOX_is_allergy.Enable(True)
876
877 self.__refresh_allergies()
878
880 if self._CHBOX_is_allergy.IsChecked() is True:
881 val = self._PRW_discontinue_reason.GetValue().strip()
882 if not val.startswith(_('not tolerated:')):
883 self._PRW_discontinue_reason.SetValue(u'%s %s' % (_('not tolerated:'), val))
884
885 self.__refresh_allergies()
886
888 delete_it = gmGuiHelpers.gm_show_question (
889 aMessage = _(
890 'Do you really want to remove this substance intake ?\n'
891 '\n'
892 'It may be prudent to edit the details first so as to\n'
893 'leave behind some indication of why it was deleted.\n'
894 ),
895 aTitle = _('Deleting medication / substance intake')
896 )
897 if not delete_it:
898 return
899
900 gmMedication.delete_substance_intake(substance = substance)
901
911
912
913
938
940
941 if parent is None:
942 parent = wx.GetApp().GetTopWindow()
943
944
945 dbcfg = gmCfg.cCfgSQL()
946 option = u'form_templates.medication_list'
947
948 template = dbcfg.get2 (
949 option = option,
950 workplace = gmSurgery.gmCurrentPractice().active_workplace,
951 bias = 'user'
952 )
953
954 if template is None:
955 template = configure_medication_list_template(parent = parent)
956 if template is None:
957 gmGuiHelpers.gm_show_error (
958 aMessage = _('There is no medication list template configured.'),
959 aTitle = _('Printing medication list')
960 )
961 return False
962 else:
963 try:
964 name, ver = template.split(u' - ')
965 except:
966 _log.exception('problem splitting medication list template name [%s]', template)
967 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
968 return False
969 template = gmForms.get_form_template(name_long = name, external_version = ver)
970 if template is None:
971 gmGuiHelpers.gm_show_error (
972 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
973 aTitle = _('Printing medication list')
974 )
975 return False
976
977
978 try:
979 meds_list = template.instantiate()
980 except KeyError:
981 _log.exception('cannot instantiate medication list template [%s]', template)
982 gmGuiHelpers.gm_show_error (
983 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
984 aTitle = _('Printing medication list')
985 )
986 return False
987
988 ph = gmMacro.gmPlaceholderHandler()
989
990 meds_list.substitute_placeholders(data_source = ph)
991 pdf_name = meds_list.generate_output(cleanup = cleanup)
992 if cleanup:
993 meds_list.cleanup()
994 if pdf_name is None:
995 gmGuiHelpers.gm_show_error (
996 aMessage = _('Error generating the medication list.'),
997 aTitle = _('Printing medication list')
998 )
999 return False
1000
1001
1002 printed = gmPrinting.print_file_by_shellscript(filename = pdf_name, jobtype = 'medication_list')
1003 if not printed:
1004 gmGuiHelpers.gm_show_error (
1005 aMessage = _('Error printing the medication list.'),
1006 aTitle = _('Printing medication list')
1007 )
1008 return False
1009
1010 pat = gmPerson.gmCurrentPatient()
1011 emr = pat.get_emr()
1012 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1013 emr.add_clin_narrative (
1014 soap_cat = None,
1015 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1016 episode = epi
1017 )
1018
1019 return True
1020
1022 """A grid class for displaying current substance intake.
1023
1024 - does NOT listen to the currently active patient
1025 - thereby it can display any patient at any time
1026 """
1028
1029 wx.grid.Grid.__init__(self, *args, **kwargs)
1030
1031 self.__patient = None
1032 self.__row_data = {}
1033 self.__prev_row = None
1034 self.__prev_tooltip_row = None
1035 self.__prev_cell_0 = None
1036 self.__grouping_mode = u'episode'
1037 self.__filter_show_unapproved = False
1038 self.__filter_show_inactive = False
1039
1040 self.__grouping2col_labels = {
1041 u'episode': [
1042 _('Episode'),
1043 _('Substance'),
1044 _('Dose'),
1045 _('Schedule'),
1046 _('Started'),
1047 _('Duration'),
1048 _('Brand')
1049 ],
1050 u'brand': [
1051 _('Brand'),
1052 _('Schedule'),
1053 _('Substance'),
1054 _('Dose'),
1055 _('Started'),
1056 _('Duration'),
1057 _('Episode')
1058 ]
1059 }
1060
1061 self.__grouping2order_by_clauses = {
1062 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1063 u'brand': u'brand nulls last, substance, started'
1064 }
1065
1066 self.__init_ui()
1067 self.__register_events()
1068
1069
1070
1072
1073 sel_block_top_left = self.GetSelectionBlockTopLeft()
1074 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1075 sel_cols = self.GetSelectedCols()
1076 sel_rows = self.GetSelectedRows()
1077
1078 selected_cells = []
1079
1080
1081 selected_cells += self.GetSelectedCells()
1082
1083
1084 selected_cells += list (
1085 (row, col)
1086 for row in sel_rows
1087 for col in xrange(self.GetNumberCols())
1088 )
1089
1090
1091 selected_cells += list (
1092 (row, col)
1093 for row in xrange(self.GetNumberRows())
1094 for col in sel_cols
1095 )
1096
1097
1098 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1099 selected_cells += [
1100 (row, col)
1101 for row in xrange(top_left[0], bottom_right[0] + 1)
1102 for col in xrange(top_left[1], bottom_right[1] + 1)
1103 ]
1104
1105 return set(selected_cells)
1106
1108 rows = {}
1109
1110 for row, col in self.get_selected_cells():
1111 rows[row] = True
1112
1113 return rows.keys()
1114
1117
1119
1120 self.empty_grid()
1121
1122 if self.__patient is None:
1123 return
1124
1125 emr = self.__patient.get_emr()
1126 meds = emr.get_current_substance_intake (
1127 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1128 include_unapproved = self.__filter_show_unapproved,
1129 include_inactive = self.__filter_show_inactive
1130 )
1131 if not meds:
1132 return
1133
1134 self.BeginBatch()
1135
1136
1137 labels = self.__grouping2col_labels[self.__grouping_mode]
1138 if self.__filter_show_unapproved:
1139 self.AppendCols(numCols = len(labels) + 1)
1140 else:
1141 self.AppendCols(numCols = len(labels))
1142 for col_idx in range(len(labels)):
1143 self.SetColLabelValue(col_idx, labels[col_idx])
1144 if self.__filter_show_unapproved:
1145 self.SetColLabelValue(len(labels), u'OK?')
1146 self.SetColSize(len(labels), 40)
1147
1148 self.AppendRows(numRows = len(meds))
1149
1150
1151 for row_idx in range(len(meds)):
1152 med = meds[row_idx]
1153 self.__row_data[row_idx] = med
1154
1155 if med['is_currently_active'] is True:
1156 atcs = []
1157 if med['atc_substance'] is not None:
1158 atcs.append(med['atc_substance'])
1159 if med['atc_brand'] is not None:
1160 atcs.append(med['atc_brand'])
1161 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand'])
1162 if allg not in [None, False]:
1163 attr = self.GetOrCreateCellAttr(row_idx, 0)
1164 if allg['type'] == u'allergy':
1165 attr.SetTextColour('red')
1166 else:
1167 attr.SetTextColour('yellow')
1168 self.SetRowAttr(row_idx, attr)
1169 else:
1170 attr = self.GetOrCreateCellAttr(row_idx, 0)
1171 attr.SetTextColour('grey')
1172 self.SetRowAttr(row_idx, attr)
1173
1174 if self.__grouping_mode == u'episode':
1175 if med['pk_episode'] is None:
1176 self.__prev_cell_0 = None
1177 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1178 else:
1179 if self.__prev_cell_0 != med['episode']:
1180 self.__prev_cell_0 = med['episode']
1181 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['episode'], u''))
1182
1183 self.SetCellValue(row_idx, 1, med['substance'])
1184 self.SetCellValue(row_idx, 2, gmTools.coalesce(med['strength'], u''))
1185 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1186 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1187
1188 if med['is_long_term']:
1189 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1190 else:
1191 if med['duration'] is None:
1192 self.SetCellValue(row_idx, 5, u'')
1193 else:
1194 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1195
1196 if med['pk_brand'] is None:
1197 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1198 else:
1199 if med['fake_brand']:
1200 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1201 else:
1202 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['brand'], u''))
1203
1204 elif self.__grouping_mode == u'brand':
1205
1206 if med['pk_brand'] is None:
1207 self.__prev_cell_0 = None
1208 self.SetCellValue(row_idx, 0, gmTools.u_diameter)
1209 else:
1210 if self.__prev_cell_0 != med['brand']:
1211 self.__prev_cell_0 = med['brand']
1212 if med['fake_brand']:
1213 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u'', _('%s (fake)')))
1214 else:
1215 self.SetCellValue(row_idx, 0, gmTools.coalesce(med['brand'], u''))
1216
1217 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1218 self.SetCellValue(row_idx, 2, med['substance'])
1219 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['strength'], u''))
1220 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1221
1222 if med['is_long_term']:
1223 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1224 else:
1225 if med['duration'] is None:
1226 self.SetCellValue(row_idx, 5, u'')
1227 else:
1228 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1229
1230 if med['pk_episode'] is None:
1231 self.SetCellValue(row_idx, 6, u'')
1232 else:
1233 self.SetCellValue(row_idx, 6, gmTools.coalesce(med['episode'], u''))
1234
1235 else:
1236 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
1237
1238 if self.__filter_show_unapproved:
1239 self.SetCellValue (
1240 row_idx,
1241 len(labels),
1242 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
1243 )
1244
1245
1246
1247 self.EndBatch()
1248
1250 self.BeginBatch()
1251 self.ClearGrid()
1252
1253
1254 if self.GetNumberRows() > 0:
1255 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
1256 if self.GetNumberCols() > 0:
1257 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
1258 self.EndBatch()
1259 self.__row_data = {}
1260 self.__prev_cell_0 = None
1261
1263
1264 if len(self.__row_data) == 0:
1265 return
1266
1267 sel_rows = self.get_selected_rows()
1268 if len(sel_rows) != 1:
1269 return
1270
1271 drug_db = get_drug_database()
1272 if drug_db is None:
1273 return
1274
1275 drug_db.show_info_on_substance(substance = self.get_selected_data()[0])
1276
1292
1294
1295 dbcfg = gmCfg.cCfgSQL()
1296
1297 url = dbcfg.get2 (
1298 option = u'external.urls.report_ADR',
1299 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1300 bias = u'user',
1301 default = u'https://dcgma.org/uaw/meldung.php'
1302 )
1303
1304 webbrowser.open(url = url, new = False, autoraise = True)
1305
1319
1322
1336
1338
1339 rows = self.get_selected_rows()
1340
1341 if len(rows) == 0:
1342 return
1343
1344 if len(rows) > 1:
1345 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
1346 return
1347
1348 subst = self.get_selected_data()[0]
1349 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
1350
1372
1377
1485
1486
1487
1489 self.CreateGrid(0, 1)
1490 self.EnableEditing(0)
1491 self.EnableDragGridSize(1)
1492 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
1493
1494 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
1495
1496 self.SetRowLabelSize(0)
1497 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
1498
1499
1500
1502 return self.__patient
1503
1507
1508 patient = property(_get_patient, _set_patient)
1509
1511 return self.__grouping_mode
1512
1516
1517 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
1518
1520 return self.__filter_show_unapproved
1521
1525
1526 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
1527
1529 return self.__filter_show_inactive
1530
1534
1535 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
1536
1537
1538
1540
1541 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
1542
1543
1544
1545
1546 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
1547
1549 """Calculate where the mouse is and set the tooltip dynamically."""
1550
1551
1552
1553 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567 row, col = self.XYToCell(x, y)
1568
1569 if row == self.__prev_tooltip_row:
1570 return
1571
1572 self.__prev_tooltip_row = row
1573
1574 try:
1575 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
1576 except KeyError:
1577 pass
1578
1583
1584 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
1585
1586 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
1587
1588 """Panel holding a grid with current substances. Used as notebook page."""
1589
1596
1597
1598
1607
1608
1609
1611 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
1612 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
1613 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
1614
1615
1616
1618 wx.CallAfter(self.__on_pre_patient_selection)
1619
1621 self._grid_substances.patient = None
1622
1625
1628
1631
1634
1637
1640
1643
1646
1649
1652
1655
1658
1661
1662
1663
1664 if __name__ == '__main__':
1665
1666 if len(sys.argv) < 2:
1667 sys.exit()
1668
1669 if sys.argv[1] != 'test':
1670 sys.exit()
1671
1672 from Gnumed.pycommon import gmI18N
1673
1674 gmI18N.activate_locale()
1675 gmI18N.install_domain(domain = 'gnumed')
1676
1677
1678
1679 pass
1680
1681
1682