1 """GNUmed medication/substances handling widgets."""
2
3
4 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
5 __license__ = "GPL v2 or later"
6
7 import logging
8 import sys
9 import os.path
10 import decimal
11
12
13 import wx
14 import wx.grid
15
16
17 if __name__ == '__main__':
18 sys.path.insert(0, '../../')
19 from Gnumed.pycommon import gmDispatcher
20 from Gnumed.pycommon import gmCfg
21 from Gnumed.pycommon import gmTools
22 from Gnumed.pycommon import gmTools
23 from Gnumed.pycommon import gmDateTime
24 from Gnumed.pycommon import gmMatchProvider
25 from Gnumed.pycommon import gmI18N
26 from Gnumed.pycommon import gmPrinting
27 from Gnumed.pycommon import gmCfg2
28 from Gnumed.pycommon import gmNetworkTools
29
30 from Gnumed.business import gmPerson
31 from Gnumed.business import gmATC
32 from Gnumed.business import gmSurgery
33 from Gnumed.business import gmMedication
34 from Gnumed.business import gmForms
35 from Gnumed.business import gmStaff
36 from Gnumed.business import gmDocuments
37
38 from Gnumed.wxpython import gmGuiHelpers
39 from Gnumed.wxpython import gmRegetMixin
40 from Gnumed.wxpython import gmAuthWidgets
41 from Gnumed.wxpython import gmEditArea
42 from Gnumed.wxpython import gmMacro
43 from Gnumed.wxpython import gmCfgWidgets
44 from Gnumed.wxpython import gmListWidgets
45 from Gnumed.wxpython import gmPhraseWheel
46 from Gnumed.wxpython import gmFormWidgets
47 from Gnumed.wxpython import gmAllergyWidgets
48 from Gnumed.wxpython import gmDocumentWidgets
49
50
51 _log = logging.getLogger('gm.ui')
52
53
54
55
73
75 dbcfg = gmCfg.cCfgSQL()
76
77
78 default_db = dbcfg.get2 (
79 option = 'external.drug_data.default_source',
80 workplace = gmSurgery.gmCurrentPractice().active_workplace,
81 bias = 'workplace'
82 )
83
84
85 if default_db is None:
86 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True)
87 configure_drug_data_source(parent = parent)
88 default_db = dbcfg.get2 (
89 option = 'external.drug_data.default_source',
90 workplace = gmSurgery.gmCurrentPractice().active_workplace,
91 bias = 'workplace'
92 )
93
94 if default_db is None:
95 gmGuiHelpers.gm_show_error (
96 aMessage = _('There is no default drug database configured.'),
97 aTitle = _('Jumping to drug database')
98 )
99 return None
100
101
102
103 try:
104 drug_db = gmMedication.drug_data_source_interfaces[default_db]()
105 except KeyError:
106
107 _log.error('faulty default drug data source configuration: %s', default_db)
108
109 configure_drug_data_source(parent = parent)
110 default_db = dbcfg.get2 (
111 option = 'external.drug_data.default_source',
112 workplace = gmSurgery.gmCurrentPractice().active_workplace,
113 bias = 'workplace'
114 )
115
116 try:
117 drug_db = gmMedication.drug_data_source_interfaces[default_db]()
118 except KeyError:
119 _log.error('still faulty default drug data source configuration: %s', default_db)
120 return None
121
122 pat = gmPerson.gmCurrentPatient()
123 if pat.connected:
124 drug_db.patient = pat
125
126 return drug_db
127
134
135
137
138 dbcfg = gmCfg.cCfgSQL()
139
140 ifap_cmd = dbcfg.get2 (
141 option = 'external.ifap-win.shell_command',
142 workplace = gmSurgery.gmCurrentPractice().active_workplace,
143 bias = 'workplace',
144 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
145 )
146 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
147 if not found:
148 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
149 return False
150 ifap_cmd = binary
151
152 if import_drugs:
153 transfer_file = os.path.expanduser(dbcfg.get2 (
154 option = 'external.ifap-win.transfer_file',
155 workplace = gmSurgery.gmCurrentPractice().active_workplace,
156 bias = 'workplace',
157 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
158 ))
159
160 try:
161 f = open(transfer_file, 'w+b').close()
162 except IOError:
163 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
164 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
165 return False
166
167 wx.BeginBusyCursor()
168 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
169 wx.EndBusyCursor()
170
171 if import_drugs:
172
173
174 try:
175 csv_file = open(transfer_file, 'rb')
176 except:
177 _log.exception('cannot access [%s]', fname)
178 csv_file = None
179
180 if csv_file is not None:
181 import csv
182 csv_lines = csv.DictReader (
183 csv_file,
184 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
185 delimiter = ';'
186 )
187 pat = gmPerson.gmCurrentPatient()
188 emr = pat.get_emr()
189
190 epi = emr.add_episode(episode_name = _('Current medication'))
191 for line in csv_lines:
192 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
193 line['Packungszahl'].strip(),
194 line['Handelsname'].strip(),
195 line['Form'].strip(),
196 line[u'Packungsgr\xf6\xdfe'].strip(),
197 line['Abpackungsmenge'].strip(),
198 line['Einheit'].strip(),
199 line['Hersteller'].strip(),
200 line['PZN'].strip()
201 )
202 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
203 csv_file.close()
204
205 return True
206
207
208
209
210
212
213 if parent is None:
214 parent = wx.GetApp().GetTopWindow()
215
216 def refresh(lctrl):
217 atcs = gmATC.get_reference_atcs()
218
219 items = [ [
220 a['atc'],
221 a['term'],
222 u'%s' % gmTools.coalesce(a['ddd'], u''),
223 gmTools.coalesce(a['unit'], u''),
224 gmTools.coalesce(a['administrative_route'], u''),
225 gmTools.coalesce(a['comment'], u''),
226 a['version'],
227 a['lang']
228 ] for a in atcs ]
229 lctrl.set_string_items(items)
230 lctrl.set_data(atcs)
231
232 gmListWidgets.get_choices_from_list (
233 parent = parent,
234 msg = _('\nThe ATC codes as known to GNUmed.\n'),
235 caption = _('Showing ATC codes.'),
236 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
237 single_selection = True,
238 refresh_callback = refresh
239 )
240
241
243
244 dlg = wx.FileDialog (
245 parent = None,
246 message = _('Choose an ATC import config file'),
247 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
248 defaultFile = '',
249 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
250 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
251 )
252
253 result = dlg.ShowModal()
254 if result == wx.ID_CANCEL:
255 return
256
257 cfg_file = dlg.GetPath()
258 dlg.Destroy()
259
260 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
261 if conn is None:
262 return False
263
264 wx.BeginBusyCursor()
265
266 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
267 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
268 else:
269 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
270
271 wx.EndBusyCursor()
272 return True
273
274
275
277
279
280 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
281
282 query = u"""
283
284 SELECT DISTINCT ON (label)
285 atc_code,
286 label
287 FROM (
288
289 SELECT
290 code as atc_code,
291 (code || ': ' || term || coalesce(' (' || ddd || unit || ')', ''))
292 AS label
293 FROM ref.atc
294 WHERE
295 term %(fragment_condition)s
296 OR
297 code %(fragment_condition)s
298
299 UNION ALL
300
301 SELECT
302 atc_code,
303 (atc_code || ': ' || description)
304 AS label
305 FROM ref.consumable_substance
306 WHERE
307 description %(fragment_condition)s
308 OR
309 atc_code %(fragment_condition)s
310
311 UNION ALL
312
313 SELECT
314 atc_code,
315 (atc_code || ': ' || description || ' (' || preparation || ')')
316 AS label
317 FROM ref.branded_drug
318 WHERE
319 description %(fragment_condition)s
320 OR
321 atc_code %(fragment_condition)s
322
323 -- it would be nice to be able to include clin.vacc_indication but that's hard to do in SQL
324
325 ) AS candidates
326 WHERE atc_code IS NOT NULL
327 ORDER BY label
328 LIMIT 50"""
329
330 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
331 mp.setThresholds(1, 2, 4)
332
333 self.SetToolTipString(_('Select an ATC (Anatomical-Therapeutic-Chemical) code.'))
334 self.matcher = mp
335 self.selection_only = True
336
337
338
339
341
342 if parent is None:
343 parent = wx.GetApp().GetTopWindow()
344
345 def add_from_db(substance):
346 drug_db = get_drug_database(parent = parent)
347 if drug_db is None:
348 return False
349 drug_db.import_drugs()
350 return True
351
352 def edit(substance=None):
353 return edit_consumable_substance(parent = parent, substance = substance, single_entry = (substance is not None))
354
355 def delete(substance):
356 if substance.is_in_use_by_patients:
357 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True)
358 return False
359
360 return gmMedication.delete_consumable_substance(substance = substance['pk'])
361
362 def refresh(lctrl):
363 substs = gmMedication.get_consumable_substances(order_by = 'description')
364 items = [ [
365 s['description'],
366 s['amount'],
367 s['unit'],
368 gmTools.coalesce(s['atc_code'], u''),
369 s['pk']
370 ] for s in substs ]
371 lctrl.set_string_items(items)
372 lctrl.set_data(substs)
373
374 msg = _('\nThese are the consumable substances registered with GNUmed.\n')
375
376 gmListWidgets.get_choices_from_list (
377 parent = parent,
378 msg = msg,
379 caption = _('Showing consumable substances.'),
380 columns = [_('Substance'), _('Amount'), _('Unit'), 'ATC', u'#'],
381 single_selection = True,
382 new_callback = edit,
383 edit_callback = edit,
384 delete_callback = delete,
385 refresh_callback = refresh,
386 left_extra_button = (_('Import'), _('Import consumable substances from a drug database.'), add_from_db)
387 )
388
389
391
392 if substance is not None:
393 if substance.is_in_use_by_patients:
394 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True)
395 return False
396
397 ea = cConsumableSubstanceEAPnl(parent = parent, id = -1)
398 ea.data = substance
399 ea.mode = gmTools.coalesce(substance, 'new', 'edit')
400 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
401 dlg.SetTitle(gmTools.coalesce(substance, _('Adding new consumable substance'), _('Editing consumable substance')))
402 if dlg.ShowModal() == wx.ID_OK:
403 dlg.Destroy()
404 return True
405 dlg.Destroy()
406 return False
407
408
409 from Gnumed.wxGladeWidgets import wxgConsumableSubstanceEAPnl
410
412
430
431
432
433
434
435
436
437
439
440 validity = True
441
442 if self._TCTRL_substance.GetValue().strip() == u'':
443 validity = False
444 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = False)
445 self._TCTRL_substance.SetFocus()
446 else:
447 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = True)
448
449 try:
450 decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.'))
451 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
452 except (TypeError, decimal.InvalidOperation):
453 validity = False
454 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
455 self._TCTRL_amount.SetFocus()
456
457 if self._PRW_unit.GetValue().strip() == u'':
458 validity = False
459 self._PRW_unit.display_as_valid(valid = False)
460 self._TCTRL_substance.SetFocus()
461 else:
462 self._PRW_unit.display_as_valid(valid = True)
463
464 if validity is False:
465 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. Missing essential input.'))
466
467 return validity
468
470 subst = gmMedication.create_consumable_substance (
471 substance = self._TCTRL_substance.GetValue().strip(),
472 atc = self._PRW_atc.GetData(),
473 amount = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')),
474 unit = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None))
475 )
476 success, data = subst.save()
477 if not success:
478 err, msg = data
479 _log.error(err)
480 _log.error(msg)
481 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
482 return False
483
484 self.data = subst
485 return True
486
488 self.data['description'] = self._TCTRL_substance.GetValue().strip()
489 self.data['atc_code'] = self._PRW_atc.GetData()
490 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.'))
491 self.data['unit'] = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None))
492 success, data = self.data.save()
493
494 if not success:
495 err, msg = data
496 _log.error(err)
497 _log.error(msg)
498 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
499 return False
500
501 return True
502
504 self._TCTRL_substance.SetValue(u'')
505 self._TCTRL_amount.SetValue(u'')
506 self._PRW_unit.SetText(u'', None)
507 self._PRW_atc.SetText(u'', None)
508
509 self._TCTRL_substance.SetFocus()
510
518
520 self._refresh_as_new()
521
522
523
524
534
535 def delete(component):
536 if component.is_in_use_by_patients:
537 gmDispatcher.send(signal = 'statustext', msg = _('Cannot remove this component from the drug. It is in use.'), beep = True)
538 return False
539
540 return component.containing_drug.remove_component(substance = component['pk_component'])
541
542 def refresh(lctrl):
543 comps = gmMedication.get_drug_components()
544 items = [ [
545 u'%s%s' % (c['brand'], gmTools.coalesce(c['atc_brand'], u'', u' [%s]')),
546 u'%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], u'', u' [%s]')),
547 u'%s %s' % (c['amount'], c['unit']),
548 c['preparation'],
549 gmTools.coalesce(c['external_code_brand'], u'', u'%%s [%s]' % c['external_code_type_brand']),
550 c['pk_component']
551 ] for c in comps ]
552 lctrl.set_string_items(items)
553 lctrl.set_data(comps)
554
555 msg = _('\nThese are the components in the drug brands known to GNUmed.\n')
556
557 gmListWidgets.get_choices_from_list (
558 parent = parent,
559 msg = msg,
560 caption = _('Showing drug brand components.'),
561 columns = [_('Brand'), _('Substance'), _('Strength'), _('Preparation'), _('Code'), u'#'],
562 single_selection = True,
563
564 edit_callback = edit,
565 delete_callback = delete,
566 refresh_callback = refresh
567 )
568
569
581
582
583 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl
584
585 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
586
604
605
606
607
608
609
610
611
613 if self.data is not None:
614 if self.data['is_in_use']:
615 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug component. It is in use.'), beep = True)
616 return False
617
618 validity = True
619
620 if self._PRW_substance.GetData() is None:
621 validity = False
622 self._PRW_substance.display_as_valid(False)
623 else:
624 self._PRW_substance.display_as_valid(True)
625
626 val = self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1)
627 try:
628 decimal.Decimal(val)
629 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
630 except:
631 validity = False
632 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
633
634 if self._PRW_unit.GetValue().strip() == u'':
635 validity = False
636 self._PRW_unit.display_as_valid(False)
637 else:
638 self._PRW_unit.display_as_valid(True)
639
640 if validity is False:
641 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save drug component. Invalid or missing essential input.'))
642
643 return validity
644
646
647 data = 1
648 data[''] = 1
649 data[''] = 1
650
651
652
653
654
655
656 return False
657 return True
658
660 self.data['pk_consumable_substance'] = self._PRW_substance.GetData()
661 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1))
662 self.data['unit'] = self._PRW_unit.GetValue().strip()
663 return self.data.save()
664
674
676 self._TCTRL_brand.SetValue(u'%s (%s)' % (self.data['brand'], self.data['preparation']))
677 self._TCTRL_components.SetValue(u' / '.join(self.data.containing_drug['components']))
678 details = []
679 if self.data['atc_brand'] is not None:
680 details.append(u'ATC: %s' % self.data['atc_brand'])
681 if self.data['external_code_brand'] is not None:
682 details.append(u'%s: %s' % (self.data['external_code_type_brand'], self.data['external_code_brand']))
683 self._TCTRL_codes.SetValue(u'; '.join(details))
684
685 self._PRW_substance.SetText(self.data['substance'], self.data['pk_consumable_substance'])
686 self._TCTRL_amount.SetValue(u'%s' % self.data['amount'])
687 self._PRW_unit.SetText(self.data['unit'], self.data['unit'])
688
689 self._PRW_substance.SetFocus()
690
692
693
694
695 self._PRW_substance.SetText(u'', None)
696 self._TCTRL_amount.SetValue(u'')
697 self._PRW_unit.SetText(u'', None)
698
699 self._PRW_substance.SetFocus()
700
701
715
716
718
720
721 query = u"""
722 (
723 SELECT DISTINCT ON (preparation)
724 preparation as prep, preparation
725 FROM ref.branded_drug
726 WHERE preparation %(fragment_condition)s
727 ) UNION (
728 SELECT DISTINCT ON (preparation)
729 preparation as prep, preparation
730 FROM clin.substance_intake
731 WHERE preparation %(fragment_condition)s
732 )
733 ORDER BY prep
734 limit 30"""
735
736 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
737 mp.setThresholds(1, 2, 4)
738 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
739 self.SetToolTipString(_('The preparation (form) of the substance or brand.'))
740 self.matcher = mp
741 self.selection_only = False
742
758
759
760
762
763 if brand is not None:
764 if brand.is_in_use_by_patients:
765 gmGuiHelpers.gm_show_info (
766 aTitle = _('Managing components of a drug'),
767 aMessage = _(
768 'Cannot manage the components of the branded drug product\n'
769 '\n'
770 ' "%s" (%s)\n'
771 '\n'
772 'because it is currently taken by patients.\n'
773 ) % (brand['brand'], brand['preparation'])
774 )
775 return False
776
777 if parent is None:
778 parent = wx.GetApp().GetTopWindow()
779
780
781
782
783 if brand is None:
784 msg = _('Pick the substances which are components of this drug.')
785 right_col = _('Components of drug')
786 comp_substs = []
787 else:
788 right_col = u'%s (%s)' % (brand['brand'], brand['preparation'])
789 msg = _(
790 'Adjust the components of "%s"\n'
791 '\n'
792 'The drug must contain at least one component. Any given\n'
793 'substance can only be included once per drug.'
794 ) % right_col
795 comp_substs = [ c.substance for c in brand.components ]
796
797 substs = gmMedication.get_consumable_substances(order_by = 'description')
798 choices = [ u'%s %s %s' % (s['description'], s['amount'], s['unit']) for s in substs ]
799 picks = [ u'%s %s %s' % (c['description'], c['amount'], c['unit']) for c in comp_substs ]
800
801 picker = gmListWidgets.cItemPickerDlg (
802 parent,
803 -1,
804 title = _('Managing components of a drug ...'),
805 msg = msg
806 )
807 picker.set_columns(['Substances'], [right_col])
808 picker.set_choices(choices = choices, data = substs)
809 picker.set_picks(picks = picks, data = comp_substs)
810
811
812
813
814
815
816 btn_pressed = picker.ShowModal()
817 substs = picker.get_picks()
818 picker.Destroy()
819
820 if btn_pressed != wx.ID_OK:
821 return (False, None)
822
823 if brand is not None:
824 brand.set_substances_as_components(substances = substs)
825
826 return (True, substs)
827
829
830 if parent is None:
831 parent = wx.GetApp().GetTopWindow()
832
833 def add_from_db(brand):
834 drug_db = get_drug_database(parent = parent)
835 if drug_db is None:
836 return False
837 drug_db.import_drugs()
838 return True
839
840 def get_tooltip(brand=None):
841 tt = u'%s %s\n' % (brand['brand'], brand['preparation'])
842 tt += u'\n'
843 tt += u'%s%s%s\n' % (
844 gmTools.bool2subst(brand.is_vaccine, u'%s, ' % _('Vaccine'), u''),
845 u'%s, ' % gmTools.bool2subst(brand.is_in_use_by_patients, _('in use'), _('not in use')),
846 gmTools.bool2subst(brand['is_fake_brand'], _('fake'), u'')
847 )
848 tt += gmTools.coalesce(brand['atc'], u'', _('ATC: %s\n'))
849 tt += gmTools.coalesce(brand['external_code'], u'', u'%s: %%s\n' % brand['external_code_type'])
850 if brand['components'] is not None:
851 tt += u'- %s' % u'\n- '.join(brand['components'])
852 return tt
853
854 def edit(brand):
855 if brand is not None:
856 if brand.is_vaccine:
857 gmGuiHelpers.gm_show_info (
858 aTitle = _('Editing medication'),
859 aMessage = _(
860 'Cannot edit the medication\n'
861 '\n'
862 ' "%s" (%s)\n'
863 '\n'
864 'because it is a vaccine. Please edit it\n'
865 'from the vaccine management section !\n'
866 ) % (brand['brand'], brand['preparation'])
867 )
868 return False
869
870 return edit_branded_drug(parent = parent, branded_drug = brand, single_entry = True)
871
872 def delete(brand):
873 if brand.is_vaccine:
874 gmGuiHelpers.gm_show_info (
875 aTitle = _('Deleting medication'),
876 aMessage = _(
877 'Cannot delete the medication\n'
878 '\n'
879 ' "%s" (%s)\n'
880 '\n'
881 'because it is a vaccine. Please delete it\n'
882 'from the vaccine management section !\n'
883 ) % (brand['brand'], brand['preparation'])
884 )
885 return False
886 gmMedication.delete_branded_drug(brand = brand['pk_brand'])
887 return True
888
889 def new():
890 return edit_branded_drug(parent = parent, branded_drug = None, single_entry = False)
891
892 def refresh(lctrl):
893 drugs = gmMedication.get_branded_drugs()
894 items = [ [
895 u'%s%s' % (
896 d['brand'],
897 gmTools.bool2subst(d['is_fake_brand'], ' (%s)' % _('fake'), u'')
898 ),
899 d['preparation'],
900 gmTools.coalesce(d['atc'], u''),
901 gmTools.coalesce(d['components'], u''),
902 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
903 d['pk_brand']
904 ] for d in drugs ]
905 lctrl.set_string_items(items)
906 lctrl.set_data(drugs)
907
908 msg = _('\nThese are the drug brands known to GNUmed.\n')
909
910 gmListWidgets.get_choices_from_list (
911 parent = parent,
912 msg = msg,
913 caption = _('Showing branded drugs.'),
914 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), u'#'],
915 single_selection = True,
916 ignore_OK_button = ignore_OK_button,
917 refresh_callback = refresh,
918 new_callback = new,
919 edit_callback = edit,
920 delete_callback = delete,
921 list_tooltip_callback = get_tooltip,
922 left_extra_button = (_('Import'), _('Import substances and brands from a drug database.'), add_from_db)
923
924
925 )
926
927
929
930 if branded_drug is not None:
931 if branded_drug.is_in_use_by_patients:
932 gmGuiHelpers.gm_show_info (
933 aTitle = _('Editing drug'),
934 aMessage = _(
935 'Cannot edit the branded drug product\n'
936 '\n'
937 ' "%s" (%s)\n'
938 '\n'
939 'because it is currently taken by patients.\n'
940 ) % (branded_drug['brand'], branded_drug['preparation'])
941 )
942 return False
943
944 if parent is None:
945 parent = wx.GetApp().GetTopWindow()
946
947 def manage_substances(drug):
948 manage_consumable_substances(parent = parent)
949
950 ea = cBrandedDrugEAPnl(parent = parent, id = -1)
951 ea.data = branded_drug
952 ea.mode = gmTools.coalesce(branded_drug, 'new', 'edit')
953 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
954 dlg.SetTitle(gmTools.coalesce(branded_drug, _('Adding new drug brand'), _('Editing drug brand')))
955 dlg.left_extra_button = (
956 _('Substances'),
957 _('Manage consumable substances'),
958 manage_substances
959 )
960 if dlg.ShowModal() == wx.ID_OK:
961 dlg.Destroy()
962 return True
963 dlg.Destroy()
964 return False
965
966
967 from Gnumed.wxGladeWidgets import wxgBrandedDrugEAPnl
968
969 -class cBrandedDrugEAPnl(wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
970
987
988
989
990
991
992
993
994
996
997 if self.data is not None:
998 if self.data.is_in_use_by_patients:
999 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug brand. It is in use.'), beep = True)
1000 return False
1001
1002 validity = True
1003
1004 if self._PRW_brand.GetValue().strip() == u'':
1005 validity = False
1006 self._PRW_brand.display_as_valid(False)
1007 else:
1008 self._PRW_brand.display_as_valid(True)
1009
1010 if self._PRW_preparation.GetValue().strip() == u'':
1011 validity = False
1012 self._PRW_preparation.display_as_valid(False)
1013 else:
1014 self._PRW_preparation.display_as_valid(True)
1015
1016 if validity is True:
1017 self._TCTRL_components.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
1018 if len(self.__component_substances) == 0:
1019 wants_empty = gmGuiHelpers.gm_show_question (
1020 title = _('Checking brand data'),
1021 question = _(
1022 'You have not selected any substances\n'
1023 'as drug components.\n'
1024 '\n'
1025 'Without components you will not be able to\n'
1026 'use this drug for documenting patient care.\n'
1027 '\n'
1028 'Are you sure you want to save\n'
1029 'it without components ?'
1030 )
1031 )
1032 if not wants_empty:
1033 validity = False
1034 self.display_ctrl_as_valid(ctrl = self._TCTRL_components, valid = False)
1035
1036 if validity is False:
1037 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save branded drug. Invalid or missing essential input.'))
1038
1039 return validity
1040
1042
1043 drug = gmMedication.create_branded_drug (
1044 brand_name = self._PRW_brand.GetValue().strip(),
1045 preparation = gmTools.coalesce (
1046 self._PRW_preparation.GetData(),
1047 self._PRW_preparation.GetValue()
1048 ).strip(),
1049 return_existing = True
1050 )
1051 drug['is_fake_brand'] = self._CHBOX_is_fake.GetValue()
1052 drug['atc'] = self._PRW_atc.GetData()
1053 code = self._TCTRL_external_code.GetValue().strip()
1054 if code != u'':
1055 drug['external_code'] = code
1056 drug['external_code_type'] = self._PRW_external_code_type.GetData().strip()
1057
1058 drug.save()
1059
1060 if len(self.__component_substances) > 0:
1061 drug.set_substances_as_components(substances = self.__component_substances)
1062
1063 self.data = drug
1064
1065 return True
1066
1068 self.data['brand'] = self._PRW_brand.GetValue().strip()
1069 self.data['preparation'] = gmTools.coalesce (
1070 self._PRW_preparation.GetData(),
1071 self._PRW_preparation.GetValue()
1072 ).strip()
1073 self.data['is_fake_brand'] = self._CHBOX_is_fake.GetValue()
1074 self.data['atc'] = self._PRW_atc.GetData()
1075 code = self._TCTRL_external_code.GetValue().strip()
1076 if code != u'':
1077 self.data['external_code'] = code
1078 self.data['external_code_type'] = self._PRW_external_code_type.GetData().strip()
1079 success, data = self.data.save()
1080 if not success:
1081 err, msg = data
1082 _log.error('problem saving')
1083 _log.error('%s', err)
1084 _log.error('%s', msg)
1085 return (success is True)
1086
1088 self._PRW_brand.SetText(u'', None)
1089 self._PRW_preparation.SetText(u'', None)
1090 self._CHBOX_is_fake.SetValue(False)
1091 self._TCTRL_components.SetValue(u'')
1092 self._PRW_atc.SetText(u'', None)
1093 self._TCTRL_external_code.SetValue(u'')
1094 self._PRW_external_code_type.SetText(u'', None)
1095
1096 self._PRW_brand.SetFocus()
1097
1098 self.__component_substances = []
1099
1101 self._refresh_as_new()
1102
1119
1120
1121
1135
1137
1139
1140 query = u"""
1141 SELECT
1142 pk
1143 AS data,
1144 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
1145 AS list_label,
1146 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
1147 AS field_label
1148 FROM ref.branded_drug
1149 WHERE description %(fragment_condition)s
1150 ORDER BY list_label
1151 LIMIT 50"""
1152
1153 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1154 mp.setThresholds(2, 3, 4)
1155 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1156 self.SetToolTipString(_(
1157 'The brand name of the drug.\n'
1158 '\n'
1159 'Note: a brand name will need to be linked to\n'
1160 'one or more components before it can be used,\n'
1161 'except in the case of fake (generic) vaccines.'
1162 ))
1163 self.matcher = mp
1164 self.selection_only = False
1165
1166
1167
1168
1170
1172
1173 query = u"""
1174 SELECT DISTINCT ON (sched)
1175 schedule as sched,
1176 schedule
1177 FROM clin.substance_intake
1178 WHERE schedule %(fragment_condition)s
1179 ORDER BY sched
1180 LIMIT 50"""
1181
1182 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1183 mp.setThresholds(1, 2, 4)
1184 mp.word_separators = '[ \t=+&:@]+'
1185 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1186 self.SetToolTipString(_('The schedule for taking this substance.'))
1187 self.matcher = mp
1188 self.selection_only = False
1189
1191
1192 if intake['is_currently_active']:
1193 intake['discontinued'] = gmDateTime.pydt_now_here()
1194 if intake['discontinue_reason'] is None:
1195 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), _('discontinued due to allergy or intolerance'))
1196 else:
1197 if not intake['discontinue_reason'].startswith(_('not tolerated:')):
1198 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), intake['discontinue_reason'])
1199 if not intake.save():
1200 return False
1201
1202 allg = intake.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1203
1204 brand = intake.containing_drug
1205 if brand is not None:
1206 comps = [ c['substance'] for c in brand.components ]
1207 if len(comps) > 1:
1208 gmGuiHelpers.gm_show_info (
1209 aTitle = _(u'Documented an allergy'),
1210 aMessage = _(
1211 u'An allergy was documented against the substance:\n'
1212 u'\n'
1213 u' [%s]\n'
1214 u'\n'
1215 u'This substance was taken with the multi-component brand:\n'
1216 u'\n'
1217 u' [%s (%s)]\n'
1218 u'\n'
1219 u'Note that ALL components of this brand were discontinued.'
1220 ) % (
1221 intake['substance'],
1222 intake['brand'],
1223 u' & '.join(comps)
1224 )
1225 )
1226
1227 if parent is None:
1228 parent = wx.GetApp().GetTopWindow()
1229
1230 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = parent, id = -1)
1231 dlg.ShowModal()
1232
1233 return True
1234
1235
1237
1238 if parent is None:
1239 parent = wx.GetApp().GetTopWindow()
1240
1241 if emr is None:
1242 emr = gmPerson.gmCurrentPatient().emr
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261 def get_tooltip(intake=None):
1262 return intake.format(one_line = False, show_all_brand_components = True)
1263
1264 def refresh(lctrl):
1265 intakes = emr.get_current_substance_intake (
1266 include_inactive = False,
1267 include_unapproved = True,
1268 order_by = u'substance, brand, started'
1269 )
1270 items = [ [
1271 u'%s%s %s %s %s%s' % (
1272 i['substance'],
1273 gmTools.coalesce(i['brand'], u'', u' (%s)'),
1274 i['amount'],
1275 i['unit'],
1276 i['preparation'],
1277 gmTools.coalesce(i['external_code_brand'], u'', u' [%s::%s]' % (i['external_code_type_brand'], i['external_code_brand']))
1278 ),
1279 u'%s%s%s' % (
1280 gmTools.coalesce(i['started'], u'', u'%%s %s' % gmTools.u_right_arrow, function_initial = ('strftime', '%Y %B %d')),
1281 gmTools.coalesce(i['schedule'], u'', u' %s %s' % (i['schedule'], gmTools.u_right_arrow)),
1282 gmTools.coalesce(i['duration'], u'', u' %s')
1283 ),
1284 u'%s' % (
1285 gmTools.bool2subst (
1286 i['intake_is_approved_of'],
1287 u'',
1288 _('disapproved')
1289 )
1290 )
1291 ] for i in intakes ]
1292 lctrl.set_string_items(items)
1293 lctrl.set_data(intakes)
1294
1295 msg = _('Substances consumed by the patient:')
1296
1297 return gmListWidgets.get_choices_from_list (
1298 parent = parent,
1299 msg = msg,
1300 caption = _('Showing consumable substances.'),
1301 columns = [ _('Intake'), _('Application'), _('Status') ],
1302 single_selection = False,
1303
1304
1305
1306 refresh_callback = refresh,
1307 list_tooltip_callback = get_tooltip
1308
1309 )
1310
1311
1312 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
1313
1314 -class cSubstanceIntakeEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
1315
1333
1335
1336 self._PRW_component.add_callback_on_lose_focus(callback = self._on_leave_component)
1337 self._PRW_component.selection_only = True
1338
1339 self._PRW_substance.add_callback_on_lose_focus(callback = self._on_leave_substance)
1340 self._PRW_substance.selection_only = True
1341
1343 emr = gmPerson.gmCurrentPatient().get_emr()
1344
1345 state = emr.allergy_state
1346 if state['last_confirmed'] is None:
1347 confirmed = _('never')
1348 else:
1349 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
1350 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
1351 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
1352 msg += u'\n'
1353
1354 for allergy in emr.get_allergies():
1355 msg += u'%s (%s, %s): %s\n' % (
1356 allergy['descriptor'],
1357 allergy['l10n_type'],
1358 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
1359 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
1360 )
1361
1362 self._LBL_allergies.SetLabel(msg)
1363
1364
1365
1455
1457
1458 emr = gmPerson.gmCurrentPatient().get_emr()
1459 epi = self._PRW_episode.GetData(can_create = True)
1460
1461 if self._PRW_substance.GetData() is None:
1462
1463 intake = emr.add_substance_intake (
1464 pk_component = self._PRW_component.GetData(),
1465 episode = epi
1466 )
1467 else:
1468 intake = emr.add_substance_intake (
1469 pk_substance = self._PRW_substance.GetData(),
1470 episode = epi,
1471 preparation = self._PRW_preparation.GetValue().strip()
1472 )
1473
1474 if intake is None:
1475 gmDispatcher.send('statustext', msg = _('Cannot add duplicate of (maybe inactive) substance intake.'), beep = True)
1476 return False
1477
1478 intake['started'] = self._DP_started.GetData()
1479 intake['discontinued'] = self._DP_discontinued.GetData()
1480 if intake['discontinued'] is None:
1481 intake['discontinue_reason'] = None
1482 else:
1483 intake['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1484 intake['schedule'] = self._PRW_schedule.GetValue().strip()
1485 intake['aim'] = self._PRW_aim.GetValue().strip()
1486 intake['notes'] = self._PRW_notes.GetValue().strip()
1487 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
1488 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1489 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1490 intake['duration'] = None
1491 else:
1492 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1493 intake.save()
1494
1495 self.data = intake
1496
1497 return True
1498
1500
1501
1502 self.data['started'] = self._DP_started.GetData()
1503 self.data['discontinued'] = self._DP_discontinued.GetData()
1504 if self.data['discontinued'] is None:
1505 self.data['discontinue_reason'] = None
1506 else:
1507 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1508 self.data['schedule'] = self._PRW_schedule.GetValue()
1509 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
1510 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1511 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1512 self.data['duration'] = None
1513 else:
1514 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1515
1516
1517 self.data['preparation'] = self._PRW_preparation.GetValue()
1518
1519
1520 self.data['aim'] = self._PRW_aim.GetValue()
1521 self.data['notes'] = self._PRW_notes.GetValue()
1522 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
1523
1524 self.data.save()
1525
1526 return True
1527
1529 self._PRW_component.SetText(u'', None)
1530 self._LBL_component.Enable(True)
1531 self._PRW_component.Enable(True)
1532 self._TCTRL_brand_ingredients.SetValue(u'')
1533 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1534
1535 self._LBL_or.Enable(True)
1536
1537 self._PRW_substance.SetText(u'', None)
1538 self._PRW_substance.Enable(True)
1539
1540 self._PRW_preparation.SetText(u'', None)
1541 self._PRW_preparation.Enable(True)
1542
1543 self._PRW_schedule.SetText(u'', None)
1544 self._PRW_duration.SetText(u'', None)
1545 self._PRW_aim.SetText(u'', None)
1546 self._PRW_notes.SetText(u'', None)
1547 self._PRW_episode.SetText(u'', None)
1548
1549 self._CHBOX_long_term.SetValue(False)
1550 self._CHBOX_approved.SetValue(True)
1551
1552 self._DP_started.SetData(gmDateTime.pydt_now_here())
1553 self._DP_discontinued.SetData(None)
1554 self._PRW_discontinue_reason.SetValue(u'')
1555
1556 self.__refresh_allergies()
1557
1558 self._PRW_component.SetFocus()
1559
1561
1562 self._TCTRL_brand_ingredients.SetValue(u'')
1563 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1564
1565 if self.data['pk_brand'] is None:
1566 self.__refresh_from_existing_substance()
1567 else:
1568 self.__refresh_from_existing_component()
1569
1570
1571 self._LBL_component.Enable(False)
1572 self._PRW_component.Enable(False)
1573 self._LBL_or.Enable(False)
1574 self._PRW_substance.Enable(False)
1575
1576 if self.data['is_long_term']:
1577 self._CHBOX_long_term.SetValue(True)
1578 self._PRW_duration.Enable(False)
1579 self._PRW_duration.SetText(gmTools.u_infinity, None)
1580 self._BTN_discontinued_as_planned.Enable(False)
1581 else:
1582 self._CHBOX_long_term.SetValue(False)
1583 self._PRW_duration.Enable(True)
1584 self._BTN_discontinued_as_planned.Enable(True)
1585 if self.data['duration'] is None:
1586 self._PRW_duration.SetText(u'', None)
1587 else:
1588 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
1589 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
1590 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
1591 self._PRW_episode.SetData(self.data['pk_episode'])
1592 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
1593
1594 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
1595
1596 self._DP_started.SetData(self.data['started'])
1597 self._DP_discontinued.SetData(self.data['discontinued'])
1598 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
1599 if self.data['discontinued'] is not None:
1600 self._PRW_discontinue_reason.Enable()
1601
1602 self.__refresh_allergies()
1603
1604 self._PRW_schedule.SetFocus()
1605
1607 self._LBL_component.Enable(False)
1608 self._PRW_component.Enable(False)
1609 self._PRW_component.SetText(u'', None)
1610 self._PRW_component.display_as_valid(True)
1611
1612 self._LBL_or.Enable(False)
1613
1614 self._PRW_substance.Enable(True)
1615 self._PRW_substance.SetText (
1616 u'%s %s %s' % (self.data['substance'], self.data['amount'], self.data['unit']),
1617 self.data['pk_substance']
1618 )
1619
1620 self._PRW_preparation.SetText(gmTools.coalesce(self.data['preparation'], u''), self.data['preparation'])
1621 self._PRW_preparation.Enable(True)
1622
1624 self._LBL_component.Enable(True)
1625 self._PRW_component.Enable(True)
1626 self._PRW_component.SetText (
1627 u'%s %s %s (%s)' % (self.data['substance'], self.data['amount'], self.data['unit'], self.data['brand']),
1628 self.data['pk_drug_component']
1629 )
1630
1631 brand = gmMedication.cBrandedDrug(aPK_obj = self.data['pk_brand'])
1632 if brand['components'] is not None:
1633 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components']))
1634 tt = u'%s:\n\n- %s' % (
1635 self.data['brand'],
1636 u'\n- '.join(brand['components'])
1637 )
1638 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1639
1640 self._LBL_or.Enable(False)
1641 self._LBL_substance.Enable(False)
1642 self._PRW_substance.SetText(u'', None)
1643 self._PRW_substance.display_as_valid(True)
1644
1645 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation'])
1646 self._PRW_preparation.Enable(False)
1647
1649 self._refresh_as_new()
1650
1651 self._PRW_episode.SetData(self.data['pk_episode'])
1652
1653 self._PRW_component.SetFocus()
1654
1655
1656
1658 if self._PRW_component.GetData() is None:
1659 self._LBL_or.Enable(True)
1660 self._PRW_component.SetText(u'', None)
1661 self._LBL_substance.Enable(True)
1662 self._PRW_substance.Enable(True)
1663 self._LBL_preparation.Enable(True)
1664 self._PRW_preparation.Enable(True)
1665 self._PRW_preparation.SetText(u'', None)
1666 self._TCTRL_brand_ingredients.SetValue(u'')
1667 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1668 else:
1669 self._LBL_or.Enable(False)
1670 self._LBL_substance.Enable(False)
1671 self._PRW_substance.SetText(u'', None)
1672 self._PRW_substance.display_as_valid(True)
1673 self._PRW_substance.Enable(False)
1674 self._LBL_preparation.Enable(False)
1675 self._PRW_preparation.Enable(False)
1676 comp = gmMedication.cDrugComponent(aPK_obj = self._PRW_component.GetData())
1677 self._PRW_preparation.SetText(comp['preparation'], comp['preparation'])
1678 brand = comp.containing_drug
1679 if brand['components'] is not None:
1680 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components']))
1681 tt = u'%s:\n\n- %s' % (
1682 brand['brand'],
1683 u'\n- '.join(brand['components'])
1684 )
1685 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1686
1688 if self._PRW_substance.GetData() is None:
1689 self._LBL_or.Enable(True)
1690 self._LBL_component.Enable(True)
1691 self._PRW_component.Enable(True)
1692 self._PRW_substance.SetText(u'', None)
1693 else:
1694 self._LBL_or.Enable(False)
1695 self._LBL_component.Enable(False)
1696 self._PRW_component.SetText(u'', None)
1697 self._PRW_component.display_as_valid(True)
1698 self._PRW_component.Enable(False)
1699 self._LBL_preparation.Enable(True)
1700 self._PRW_preparation.Enable(True)
1701 self._TCTRL_brand_ingredients.SetValue(u'')
1702 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1703
1705 if self._DP_discontinued.GetData() is None:
1706 self._PRW_discontinue_reason.Enable(False)
1707 else:
1708 self._PRW_discontinue_reason.Enable(True)
1709
1712
1715
1718
1730
1760
1762 if self._CHBOX_long_term.IsChecked() is True:
1763 self._PRW_duration.Enable(False)
1764 self._BTN_discontinued_as_planned.Enable(False)
1765 self._PRW_discontinue_reason.Enable(False)
1766 else:
1767 self._PRW_duration.Enable(True)
1768 self._BTN_discontinued_as_planned.Enable(True)
1769 self._PRW_discontinue_reason.Enable(True)
1770
1771 self.__refresh_allergies()
1772
1782
1783
1785
1786 subst = gmMedication.cSubstanceIntakeEntry(aPK_obj = substance)
1787 msg = _(
1788 '\n'
1789 '[%s]\n'
1790 '\n'
1791 'It may be prudent to edit (before deletion) the details\n'
1792 'of this substance intake entry so as to leave behind\n'
1793 'some indication of why it was deleted.\n'
1794 ) % subst.format()
1795
1796 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1797 parent,
1798 -1,
1799 caption = _('Deleting medication / substance intake'),
1800 question = msg,
1801 button_defs = [
1802 {'label': _('&Edit'), 'tooltip': _('Allow editing of substance intake entry before deletion.'), 'default': True},
1803 {'label': _('&Delete'), 'tooltip': _('Delete immediately without editing first.')},
1804 {'label': _('&Cancel'), 'tooltip': _('Abort. Do not delete or edit substance intake entry.')}
1805 ]
1806 )
1807
1808 edit_first = dlg.ShowModal()
1809 dlg.Destroy()
1810
1811 if edit_first == wx.ID_CANCEL:
1812 return
1813
1814 if edit_first == wx.ID_YES:
1815 edit_intake_of_substance(parent = parent, substance = subst)
1816 delete_it = gmGuiHelpers.gm_show_question (
1817 aMessage = _('Now delete substance intake entry ?'),
1818 aTitle = _('Deleting medication / substance intake')
1819 )
1820 else:
1821 delete_it = True
1822
1823 if not delete_it:
1824 return
1825
1826 gmMedication.delete_substance_intake(substance = substance)
1827
1842
1843
1844
1845
1873
1875
1876 if parent is None:
1877 parent = wx.GetApp().GetTopWindow()
1878
1879
1880 dbcfg = gmCfg.cCfgSQL()
1881 option = u'form_templates.medication_list'
1882
1883 template = dbcfg.get2 (
1884 option = option,
1885 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1886 bias = 'user'
1887 )
1888
1889 if template is None:
1890 template = configure_medication_list_template(parent = parent)
1891 if template is None:
1892 gmGuiHelpers.gm_show_error (
1893 aMessage = _('There is no medication list template configured.'),
1894 aTitle = _('Printing medication list')
1895 )
1896 return False
1897 else:
1898 try:
1899 name, ver = template.split(u' - ')
1900 except:
1901 _log.exception('problem splitting medication list template name [%s]', template)
1902 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
1903 return False
1904 template = gmForms.get_form_template(name_long = name, external_version = ver)
1905 if template is None:
1906 gmGuiHelpers.gm_show_error (
1907 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
1908 aTitle = _('Printing medication list')
1909 )
1910 return False
1911
1912
1913 try:
1914 meds_list = template.instantiate()
1915 except KeyError:
1916 _log.exception('cannot instantiate medication list template [%s]', template)
1917 gmGuiHelpers.gm_show_error (
1918 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
1919 aTitle = _('Printing medication list')
1920 )
1921 return False
1922
1923 ph = gmMacro.gmPlaceholderHandler()
1924
1925 meds_list.substitute_placeholders(data_source = ph)
1926 pdf_name = meds_list.generate_output()
1927 if pdf_name is None:
1928 gmGuiHelpers.gm_show_error (
1929 aMessage = _('Error generating the medication list.'),
1930 aTitle = _('Printing medication list')
1931 )
1932 return False
1933
1934
1935 printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'medication_list')
1936 if not printed:
1937 gmGuiHelpers.gm_show_error (
1938 aMessage = _('Error printing the medication list.'),
1939 aTitle = _('Printing medication list')
1940 )
1941 return False
1942
1943
1944 pat = gmPerson.gmCurrentPatient()
1945 emr = pat.get_emr()
1946 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1947 emr.add_clin_narrative (
1948 soap_cat = None,
1949 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1950 episode = epi
1951 )
1952
1953 return True
1954
1955
1984
1986
1987 if parent is None:
1988 parent = wx.GetApp().GetTopWindow()
1989
1990 dbcfg = gmCfg.cCfgSQL()
1991 option = u'form_templates.prescription'
1992 template_name = dbcfg.get2 (
1993 option = option,
1994 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1995 bias = 'user'
1996 )
1997
1998 if template_name is None:
1999 template = configure_prescription_template(parent = parent)
2000 if template is None:
2001 gmGuiHelpers.gm_show_error (
2002 aMessage = _('There is no prescription template configured.'),
2003 aTitle = _('Printing prescription')
2004 )
2005 return None
2006 return template
2007
2008 try:
2009 name, ver = template_name.split(u' - ')
2010 except:
2011 _log.exception('problem splitting prescription template name [%s]', template_name)
2012 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading prescription template.'), beep = True)
2013 return False
2014 template = gmForms.get_form_template(name_long = name, external_version = ver)
2015 if template is None:
2016 gmGuiHelpers.gm_show_error (
2017 aMessage = _('Cannot load prescription template [%s - %s]') % (name, ver),
2018 aTitle = _('Printing prescription')
2019 )
2020 return False
2021 return template
2022
2024
2025
2026 rx_template = get_prescription_template(parent = parent)
2027 if rx_template is None:
2028 return False
2029
2030
2031 try:
2032 rx = rx_template.instantiate()
2033 except KeyError:
2034 _log.exception('cannot instantiate prescription template [%s]', rx_template)
2035 gmGuiHelpers.gm_show_error (
2036 aMessage = _('Invalid prescription template [%s - %s (%s)]') % (rx_template['name_long'], rx_template['external_version'], rx_template['engine']),
2037 aTitle = _('Printing prescription list')
2038 )
2039 return False
2040 ph = gmMacro.gmPlaceholderHandler()
2041
2042 rx.substitute_placeholders(data_source = ph)
2043 pdf_name = rx.generate_output()
2044 if pdf_name is None:
2045 gmGuiHelpers.gm_show_error (
2046 aMessage = _('Error generating the prescription printout.'),
2047 aTitle = _('Printing prescription')
2048 )
2049 return False
2050
2051
2052 printed = gmPrinting.print_files(filenames = [pdf_name], jobtype = 'prescription')
2053 if not printed:
2054 gmGuiHelpers.gm_show_error (
2055 aMessage = _('Error printing the prescription.'),
2056 aTitle = _('Printing prescription')
2057 )
2058 return False
2059
2060 epi = emr.add_episode (
2061 episode_name = gmMedication.DEFAULT_MEDICATION_HISTORY_EPISODE,
2062 is_open = False
2063 )
2064
2065
2066 files2import = []
2067 files2import.extend(rx.final_output_filenames)
2068 files2import.extend(rx.re_editable_filenames)
2069 doc = gmDocumentWidgets.save_files_as_new_document (
2070 parent = parent,
2071 filenames = files2import,
2072 document_type = u'prescription',
2073
2074
2075
2076 episode = epi,
2077 review_as_normal = True
2078 )
2079
2080
2081 emr.add_clin_narrative (
2082 soap_cat = None,
2083 note = _('prescription printed from template [%s - %s]') % (rx_template['name_long'], rx_template['external_version']),
2084 episode = epi
2085 )
2086
2087 return True
2088
2089
2117
2118
2120
2121 if len(prescribed_drugs) == 0:
2122 return
2123
2124 curr_brands = [ i['pk_brand'] for i in emr.get_current_substance_intake() if i['pk_brand'] is not None ]
2125 new_drugs = []
2126 for drug in prescribed_drugs:
2127 if drug['pk_brand'] not in curr_brands:
2128 new_drugs.append(drug)
2129
2130 if len(new_drugs) == 0:
2131 return
2132
2133 if parent is None:
2134 parent = wx.GetApp().GetTopWindow()
2135
2136 dlg = gmListWidgets.cItemPickerDlg (
2137 parent,
2138 -1,
2139 msg = _(
2140 'These brands have been prescribed but are not listed\n'
2141 'in the current medication list of this patient.\n'
2142 '\n'
2143 'Please select those you want added to the medication list.'
2144 )
2145 )
2146 dlg.set_columns (
2147 columns = [_('Newly prescribed drugs')],
2148 columns_right = [_('Add to medication list')]
2149 )
2150 choices = [ (u'%s %s (%s)' % (d['brand'], d['preparation'], u'; '.join(d['components']))) for d in new_drugs ]
2151 dlg.set_choices (
2152 choices = choices,
2153 data = new_drugs
2154 )
2155 dlg.ShowModal()
2156 drugs2add = dlg.get_picks()
2157 dlg.Destroy()
2158
2159 if drugs2add is None:
2160 return
2161
2162 if len(drugs2add) == 0:
2163 return
2164
2165 for drug in drugs2add:
2166
2167 intake = emr.add_substance_intake (
2168 pk_component = drug['pk_components'][0],
2169 episode = emr.add_episode(episode_name = gmMedication.DEFAULT_MEDICATION_HISTORY_EPISODE)['pk_episode'],
2170 )
2171 if intake is None:
2172 continue
2173 intake['intake_is_approved_of'] = True
2174 intake.save()
2175
2176 return
2177
2179 """A grid class for displaying current substance intake.
2180
2181 - does NOT listen to the currently active patient
2182 - thereby it can display any patient at any time
2183 """
2185
2186 wx.grid.Grid.__init__(self, *args, **kwargs)
2187
2188 self.__patient = None
2189 self.__row_data = {}
2190 self.__prev_row = None
2191 self.__prev_tooltip_row = None
2192 self.__prev_cell_0 = None
2193 self.__grouping_mode = u'issue'
2194 self.__filter_show_unapproved = True
2195 self.__filter_show_inactive = True
2196
2197 self.__grouping2col_labels = {
2198 u'issue': [
2199 _('Health issue'),
2200 _('Substance'),
2201 _('Strength'),
2202 _('Schedule'),
2203 _('Started'),
2204 _('Duration / Until'),
2205 _('Brand'),
2206 _('Advice')
2207 ],
2208 u'brand': [
2209 _('Brand'),
2210 _('Schedule'),
2211 _('Substance'),
2212 _('Strength'),
2213 _('Started'),
2214 _('Duration / Until'),
2215 _('Health issue'),
2216 _('Advice')
2217 ],
2218 u'episode': [
2219 _('Episode'),
2220 _('Substance'),
2221 _('Strength'),
2222 _('Schedule'),
2223 _('Started'),
2224 _('Duration / Until'),
2225 _('Brand'),
2226 _('Advice')
2227 ]
2228 }
2229
2230 self.__grouping2order_by_clauses = {
2231 u'issue': u'pk_health_issue nulls first, substance, started',
2232 u'episode': u'pk_health_issue nulls first, episode, substance, started',
2233 u'brand': u'brand nulls last, substance, started'
2234 }
2235
2236 self.__init_ui()
2237 self.__register_events()
2238
2239
2240
2242
2243 sel_block_top_left = self.GetSelectionBlockTopLeft()
2244 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
2245 sel_cols = self.GetSelectedCols()
2246 sel_rows = self.GetSelectedRows()
2247
2248 selected_cells = []
2249
2250
2251 selected_cells += self.GetSelectedCells()
2252
2253
2254 selected_cells += list (
2255 (row, col)
2256 for row in sel_rows
2257 for col in xrange(self.GetNumberCols())
2258 )
2259
2260
2261 selected_cells += list (
2262 (row, col)
2263 for row in xrange(self.GetNumberRows())
2264 for col in sel_cols
2265 )
2266
2267
2268 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
2269 selected_cells += [
2270 (row, col)
2271 for row in xrange(top_left[0], bottom_right[0] + 1)
2272 for col in xrange(top_left[1], bottom_right[1] + 1)
2273 ]
2274
2275 return set(selected_cells)
2276
2278 rows = {}
2279
2280 for row, col in self.get_selected_cells():
2281 rows[row] = True
2282
2283 return rows.keys()
2284
2287
2289
2290 self.empty_grid()
2291
2292 if self.__patient is None:
2293 return
2294
2295 emr = self.__patient.get_emr()
2296 meds = emr.get_current_substance_intake (
2297 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
2298 include_unapproved = self.__filter_show_unapproved,
2299 include_inactive = self.__filter_show_inactive
2300 )
2301 if not meds:
2302 return
2303
2304 self.BeginBatch()
2305
2306
2307 labels = self.__grouping2col_labels[self.__grouping_mode]
2308 if self.__filter_show_unapproved:
2309 self.AppendCols(numCols = len(labels) + 1)
2310 else:
2311 self.AppendCols(numCols = len(labels))
2312 for col_idx in range(len(labels)):
2313 self.SetColLabelValue(col_idx, labels[col_idx])
2314 if self.__filter_show_unapproved:
2315 self.SetColLabelValue(len(labels), u'OK?')
2316 self.SetColSize(len(labels), 40)
2317
2318 self.AppendRows(numRows = len(meds))
2319
2320
2321 for row_idx in range(len(meds)):
2322 med = meds[row_idx]
2323 self.__row_data[row_idx] = med
2324
2325 if med['is_currently_active'] is True:
2326 atcs = []
2327 if med['atc_substance'] is not None:
2328 atcs.append(med['atc_substance'])
2329
2330
2331
2332 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],))
2333 if allg not in [None, False]:
2334 attr = self.GetOrCreateCellAttr(row_idx, 0)
2335 if allg['type'] == u'allergy':
2336 attr.SetTextColour('red')
2337 else:
2338 attr.SetTextColour('yellow')
2339 self.SetRowAttr(row_idx, attr)
2340 else:
2341 attr = self.GetOrCreateCellAttr(row_idx, 0)
2342 attr.SetTextColour('grey')
2343 self.SetRowAttr(row_idx, attr)
2344
2345 if self.__grouping_mode == u'episode':
2346 if med['pk_episode'] is None:
2347 self.__prev_cell_0 = None
2348 epi = gmTools.u_diameter
2349 else:
2350 if self.__prev_cell_0 == med['episode']:
2351 epi = u''
2352 else:
2353 self.__prev_cell_0 = med['episode']
2354 epi = gmTools.coalesce(med['episode'], u'')
2355 self.SetCellValue(row_idx, 0, gmTools.wrap(text = epi, width = 40))
2356
2357 self.SetCellValue(row_idx, 1, med['substance'])
2358 self.SetCellValue(row_idx, 2, u'%s %s' % (med['amount'], med['unit']))
2359 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
2360 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
2361
2362 if med['is_long_term']:
2363 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
2364 else:
2365 if med['discontinued'] is None:
2366 if med['duration'] is None:
2367 self.SetCellValue(row_idx, 5, u'')
2368 else:
2369 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
2370 else:
2371 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
2372
2373 if med['pk_brand'] is None:
2374 brand = med['preparation']
2375 else:
2376 if med['fake_brand']:
2377 brand = u'%s %s' % (
2378 gmTools.coalesce(med['brand'], u'', _('%s (fake)')),
2379 med['preparation']
2380 )
2381 else:
2382 brand = u'%s %s' % (
2383 gmTools.coalesce(med['brand'], u''),
2384 med['preparation']
2385 )
2386 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35))
2387
2388 elif self.__grouping_mode == u'issue':
2389 if med['pk_health_issue'] is None:
2390 self.__prev_cell_0 = None
2391 issue = u'%s%s' % (
2392 gmTools.u_diameter,
2393 gmTools.coalesce(med['episode'], u'', u' (%s)')
2394 )
2395 else:
2396 if self.__prev_cell_0 == med['health_issue']:
2397 issue = u''
2398 else:
2399 self.__prev_cell_0 = med['health_issue']
2400 issue = med['health_issue']
2401 self.SetCellValue(row_idx, 0, gmTools.wrap(text = issue, width = 40))
2402
2403 self.SetCellValue(row_idx, 1, med['substance'])
2404 self.SetCellValue(row_idx, 2, u'%s %s' % (med['amount'], med['unit']))
2405 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
2406 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
2407
2408 if med['is_long_term']:
2409 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
2410 else:
2411 if med['discontinued'] is None:
2412 if med['duration'] is None:
2413 self.SetCellValue(row_idx, 5, u'')
2414 else:
2415 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
2416 else:
2417 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
2418
2419 if med['pk_brand'] is None:
2420 brand = med['preparation']
2421 else:
2422 if med['fake_brand']:
2423 brand = u'%s %s' % (
2424 gmTools.coalesce(med['brand'], u'', _('%s (fake)')),
2425 med['preparation']
2426 )
2427 else:
2428 brand = u'%s %s' % (
2429 gmTools.coalesce(med['brand'], u''),
2430 med['preparation']
2431 )
2432 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35))
2433
2434 elif self.__grouping_mode == u'brand':
2435
2436 if med['pk_brand'] is None:
2437 self.__prev_cell_0 = None
2438 brand = u'%s (%s)' % (
2439 gmTools.u_diameter,
2440 med['preparation']
2441 )
2442 else:
2443 if self.__prev_cell_0 == med['brand']:
2444 brand = u''
2445 else:
2446 self.__prev_cell_0 = med['brand']
2447 if med['fake_brand']:
2448 brand = u'%s %s' % (
2449 gmTools.coalesce(med['brand'], u'', _('%s (fake)')),
2450 med['preparation']
2451 )
2452 else:
2453 brand = u'%s %s' % (
2454 gmTools.coalesce(med['brand'], u''),
2455 med['preparation']
2456 )
2457 self.SetCellValue(row_idx, 0, gmTools.wrap(text = brand, width = 35))
2458
2459 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
2460 self.SetCellValue(row_idx, 2, med['substance'])
2461 self.SetCellValue(row_idx, 3, u'%s %s' % (med['amount'], med['unit']))
2462 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
2463
2464 if med['is_long_term']:
2465 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
2466 else:
2467 if med['discontinued'] is None:
2468 if med['duration'] is None:
2469 self.SetCellValue(row_idx, 5, u'')
2470 else:
2471 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
2472 else:
2473 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
2474
2475 if med['pk_health_issue'] is None:
2476 issue = u'%s%s' % (
2477 gmTools.u_diameter,
2478 gmTools.coalesce(med['episode'], u'', u' (%s)')
2479 )
2480 else:
2481 issue = gmTools.coalesce(med['health_issue'], u'')
2482 self.SetCellValue(row_idx, 6, gmTools.wrap(text = issue, width = 40))
2483
2484 else:
2485 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
2486
2487 if med['notes'] is not None:
2488 self.SetCellValue(row_idx, 7, gmTools.wrap(text = med['notes'], width = 50))
2489
2490 if self.__filter_show_unapproved:
2491 self.SetCellValue (
2492 row_idx,
2493 len(labels),
2494 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
2495 )
2496
2497
2498
2499 self.AutoSize()
2500 self.EndBatch()
2501
2503 self.BeginBatch()
2504 self.ClearGrid()
2505
2506
2507 if self.GetNumberRows() > 0:
2508 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
2509 if self.GetNumberCols() > 0:
2510 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
2511 self.EndBatch()
2512 self.__row_data = {}
2513 self.__prev_cell_0 = None
2514
2516
2517 if len(self.__row_data) == 0:
2518 return
2519
2520 sel_rows = self.get_selected_rows()
2521 if len(sel_rows) != 1:
2522 return
2523
2524 drug_db = get_drug_database()
2525 if drug_db is None:
2526 return
2527
2528 intake = self.get_selected_data()[0]
2529 if intake['brand'] is None:
2530 drug_db.show_info_on_substance(substance_intake = intake)
2531 else:
2532 drug_db.show_info_on_drug(substance_intake = intake)
2533
2541
2544
2554
2560
2574
2577
2591
2605
2621
2625
2730
2731
2732
2734 self.CreateGrid(0, 1)
2735 self.EnableEditing(0)
2736 self.EnableDragGridSize(1)
2737 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
2738
2739 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
2740
2741 self.SetRowLabelSize(0)
2742 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
2743
2744
2745
2747 return self.__patient
2748
2752
2753 patient = property(_get_patient, _set_patient)
2754
2756 return self.__grouping_mode
2757
2761
2762 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
2763
2765 return self.__filter_show_unapproved
2766
2770
2771 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
2772
2774 return self.__filter_show_inactive
2775
2779
2780 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
2781
2782
2783
2785
2786 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
2787
2788
2789
2790
2791 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
2792
2794 """Calculate where the mouse is and set the tooltip dynamically."""
2795
2796
2797
2798 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812 row, col = self.XYToCell(x, y)
2813
2814 if row == self.__prev_tooltip_row:
2815 return
2816
2817 self.__prev_tooltip_row = row
2818
2819 try:
2820 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
2821 except KeyError:
2822 pass
2823
2828
2829 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
2830
2831 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
2832
2833 """Panel holding a grid with current substances. Used as notebook page."""
2834
2841
2842
2843
2852
2853
2854
2856 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
2857 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
2858 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
2859
2860
2861
2863 wx.CallAfter(self.__on_pre_patient_selection)
2864
2866 self._grid_substances.patient = None
2867
2869 wx.CallAfter(self.__on_post_patient_selection)
2870
2872 self._schedule_data_reget()
2873
2876
2879
2882
2885
2888
2891
2894
2897
2900
2903
2906
2909
2912
2915
2918
2921
2922
2923
2924 if __name__ == '__main__':
2925
2926 if len(sys.argv) < 2:
2927 sys.exit()
2928
2929 if sys.argv[1] != 'test':
2930 sys.exit()
2931
2932 from Gnumed.pycommon import gmI18N
2933 from Gnumed.business import gmPersonSearch
2934
2935 gmI18N.activate_locale()
2936 gmI18N.install_domain(domain = 'gnumed')
2937
2938 pat = gmPersonSearch.ask_for_patient()
2939 if pat is None:
2940 sys.exit()
2941 gmPerson.set_active_patient(patient = pat)
2942
2943
2944
2945
2946
2947
2948 manage_substance_intakes()
2949
2950
2951