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 gmI18N
20 gmI18N.activate_locale()
21 gmI18N.install_domain(domain = 'gnumed')
22
23 from Gnumed.pycommon import gmDispatcher
24 from Gnumed.pycommon import gmCfg
25 from Gnumed.pycommon import gmTools
26 from Gnumed.pycommon import gmDateTime
27 from Gnumed.pycommon import gmMatchProvider
28 from Gnumed.pycommon import gmI18N
29 from Gnumed.pycommon import gmPrinting
30 from Gnumed.pycommon import gmCfg2
31 from Gnumed.pycommon import gmNetworkTools
32
33 from Gnumed.business import gmPerson
34 from Gnumed.business import gmATC
35 from Gnumed.business import gmPraxis
36 from Gnumed.business import gmMedication
37 from Gnumed.business import gmForms
38 from Gnumed.business import gmStaff
39 from Gnumed.business import gmDocuments
40 from Gnumed.business import gmLOINC
41 from Gnumed.business import gmClinicalRecord
42 from Gnumed.business import gmClinicalCalculator
43
44 from Gnumed.wxpython import gmGuiHelpers
45 from Gnumed.wxpython import gmRegetMixin
46 from Gnumed.wxpython import gmAuthWidgets
47 from Gnumed.wxpython import gmEditArea
48 from Gnumed.wxpython import gmMacro
49 from Gnumed.wxpython import gmCfgWidgets
50 from Gnumed.wxpython import gmListWidgets
51 from Gnumed.wxpython import gmPhraseWheel
52 from Gnumed.wxpython import gmFormWidgets
53 from Gnumed.wxpython import gmAllergyWidgets
54 from Gnumed.wxpython import gmDocumentWidgets
55
56
57 _log = logging.getLogger('gm.ui')
58
59
60
61
79
81 dbcfg = gmCfg.cCfgSQL()
82
83
84 default_db = dbcfg.get2 (
85 option = 'external.drug_data.default_source',
86 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
87 bias = 'workplace'
88 )
89
90
91 if default_db is None:
92 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True)
93 configure_drug_data_source(parent = parent)
94 default_db = dbcfg.get2 (
95 option = 'external.drug_data.default_source',
96 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
97 bias = 'workplace'
98 )
99
100 if default_db is None:
101 gmGuiHelpers.gm_show_error (
102 aMessage = _('There is no default drug database configured.'),
103 aTitle = _('Jumping to drug database')
104 )
105 return None
106
107
108
109 try:
110 drug_db = gmMedication.drug_data_source_interfaces[default_db]()
111 except KeyError:
112
113 _log.error('faulty default drug data source configuration: %s', default_db)
114
115 configure_drug_data_source(parent = parent)
116 default_db = dbcfg.get2 (
117 option = 'external.drug_data.default_source',
118 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
119 bias = 'workplace'
120 )
121
122 try:
123 drug_db = gmMedication.drug_data_source_interfaces[default_db]()
124 except KeyError:
125 _log.error('still faulty default drug data source configuration: %s', default_db)
126 return None
127
128 pat = gmPerson.gmCurrentPatient()
129 if pat.connected:
130 drug_db.patient = pat
131
132 return drug_db
133
140
141
143
144 dbcfg = gmCfg.cCfgSQL()
145
146 ifap_cmd = dbcfg.get2 (
147 option = 'external.ifap-win.shell_command',
148 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
149 bias = 'workplace',
150 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
151 )
152 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
153 if not found:
154 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
155 return False
156 ifap_cmd = binary
157
158 if import_drugs:
159 transfer_file = os.path.expanduser(dbcfg.get2 (
160 option = 'external.ifap-win.transfer_file',
161 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
162 bias = 'workplace',
163 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
164 ))
165
166 try:
167 f = open(transfer_file, 'w+b').close()
168 except IOError:
169 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
170 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
171 return False
172
173 wx.BeginBusyCursor()
174 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
175 wx.EndBusyCursor()
176
177 if import_drugs:
178
179
180 try:
181 csv_file = open(transfer_file, 'rb')
182 except:
183 _log.exception('cannot access [%s]', fname)
184 csv_file = None
185
186 if csv_file is not None:
187 import csv
188 csv_lines = csv.DictReader (
189 csv_file,
190 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
191 delimiter = ';'
192 )
193 pat = gmPerson.gmCurrentPatient()
194 emr = pat.get_emr()
195
196 epi = emr.add_episode(episode_name = _('Current medication'))
197 for line in csv_lines:
198 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
199 line['Packungszahl'].strip(),
200 line['Handelsname'].strip(),
201 line['Form'].strip(),
202 line[u'Packungsgr\xf6\xdfe'].strip(),
203 line['Abpackungsmenge'].strip(),
204 line['Einheit'].strip(),
205 line['Hersteller'].strip(),
206 line['PZN'].strip()
207 )
208 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
209 csv_file.close()
210
211 return True
212
213
214
215
216
218
219 if parent is None:
220 parent = wx.GetApp().GetTopWindow()
221
222 def refresh(lctrl):
223 atcs = gmATC.get_reference_atcs()
224
225 items = [ [
226 a['atc'],
227 a['term'],
228 u'%s' % gmTools.coalesce(a['ddd'], u''),
229 gmTools.coalesce(a['unit'], u''),
230 gmTools.coalesce(a['administrative_route'], u''),
231 gmTools.coalesce(a['comment'], u''),
232 a['version'],
233 a['lang']
234 ] for a in atcs ]
235 lctrl.set_string_items(items)
236 lctrl.set_data(atcs)
237
238 gmListWidgets.get_choices_from_list (
239 parent = parent,
240 msg = _('\nThe ATC codes as known to GNUmed.\n'),
241 caption = _('Showing ATC codes.'),
242 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
243 single_selection = True,
244 refresh_callback = refresh
245 )
246
247
249
250 dlg = wx.FileDialog (
251 parent = None,
252 message = _('Choose an ATC import config file'),
253 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
254 defaultFile = '',
255 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
256 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
257 )
258
259 result = dlg.ShowModal()
260 if result == wx.ID_CANCEL:
261 return
262
263 cfg_file = dlg.GetPath()
264 dlg.Destroy()
265
266 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
267 if conn is None:
268 return False
269
270 wx.BeginBusyCursor()
271
272 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
273 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
274 else:
275 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
276
277 wx.EndBusyCursor()
278 return True
279
280
281
283
285
286 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
287
288 query = u"""
289
290 SELECT DISTINCT ON (label)
291 atc_code,
292 label
293 FROM (
294
295 SELECT
296 code as atc_code,
297 (code || ': ' || term || coalesce(' (' || ddd || unit || ')', ''))
298 AS label
299 FROM ref.atc
300 WHERE
301 term %(fragment_condition)s
302 OR
303 code %(fragment_condition)s
304
305 UNION ALL
306
307 SELECT
308 atc_code,
309 (atc_code || ': ' || description)
310 AS label
311 FROM ref.consumable_substance
312 WHERE
313 description %(fragment_condition)s
314 OR
315 atc_code %(fragment_condition)s
316
317 UNION ALL
318
319 SELECT
320 atc_code,
321 (atc_code || ': ' || description || ' (' || preparation || ')')
322 AS label
323 FROM ref.branded_drug
324 WHERE
325 description %(fragment_condition)s
326 OR
327 atc_code %(fragment_condition)s
328
329 -- it would be nice to be able to include clin.vacc_indication but that's hard to do in SQL
330
331 ) AS candidates
332 WHERE atc_code IS NOT NULL
333 ORDER BY label
334 LIMIT 50"""
335
336 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
337 mp.setThresholds(1, 2, 4)
338
339 self.SetToolTipString(_('Select an ATC (Anatomical-Therapeutic-Chemical) code.'))
340 self.matcher = mp
341 self.selection_only = True
342
343
344
345
347
348 if parent is None:
349 parent = wx.GetApp().GetTopWindow()
350
351 def add_from_db(substance):
352 drug_db = get_drug_database(parent = parent)
353 if drug_db is None:
354 return False
355 drug_db.import_drugs()
356 return True
357
358 def edit(substance=None):
359 return edit_consumable_substance(parent = parent, substance = substance, single_entry = (substance is not None))
360
361 def delete(substance):
362 if substance.is_in_use_by_patients:
363 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True)
364 return False
365
366 return gmMedication.delete_consumable_substance(substance = substance['pk'])
367
368 def refresh(lctrl):
369 substs = gmMedication.get_consumable_substances(order_by = 'description')
370 items = [ [
371 s['description'],
372 s['amount'],
373 s['unit'],
374 gmTools.coalesce(s['atc_code'], u''),
375 s['pk']
376 ] for s in substs ]
377 lctrl.set_string_items(items)
378 lctrl.set_data(substs)
379
380 msg = _('\nThese are the consumable substances registered with GNUmed.\n')
381
382 gmListWidgets.get_choices_from_list (
383 parent = parent,
384 msg = msg,
385 caption = _('Showing consumable substances.'),
386 columns = [_('Substance'), _('Amount'), _('Unit'), 'ATC', u'#'],
387 single_selection = True,
388 new_callback = edit,
389 edit_callback = edit,
390 delete_callback = delete,
391 refresh_callback = refresh,
392 left_extra_button = (_('Import'), _('Import consumable substances from a drug database.'), add_from_db)
393 )
394
395
397
398 if substance is not None:
399 if substance.is_in_use_by_patients:
400 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True)
401 return False
402
403 ea = cConsumableSubstanceEAPnl(parent = parent, id = -1)
404 ea.data = substance
405 ea.mode = gmTools.coalesce(substance, 'new', 'edit')
406 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
407 dlg.SetTitle(gmTools.coalesce(substance, _('Adding new consumable substance'), _('Editing consumable substance')))
408 if dlg.ShowModal() == wx.ID_OK:
409 dlg.Destroy()
410 return True
411 dlg.Destroy()
412 return False
413
414
415 from Gnumed.wxGladeWidgets import wxgConsumableSubstanceEAPnl
416
418
436
437
438
439
440
441
442
443
445
446 validity = True
447
448 if self._TCTRL_substance.GetValue().strip() == u'':
449 validity = False
450 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = False)
451 self._TCTRL_substance.SetFocus()
452 else:
453 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = True)
454
455 try:
456 decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.'))
457 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
458 except (TypeError, decimal.InvalidOperation):
459 validity = False
460 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
461 self._TCTRL_amount.SetFocus()
462
463 if self._PRW_unit.GetValue().strip() == u'':
464 validity = False
465 self._PRW_unit.display_as_valid(valid = False)
466 self._TCTRL_substance.SetFocus()
467 else:
468 self._PRW_unit.display_as_valid(valid = True)
469
470 if validity is False:
471 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. Missing essential input.'))
472
473 return validity
474
476 subst = gmMedication.create_consumable_substance (
477 substance = self._TCTRL_substance.GetValue().strip(),
478 atc = self._PRW_atc.GetData(),
479 amount = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')),
480 unit = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None))
481 )
482 success, data = subst.save()
483 if not success:
484 err, msg = data
485 _log.error(err)
486 _log.error(msg)
487 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
488 return False
489
490 self.data = subst
491 return True
492
494 self.data['description'] = self._TCTRL_substance.GetValue().strip()
495 self.data['atc_code'] = self._PRW_atc.GetData()
496 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.'))
497 self.data['unit'] = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None))
498 success, data = self.data.save()
499
500 if not success:
501 err, msg = data
502 _log.error(err)
503 _log.error(msg)
504 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
505 return False
506
507 return True
508
510 self._TCTRL_substance.SetValue(u'')
511 self._TCTRL_amount.SetValue(u'')
512 self._PRW_unit.SetText(u'', None)
513 self._PRW_atc.SetText(u'', None)
514
515 self._TCTRL_substance.SetFocus()
516
524
526 self._refresh_as_new()
527
528
529
530
540
541 def delete(component):
542 if component.is_in_use_by_patients:
543 gmDispatcher.send(signal = 'statustext', msg = _('Cannot remove this component from the drug. It is in use.'), beep = True)
544 return False
545
546 return component.containing_drug.remove_component(substance = component['pk_component'])
547
548 def refresh(lctrl):
549 comps = gmMedication.get_drug_components()
550 items = [ [
551 u'%s%s' % (c['brand'], gmTools.coalesce(c['atc_brand'], u'', u' [%s]')),
552 u'%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], u'', u' [%s]')),
553 u'%s %s' % (c['amount'], c['unit']),
554 c['preparation'],
555 gmTools.coalesce(c['external_code_brand'], u'', u'%%s [%s]' % c['external_code_type_brand']),
556 c['pk_component']
557 ] for c in comps ]
558 lctrl.set_string_items(items)
559 lctrl.set_data(comps)
560
561 msg = _('\nThese are the components in the drug brands known to GNUmed.\n')
562
563 gmListWidgets.get_choices_from_list (
564 parent = parent,
565 msg = msg,
566 caption = _('Showing drug brand components.'),
567 columns = [_('Brand'), _('Substance'), _('Strength'), _('Preparation'), _('Code'), u'#'],
568 single_selection = True,
569
570 edit_callback = edit,
571 delete_callback = delete,
572 refresh_callback = refresh
573 )
574
575
587
588
589 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl
590
591 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
592
610
611
612
613
614
615
616
617
619 if self.data is not None:
620 if self.data['is_in_use']:
621 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug component. It is in use.'), beep = True)
622 return False
623
624 validity = True
625
626 if self._PRW_substance.GetData() is None:
627 validity = False
628 self._PRW_substance.display_as_valid(False)
629 else:
630 self._PRW_substance.display_as_valid(True)
631
632 val = self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1)
633 try:
634 decimal.Decimal(val)
635 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
636 except:
637 validity = False
638 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
639
640 if self._PRW_unit.GetValue().strip() == u'':
641 validity = False
642 self._PRW_unit.display_as_valid(False)
643 else:
644 self._PRW_unit.display_as_valid(True)
645
646 if validity is False:
647 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save drug component. Invalid or missing essential input.'))
648
649 return validity
650
652
653 data = 1
654 data[''] = 1
655 data[''] = 1
656
657
658
659
660
661
662 return False
663 return True
664
666 self.data['pk_consumable_substance'] = self._PRW_substance.GetData()
667 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1))
668 self.data['unit'] = self._PRW_unit.GetValue().strip()
669 return self.data.save()
670
680
682 self._TCTRL_brand.SetValue(u'%s (%s)' % (self.data['brand'], self.data['preparation']))
683 self._TCTRL_components.SetValue(u' / '.join(self.data.containing_drug['components']))
684 details = []
685 if self.data['atc_brand'] is not None:
686 details.append(u'ATC: %s' % self.data['atc_brand'])
687 if self.data['external_code_brand'] is not None:
688 details.append(u'%s: %s' % (self.data['external_code_type_brand'], self.data['external_code_brand']))
689 self._TCTRL_codes.SetValue(u'; '.join(details))
690
691 self._PRW_substance.SetText(self.data['substance'], self.data['pk_consumable_substance'])
692 self._TCTRL_amount.SetValue(u'%s' % self.data['amount'])
693 self._PRW_unit.SetText(self.data['unit'], self.data['unit'])
694
695 self._PRW_substance.SetFocus()
696
698
699
700
701 self._PRW_substance.SetText(u'', None)
702 self._TCTRL_amount.SetValue(u'')
703 self._PRW_unit.SetText(u'', None)
704
705 self._PRW_substance.SetFocus()
706
707
721
722
723
725
727
728 query = u"""
729 (
730 SELECT DISTINCT ON (list_label)
731 preparation AS data,
732 preparation AS list_label,
733 preparation AS field_label
734 FROM ref.branded_drug
735 WHERE preparation %(fragment_condition)s
736 ) UNION (
737 SELECT DISTINCT ON (list_label)
738 preparation AS data,
739 preparation AS list_label,
740 preparation AS field_label
741 FROM clin.substance_intake
742 WHERE preparation %(fragment_condition)s
743 )
744 ORDER BY list_label
745 LIMIT 30"""
746
747 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
748 mp.setThresholds(1, 2, 4)
749 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
750 self.SetToolTipString(_('The preparation (form) of the substance or brand.'))
751 self.matcher = mp
752 self.selection_only = False
753
754
770
771
772
773
775
776 if brand is not None:
777 if brand.is_in_use_by_patients:
778 gmGuiHelpers.gm_show_info (
779 aTitle = _('Managing components of a drug'),
780 aMessage = _(
781 'Cannot manage the components of the branded drug product\n'
782 '\n'
783 ' "%s" (%s)\n'
784 '\n'
785 'because it is currently taken by patients.\n'
786 ) % (brand['brand'], brand['preparation'])
787 )
788 return False
789
790 if parent is None:
791 parent = wx.GetApp().GetTopWindow()
792
793
794
795
796 if brand is None:
797 msg = _('Pick the substances which are components of this drug.')
798 right_col = _('Components of drug')
799 comp_substs = []
800 else:
801 right_col = u'%s (%s)' % (brand['brand'], brand['preparation'])
802 msg = _(
803 'Adjust the components of "%s"\n'
804 '\n'
805 'The drug must contain at least one component. Any given\n'
806 'substance can only be included once per drug.'
807 ) % right_col
808 comp_substs = [ c.substance for c in brand.components ]
809
810 substs = gmMedication.get_consumable_substances(order_by = 'description')
811 choices = [ u'%s %s %s' % (s['description'], s['amount'], s['unit']) for s in substs ]
812 picks = [ u'%s %s %s' % (c['description'], c['amount'], c['unit']) for c in comp_substs ]
813
814 picker = gmListWidgets.cItemPickerDlg (
815 parent,
816 -1,
817 title = _('Managing components of a drug ...'),
818 msg = msg
819 )
820 picker.set_columns(['Substances'], [right_col])
821 picker.set_choices(choices = choices, data = substs)
822 picker.set_picks(picks = picks, data = comp_substs)
823
824
825
826
827
828
829 btn_pressed = picker.ShowModal()
830 substs = picker.get_picks()
831 picker.Destroy()
832
833 if btn_pressed != wx.ID_OK:
834 return (False, None)
835
836 if brand is not None:
837 brand.set_substances_as_components(substances = substs)
838
839 return (True, substs)
840
842
843 if parent is None:
844 parent = wx.GetApp().GetTopWindow()
845
846 def add_from_db(brand):
847 drug_db = get_drug_database(parent = parent)
848 if drug_db is None:
849 return False
850 drug_db.import_drugs()
851 return True
852
853 def get_tooltip(brand=None):
854 tt = u'%s %s\n' % (brand['brand'], brand['preparation'])
855 tt += u'\n'
856 tt += u'%s%s%s\n' % (
857 gmTools.bool2subst(brand.is_vaccine, u'%s, ' % _('Vaccine'), u''),
858 u'%s, ' % gmTools.bool2subst(brand.is_in_use_by_patients, _('in use'), _('not in use')),
859 gmTools.bool2subst(brand['is_fake_brand'], _('fake'), u'')
860 )
861 tt += gmTools.coalesce(brand['atc'], u'', _('ATC: %s\n'))
862 tt += gmTools.coalesce(brand['external_code'], u'', u'%s: %%s\n' % brand['external_code_type'])
863 if brand['components'] is not None:
864 tt += u'- %s' % u'\n- '.join(brand['components'])
865 return tt
866
867 def edit(brand):
868 if brand is not None:
869 if brand.is_vaccine:
870 gmGuiHelpers.gm_show_info (
871 aTitle = _('Editing medication'),
872 aMessage = _(
873 'Cannot edit the medication\n'
874 '\n'
875 ' "%s" (%s)\n'
876 '\n'
877 'because it is a vaccine. Please edit it\n'
878 'from the vaccine management section !\n'
879 ) % (brand['brand'], brand['preparation'])
880 )
881 return False
882
883 return edit_branded_drug(parent = parent, branded_drug = brand, single_entry = True)
884
885 def delete(brand):
886 if brand.is_vaccine:
887 gmGuiHelpers.gm_show_info (
888 aTitle = _('Deleting medication'),
889 aMessage = _(
890 'Cannot delete the medication\n'
891 '\n'
892 ' "%s" (%s)\n'
893 '\n'
894 'because it is a vaccine. Please delete it\n'
895 'from the vaccine management section !\n'
896 ) % (brand['brand'], brand['preparation'])
897 )
898 return False
899 gmMedication.delete_branded_drug(brand = brand['pk_brand'])
900 return True
901
902 def new():
903 return edit_branded_drug(parent = parent, branded_drug = None, single_entry = False)
904
905 def refresh(lctrl):
906 drugs = gmMedication.get_branded_drugs()
907 items = [ [
908 u'%s%s' % (
909 d['brand'],
910 gmTools.bool2subst(d['is_fake_brand'], ' (%s)' % _('fake'), u'')
911 ),
912 d['preparation'],
913 gmTools.coalesce(d['atc'], u''),
914 gmTools.coalesce(d['components'], u''),
915 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
916 d['pk_brand']
917 ] for d in drugs ]
918 lctrl.set_string_items(items)
919 lctrl.set_data(drugs)
920
921 msg = _('\nThese are the drug brands known to GNUmed.\n')
922
923 gmListWidgets.get_choices_from_list (
924 parent = parent,
925 msg = msg,
926 caption = _('Showing branded drugs.'),
927 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), u'#'],
928 single_selection = True,
929 ignore_OK_button = ignore_OK_button,
930 refresh_callback = refresh,
931 new_callback = new,
932 edit_callback = edit,
933 delete_callback = delete,
934 list_tooltip_callback = get_tooltip,
935 left_extra_button = (_('Import'), _('Import substances and brands from a drug database.'), add_from_db)
936
937
938 )
939
940
942
943 if branded_drug is not None:
944 if branded_drug.is_in_use_by_patients:
945 gmGuiHelpers.gm_show_info (
946 aTitle = _('Editing drug'),
947 aMessage = _(
948 'Cannot edit the branded drug product\n'
949 '\n'
950 ' "%s" (%s)\n'
951 '\n'
952 'because it is currently taken by patients.\n'
953 ) % (branded_drug['brand'], branded_drug['preparation'])
954 )
955 return False
956
957 if parent is None:
958 parent = wx.GetApp().GetTopWindow()
959
960 def manage_substances(drug):
961 manage_consumable_substances(parent = parent)
962
963 ea = cBrandedDrugEAPnl(parent = parent, id = -1)
964 ea.data = branded_drug
965 ea.mode = gmTools.coalesce(branded_drug, 'new', 'edit')
966 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
967 dlg.SetTitle(gmTools.coalesce(branded_drug, _('Adding new drug brand'), _('Editing drug brand')))
968 dlg.left_extra_button = (
969 _('Substances'),
970 _('Manage consumable substances'),
971 manage_substances
972 )
973 if dlg.ShowModal() == wx.ID_OK:
974 dlg.Destroy()
975 return True
976 dlg.Destroy()
977 return False
978
979
980 from Gnumed.wxGladeWidgets import wxgBrandedDrugEAPnl
981
982 -class cBrandedDrugEAPnl(wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
983
1000
1001
1002
1003
1004
1005
1006
1007
1009
1010 if self.data is not None:
1011 if self.data.is_in_use_by_patients:
1012 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug brand. It is in use.'), beep = True)
1013 return False
1014
1015 validity = True
1016
1017 brand_name = self._PRW_brand.GetValue().strip()
1018 if brand_name == u'':
1019 validity = False
1020 self._PRW_brand.display_as_valid(False)
1021 else:
1022 self._PRW_brand.display_as_valid(True)
1023
1024 preparation = self._PRW_preparation.GetValue().strip()
1025 if preparation == u'':
1026 validity = False
1027 self._PRW_preparation.display_as_valid(False)
1028 else:
1029 self._PRW_preparation.display_as_valid(True)
1030
1031 if validity is True:
1032
1033 drug = gmMedication.get_drug_by_brand(brand_name = brand_name, preparation = preparation)
1034 if drug is not None:
1035 validity = False
1036 self._PRW_brand.display_as_valid(False)
1037 self._PRW_preparation.display_as_valid(False)
1038 gmGuiHelpers.gm_show_error (
1039 title = _('Checking brand data'),
1040 error = _(
1041 'The brand information you entered:\n'
1042 '\n'
1043 ' [%s %s]\n'
1044 '\n'
1045 'already exists as a drug product.'
1046 ) % (brand_name, preparation)
1047 )
1048
1049 else:
1050
1051 self._TCTRL_components.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BACKGROUND))
1052 if len(self.__component_substances) == 0:
1053 wants_empty = gmGuiHelpers.gm_show_question (
1054 title = _('Checking brand data'),
1055 question = _(
1056 'You have not selected any substances\n'
1057 'as drug components.\n'
1058 '\n'
1059 'Without components you will not be able to\n'
1060 'use this drug for documenting patient care.\n'
1061 '\n'
1062 'Are you sure you want to save\n'
1063 'it without components ?'
1064 )
1065 )
1066 if not wants_empty:
1067 validity = False
1068 self.display_ctrl_as_valid(ctrl = self._TCTRL_components, valid = False)
1069
1070 if validity is False:
1071 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save branded drug. Invalid or missing essential input.'))
1072
1073 return validity
1074
1076
1077 drug = gmMedication.create_branded_drug (
1078 brand_name = self._PRW_brand.GetValue().strip(),
1079 preparation = gmTools.coalesce (
1080 self._PRW_preparation.GetData(),
1081 self._PRW_preparation.GetValue()
1082 ).strip(),
1083 return_existing = True
1084 )
1085 drug['is_fake_brand'] = self._CHBOX_is_fake.GetValue()
1086 drug['atc'] = self._PRW_atc.GetData()
1087 code = self._TCTRL_external_code.GetValue().strip()
1088 if code != u'':
1089 drug['external_code'] = code
1090 drug['external_code_type'] = self._PRW_external_code_type.GetData().strip()
1091
1092 drug.save()
1093
1094 if len(self.__component_substances) > 0:
1095 drug.set_substances_as_components(substances = self.__component_substances)
1096
1097 self.data = drug
1098
1099 return True
1100
1102 self.data['brand'] = self._PRW_brand.GetValue().strip()
1103 self.data['preparation'] = gmTools.coalesce (
1104 self._PRW_preparation.GetData(),
1105 self._PRW_preparation.GetValue()
1106 ).strip()
1107 self.data['is_fake_brand'] = self._CHBOX_is_fake.GetValue()
1108 self.data['atc'] = self._PRW_atc.GetData()
1109 code = self._TCTRL_external_code.GetValue().strip()
1110 if code != u'':
1111 self.data['external_code'] = code
1112 self.data['external_code_type'] = self._PRW_external_code_type.GetData().strip()
1113 success, data = self.data.save()
1114 if not success:
1115 err, msg = data
1116 _log.error('problem saving')
1117 _log.error('%s', err)
1118 _log.error('%s', msg)
1119 return (success is True)
1120
1122 self._PRW_brand.SetText(u'', None)
1123 self._PRW_preparation.SetText(u'', None)
1124 self._CHBOX_is_fake.SetValue(False)
1125 self._TCTRL_components.SetValue(u'')
1126 self._PRW_atc.SetText(u'', None)
1127 self._TCTRL_external_code.SetValue(u'')
1128 self._PRW_external_code_type.SetText(u'', None)
1129
1130 self._PRW_brand.SetFocus()
1131
1132 self.__component_substances = []
1133
1135 self._refresh_as_new()
1136
1153
1154
1155
1169
1171
1173
1174 query = u"""
1175 SELECT
1176 pk
1177 AS data,
1178 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
1179 AS list_label,
1180 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
1181 AS field_label
1182 FROM ref.branded_drug
1183 WHERE description %(fragment_condition)s
1184 ORDER BY list_label
1185 LIMIT 50"""
1186
1187 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1188 mp.setThresholds(2, 3, 4)
1189 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1190 self.SetToolTipString(_(
1191 'The brand name of the drug.\n'
1192 '\n'
1193 'Note: a brand name will need to be linked to\n'
1194 'one or more components before it can be used,\n'
1195 'except in the case of fake (generic) vaccines.'
1196 ))
1197 self.matcher = mp
1198 self.selection_only = False
1199
1200
1201
1202
1204
1206
1207 query = u"""
1208 SELECT DISTINCT ON (sched)
1209 schedule as sched,
1210 schedule
1211 FROM clin.substance_intake
1212 WHERE schedule %(fragment_condition)s
1213 ORDER BY sched
1214 LIMIT 50"""
1215
1216 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1217 mp.setThresholds(1, 2, 4)
1218 mp.word_separators = '[ \t=+&:@]+'
1219 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1220 self.SetToolTipString(_('The schedule for taking this substance.'))
1221 self.matcher = mp
1222 self.selection_only = False
1223
1224
1226
1228
1229 query = u"""
1230 (
1231 SELECT DISTINCT ON (field_label)
1232 aim
1233 AS data,
1234 aim || ' (' || substance || ' ' || amount || ' ' || unit || ')'
1235 AS list_label,
1236 aim
1237 AS field_label
1238 FROM clin.v_substance_intakes
1239 WHERE
1240 aim %(fragment_condition)s
1241 %(ctxt_substance)s
1242 ) UNION (
1243 SELECT DISTINCT ON (field_label)
1244 aim
1245 AS data,
1246 aim || ' (' || substance || ' ' || amount || ' ' || unit || ')'
1247 AS list_label,
1248 aim
1249 AS field_label
1250 FROM clin.v_substance_intakes
1251 WHERE
1252 aim %(fragment_condition)s
1253 )
1254 ORDER BY list_label
1255 LIMIT 30"""
1256
1257 context = {'ctxt_substance': {
1258 'where_part': u'AND substance = %(substance)s',
1259 'placeholder': u'substance'
1260 }}
1261
1262 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query, context = context)
1263 mp.setThresholds(1, 2, 4)
1264
1265 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1266 self.SetToolTipString(_('The medical aim for consuming this substance.'))
1267 self.matcher = mp
1268 self.selection_only = False
1269
1270
1272
1273 if intake['is_currently_active']:
1274 intake['discontinued'] = gmDateTime.pydt_now_here()
1275 if intake['discontinue_reason'] is None:
1276 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), _('discontinued due to allergy or intolerance'))
1277 else:
1278 if not intake['discontinue_reason'].startswith(_('not tolerated:')):
1279 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), intake['discontinue_reason'])
1280 if not intake.save():
1281 return False
1282
1283 allg = intake.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1284
1285 brand = intake.containing_drug
1286 if brand is not None:
1287 comps = [ c['substance'] for c in brand.components ]
1288 if len(comps) > 1:
1289 gmGuiHelpers.gm_show_info (
1290 aTitle = _(u'Documented an allergy'),
1291 aMessage = _(
1292 u'An allergy was documented against the substance:\n'
1293 u'\n'
1294 u' [%s]\n'
1295 u'\n'
1296 u'This substance was taken with the multi-component brand:\n'
1297 u'\n'
1298 u' [%s (%s)]\n'
1299 u'\n'
1300 u'Note that ALL components of this brand were discontinued.'
1301 ) % (
1302 intake['substance'],
1303 intake['brand'],
1304 u' & '.join(comps)
1305 )
1306 )
1307
1308 if parent is None:
1309 parent = wx.GetApp().GetTopWindow()
1310
1311 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = parent, id = -1)
1312 dlg.ShowModal()
1313
1314 return True
1315
1316
1318
1319 if parent is None:
1320 parent = wx.GetApp().GetTopWindow()
1321
1322 if emr is None:
1323 emr = gmPerson.gmCurrentPatient().emr
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342 def get_tooltip(intake=None):
1343 return intake.format(one_line = False, show_all_brand_components = True)
1344
1345 def refresh(lctrl):
1346 intakes = emr.get_current_substance_intakes (
1347 include_inactive = False,
1348 include_unapproved = True,
1349 order_by = u'substance, brand, started'
1350 )
1351 items = []
1352 for i in intakes:
1353 if i['started'] is None:
1354 started = u''
1355 else:
1356 started = u'%s:' % gmDateTime.pydt_strftime(i['started'], '%Y %b %d')
1357 items.append ([
1358 u'%s%s %s %s %s%s' % (
1359 i['substance'],
1360 gmTools.coalesce(i['brand'], u'', u' (%s)'),
1361 i['amount'],
1362 i['unit'],
1363 i['preparation'],
1364 gmTools.coalesce(i['external_code_brand'], u'', u' [%s::%s]' % (i['external_code_type_brand'], i['external_code_brand']))
1365 ),
1366 u'%s%s%s' % (
1367 started,
1368 gmTools.coalesce(i['schedule'], u'', u' %%s %s' % gmTools.u_right_arrow),
1369 gmTools.coalesce(i['duration'], u'', u' %s')
1370 ),
1371 u'%s' % (
1372 gmTools.bool2subst (
1373 i['intake_is_approved_of'],
1374 u'',
1375 _('disapproved')
1376 )
1377 )
1378 ])
1379 lctrl.set_string_items(items)
1380 lctrl.set_data(intakes)
1381
1382 msg = _('Substances consumed by the patient:')
1383
1384 return gmListWidgets.get_choices_from_list (
1385 parent = parent,
1386 msg = msg,
1387 caption = _('Showing consumable substances.'),
1388 columns = [ _('Intake'), _('Application'), _('Status') ],
1389 single_selection = False,
1390
1391
1392
1393 refresh_callback = refresh,
1394 list_tooltip_callback = get_tooltip
1395
1396 )
1397
1398
1399 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
1400
1401 -class cSubstanceIntakeEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
1402
1422
1434
1436 curr_pat = gmPerson.gmCurrentPatient()
1437 emr = curr_pat.emr
1438
1439 state = emr.allergy_state
1440 if state['last_confirmed'] is None:
1441 confirmed = _('never')
1442 else:
1443 confirmed = gmDateTime.pydt_strftime(state['last_confirmed'], '%Y %b %d')
1444 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
1445 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
1446
1447 tt = u''
1448
1449 allgs = emr.get_allergies()
1450 if len(allgs) > 0:
1451 msg += u'\n'
1452 for allergy in allgs:
1453 msg += u'%s: %s (%s)\n' % (
1454 allergy['descriptor'],
1455 allergy['l10n_type'],
1456 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?')
1457 )
1458 tt += u'%s: %s\n' % (
1459 allergy['descriptor'],
1460 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
1461 )
1462
1463 if len(allgs) > 0:
1464 msg += u'\n'
1465 tt += u'\n'
1466
1467 gfr = emr.get_most_recent_results(loinc = gmLOINC.LOINC_gfr_quantity, no_of_results = 1)
1468 if gfr is None:
1469 self.calc.patient = curr_pat
1470 gfr = self.calc.eGFR
1471 if gfr.numeric_value is None:
1472 msg += _('GFR: unknown')
1473 else:
1474 msg += gfr.message
1475 tt += gfr.format (
1476 left_margin = 0,
1477 width = 50,
1478 eol = u'\n',
1479 with_formula = True,
1480 with_warnings = True,
1481 with_variables = False,
1482 with_sub_results = True,
1483 return_list = False
1484 )
1485 else:
1486 msg += u'%s: %s %s (%s)\n' % (
1487 gfr['unified_abbrev'],
1488 gfr['unified_val'],
1489 gmTools.coalesce(gfr['abnormality_indicator'], u'', u' (%s)'),
1490 gmDateTime.pydt_strftime (
1491 gfr['clin_when'],
1492 format = '%Y %b %d'
1493 )
1494 )
1495 tt += _('GFR reported by path lab')
1496
1497 self._LBL_allergies.SetLabel(msg)
1498 self._LBL_allergies.SetToolTipString(tt)
1499
1500
1501
1608
1610
1611 emr = gmPerson.gmCurrentPatient().get_emr()
1612 epi = self._PRW_episode.GetData(can_create = True)
1613
1614 if self._PRW_substance.GetData() is None:
1615
1616 intake = emr.add_substance_intake (
1617 pk_component = self._PRW_component.GetData(),
1618 episode = epi
1619 )
1620 else:
1621 intake = emr.add_substance_intake (
1622 pk_substance = self._PRW_substance.GetData(),
1623 episode = epi,
1624 preparation = self._PRW_preparation.GetValue().strip()
1625 )
1626
1627 if intake is None:
1628 gmDispatcher.send('statustext', msg = _('Cannot add duplicate of (maybe inactive) substance intake.'), beep = True)
1629 return False
1630
1631 intake['started'] = self._DP_started.GetData()
1632 intake['discontinued'] = self._DP_discontinued.GetData()
1633 if intake['discontinued'] is None:
1634 intake['discontinue_reason'] = None
1635 else:
1636 intake['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1637 intake['schedule'] = self._PRW_schedule.GetValue().strip()
1638 intake['aim'] = self._PRW_aim.GetValue().strip()
1639 intake['notes'] = self._PRW_notes.GetValue().strip()
1640 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
1641 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1642 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1643 intake['duration'] = None
1644 else:
1645 if self._PRW_duration.GetData() is None:
1646 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1647 else:
1648 intake['duration'] = self._PRW_duration.GetData()
1649 intake.save()
1650
1651 self.data = intake
1652
1653 return True
1654
1656
1657
1658 self.data['started'] = self._DP_started.GetData()
1659 self.data['discontinued'] = self._DP_discontinued.GetData()
1660 if self.data['discontinued'] is None:
1661 self.data['discontinue_reason'] = None
1662 else:
1663 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1664 self.data['schedule'] = self._PRW_schedule.GetValue()
1665 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
1666 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1667 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1668 self.data['duration'] = None
1669 else:
1670
1671 if self._PRW_duration.GetData() is None:
1672 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1673 else:
1674 self.data['duration'] = self._PRW_duration.GetData()
1675
1676
1677 self.data['preparation'] = self._PRW_preparation.GetValue()
1678
1679
1680 self.data['aim'] = self._PRW_aim.GetValue()
1681 self.data['notes'] = self._PRW_notes.GetValue()
1682 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
1683
1684 self.data.save()
1685
1686 return True
1687
1689 self._PRW_component.SetText(u'', None)
1690 self._LBL_component.Enable(True)
1691 self._PRW_component.Enable(True)
1692 self._TCTRL_brand_ingredients.SetValue(u'')
1693 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1694
1695 self._LBL_or.Enable(True)
1696
1697 self._PRW_substance.SetText(u'', None)
1698 self._PRW_substance.Enable(True)
1699
1700 self._PRW_preparation.SetText(u'', None)
1701 self._PRW_preparation.Enable(True)
1702
1703 self._PRW_schedule.SetText(u'', None)
1704 self._PRW_duration.SetText(u'', None)
1705 self._PRW_aim.SetText(u'', None)
1706 self._PRW_notes.SetText(u'', None)
1707 self._PRW_episode.SetText(u'', None)
1708
1709 self._CHBOX_long_term.SetValue(False)
1710 self._CHBOX_approved.SetValue(True)
1711
1712 self._DP_started.SetData(gmDateTime.pydt_now_here())
1713 self._DP_discontinued.SetData(None)
1714 self._PRW_discontinue_reason.SetValue(u'')
1715
1716 self.__refresh_allergies()
1717
1718 self._PRW_component.SetFocus()
1719
1721
1722 self._TCTRL_brand_ingredients.SetValue(u'')
1723 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1724
1725 if self.data['pk_brand'] is None:
1726 self.__refresh_from_existing_substance()
1727 else:
1728 self.__refresh_from_existing_component()
1729
1730
1731 self._LBL_component.Enable(False)
1732 self._PRW_component.Enable(False)
1733 self._LBL_or.Enable(False)
1734 self._PRW_substance.Enable(False)
1735
1736 if self.data['is_long_term']:
1737 self._CHBOX_long_term.SetValue(True)
1738 self._PRW_duration.Enable(False)
1739 self._PRW_duration.SetText(gmTools.u_infinity, None)
1740 self._BTN_discontinued_as_planned.Enable(False)
1741 else:
1742 self._CHBOX_long_term.SetValue(False)
1743 self._PRW_duration.Enable(True)
1744 self._BTN_discontinued_as_planned.Enable(True)
1745 self._PRW_duration.SetData(self.data['duration'])
1746
1747
1748
1749
1750 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
1751 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
1752 self._PRW_episode.SetData(self.data['pk_episode'])
1753 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
1754
1755 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
1756
1757 self._DP_started.SetData(self.data['started'])
1758 self._DP_discontinued.SetData(self.data['discontinued'])
1759 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
1760 if self.data['discontinued'] is not None:
1761 self._PRW_discontinue_reason.Enable()
1762
1763 self.__refresh_allergies()
1764
1765 self._PRW_schedule.SetFocus()
1766
1768 self._LBL_component.Enable(False)
1769 self._PRW_component.Enable(False)
1770 self._PRW_component.SetText(u'', None)
1771 self._PRW_component.display_as_valid(True)
1772
1773 self._LBL_or.Enable(False)
1774
1775 self._PRW_substance.Enable(True)
1776 self._PRW_substance.SetText (
1777 u'%s %s %s' % (self.data['substance'], self.data['amount'], self.data['unit']),
1778 self.data['pk_substance']
1779 )
1780
1781
1782 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation'])
1783 self._PRW_preparation.Enable(True)
1784
1786 self._LBL_component.Enable(True)
1787 self._PRW_component.Enable(True)
1788 self._PRW_component.SetText (
1789 u'%s %s %s (%s)' % (self.data['substance'], self.data['amount'], self.data['unit'], self.data['brand']),
1790 self.data['pk_drug_component']
1791 )
1792
1793 brand = gmMedication.cBrandedDrug(aPK_obj = self.data['pk_brand'])
1794 if brand['components'] is not None:
1795 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components']))
1796 tt = u'%s:\n\n- %s' % (
1797 self.data['brand'],
1798 u'\n- '.join(brand['components'])
1799 )
1800 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1801
1802 self._LBL_or.Enable(False)
1803 self._LBL_substance.Enable(False)
1804 self._PRW_substance.SetText(u'', None)
1805 self._PRW_substance.display_as_valid(True)
1806
1807 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation'])
1808 self._PRW_preparation.Enable(False)
1809
1811 self._refresh_as_new()
1812
1813 self._PRW_episode.SetData(self.data['pk_episode'])
1814
1815 self._PRW_component.SetFocus()
1816
1817
1818
1820 if self._PRW_component.GetData() is None:
1821 self._LBL_or.Enable(True)
1822 self._PRW_component.SetText(u'', None)
1823 self._LBL_substance.Enable(True)
1824 self._PRW_substance.Enable(True)
1825 self._LBL_preparation.Enable(True)
1826 self._PRW_preparation.Enable(True)
1827
1828 self._TCTRL_brand_ingredients.SetValue(u'')
1829 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1830 else:
1831 self._LBL_or.Enable(False)
1832 self._LBL_substance.Enable(False)
1833 self._PRW_substance.SetText(u'', None)
1834 self._PRW_substance.display_as_valid(True)
1835 self._PRW_substance.Enable(False)
1836 self._LBL_preparation.Enable(False)
1837 self._PRW_preparation.Enable(False)
1838 comp = gmMedication.cDrugComponent(aPK_obj = self._PRW_component.GetData())
1839 self._PRW_preparation.SetText(comp['preparation'], comp['preparation'])
1840 brand = comp.containing_drug
1841 if brand['components'] is not None:
1842 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components']))
1843 tt = u'%s:\n\n- %s' % (
1844 brand['brand'],
1845 u'\n- '.join(brand['components'])
1846 )
1847 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1848
1850 if self._PRW_substance.GetData() is None:
1851 self._LBL_or.Enable(True)
1852 self._LBL_component.Enable(True)
1853 self._PRW_component.Enable(True)
1854 self._PRW_substance.SetText(u'', None)
1855 else:
1856 self._LBL_or.Enable(False)
1857 self._LBL_component.Enable(False)
1858 self._PRW_component.SetText(u'', None)
1859 self._PRW_component.display_as_valid(True)
1860 self._PRW_component.Enable(False)
1861 self._LBL_preparation.Enable(True)
1862 self._PRW_preparation.Enable(True)
1863 self._TCTRL_brand_ingredients.SetValue(u'')
1864 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1865
1867
1868
1869
1870
1871
1872 subst = self._PRW_component.GetValue().strip()
1873 if subst != u'':
1874 comp = self._PRW_component.GetData(as_instance = True)
1875 if comp is None:
1876 self._PRW_aim.set_context(context = u'substance', val = subst)
1877 return
1878 self._PRW_aim.set_context(context = u'substance', val = comp['substance'])
1879 return
1880
1881 subst = self._PRW_substance.GetValue().strip()
1882 if subst == u'':
1883 self._PRW_aim.unset_context(context = u'substance')
1884 return
1885 comp = self._PRW_substance.GetData(as_instance = True)
1886 if comp is None:
1887 self._PRW_aim.set_context(context = u'substance', val = subst)
1888 return
1889 self._PRW_aim.set_context(context = u'substance', val = comp['description'])
1890
1892 if self._DP_discontinued.GetData() is None:
1893 self._PRW_discontinue_reason.Enable(False)
1894 else:
1895 self._PRW_discontinue_reason.Enable(True)
1896
1899
1902
1905
1917
1947
1949 if self._CHBOX_long_term.IsChecked() is True:
1950 self._PRW_duration.Enable(False)
1951 self._BTN_discontinued_as_planned.Enable(False)
1952 self._PRW_discontinue_reason.Enable(False)
1953 else:
1954 self._PRW_duration.Enable(True)
1955 self._BTN_discontinued_as_planned.Enable(True)
1956 self._PRW_discontinue_reason.Enable(True)
1957
1958 self.__refresh_allergies()
1959
1969
1970
1972
1973 subst = gmMedication.cSubstanceIntakeEntry(aPK_obj = substance)
1974 msg = _(
1975 '\n'
1976 '[%s]\n'
1977 '\n'
1978 'It may be prudent to edit (before deletion) the details\n'
1979 'of this substance intake entry so as to leave behind\n'
1980 'some indication of why it was deleted.\n'
1981 ) % subst.format()
1982
1983 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1984 parent,
1985 -1,
1986 caption = _('Deleting medication / substance intake'),
1987 question = msg,
1988 button_defs = [
1989 {'label': _('&Edit'), 'tooltip': _('Allow editing of substance intake entry before deletion.'), 'default': True},
1990 {'label': _('&Delete'), 'tooltip': _('Delete immediately without editing first.')},
1991 {'label': _('&Cancel'), 'tooltip': _('Abort. Do not delete or edit substance intake entry.')}
1992 ]
1993 )
1994
1995 edit_first = dlg.ShowModal()
1996 dlg.Destroy()
1997
1998 if edit_first == wx.ID_CANCEL:
1999 return
2000
2001 if edit_first == wx.ID_YES:
2002 edit_intake_of_substance(parent = parent, substance = subst)
2003 delete_it = gmGuiHelpers.gm_show_question (
2004 aMessage = _('Now delete substance intake entry ?'),
2005 aTitle = _('Deleting medication / substance intake')
2006 )
2007 else:
2008 delete_it = True
2009
2010 if not delete_it:
2011 return
2012
2013 gmMedication.delete_substance_intake(substance = substance)
2014
2029
2030
2031
2032
2060
2062
2063 if parent is None:
2064 parent = wx.GetApp().GetTopWindow()
2065
2066
2067 dbcfg = gmCfg.cCfgSQL()
2068 option = u'form_templates.medication_list'
2069
2070 template = dbcfg.get2 (
2071 option = option,
2072 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
2073 bias = 'user'
2074 )
2075
2076 if template is None:
2077 template = configure_medication_list_template(parent = parent)
2078 if template is None:
2079 gmGuiHelpers.gm_show_error (
2080 aMessage = _('There is no medication list template configured.'),
2081 aTitle = _('Printing medication list')
2082 )
2083 return False
2084 else:
2085 try:
2086 name, ver = template.split(u' - ')
2087 except:
2088 _log.exception('problem splitting medication list template name [%s]', template)
2089 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
2090 return False
2091 template = gmForms.get_form_template(name_long = name, external_version = ver)
2092 if template is None:
2093 gmGuiHelpers.gm_show_error (
2094 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
2095 aTitle = _('Printing medication list')
2096 )
2097 return False
2098
2099
2100 meds_list = gmFormWidgets.generate_form_from_template (
2101 parent = parent,
2102 template = template,
2103 edit = False
2104 )
2105 if meds_list is None:
2106 return False
2107
2108
2109 return gmFormWidgets.act_on_generated_forms (
2110 parent = parent,
2111 forms = [meds_list],
2112 jobtype = 'medication_list',
2113
2114 episode_name = gmMedication.DEFAULT_MEDICATION_HISTORY_EPISODE,
2115 progress_note = _('generated medication list document'),
2116 review_copy_as_normal = True
2117 )
2118
2119
2148
2150
2151 if parent is None:
2152 parent = wx.GetApp().GetTopWindow()
2153
2154 dbcfg = gmCfg.cCfgSQL()
2155 option = u'form_templates.prescription'
2156 template_name = dbcfg.get2 (
2157 option = option,
2158 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
2159 bias = 'user'
2160 )
2161
2162 if template_name is None:
2163 template = configure_prescription_template(parent = parent)
2164 if template is None:
2165 gmGuiHelpers.gm_show_error (
2166 aMessage = _('There is no prescription template configured.'),
2167 aTitle = _('Printing prescription')
2168 )
2169 return None
2170 return template
2171
2172 try:
2173 name, ver = template_name.split(u' - ')
2174 except:
2175 _log.exception('problem splitting prescription template name [%s]', template_name)
2176 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading prescription template.'), beep = True)
2177 return False
2178 template = gmForms.get_form_template(name_long = name, external_version = ver)
2179 if template is None:
2180 gmGuiHelpers.gm_show_error (
2181 aMessage = _('Cannot load prescription template [%s - %s]') % (name, ver),
2182 aTitle = _('Printing prescription')
2183 )
2184 return None
2185 return template
2186
2213
2214
2242
2243
2245
2246 if len(prescribed_drugs) == 0:
2247 return
2248
2249 curr_brands = [ i['pk_brand'] for i in emr.get_current_substance_intakes() if i['pk_brand'] is not None ]
2250 new_drugs = []
2251 for drug in prescribed_drugs:
2252 if drug['pk_brand'] not in curr_brands:
2253 new_drugs.append(drug)
2254
2255 if len(new_drugs) == 0:
2256 return
2257
2258 if parent is None:
2259 parent = wx.GetApp().GetTopWindow()
2260
2261 dlg = gmListWidgets.cItemPickerDlg (
2262 parent,
2263 -1,
2264 msg = _(
2265 'These brands have been prescribed but are not listed\n'
2266 'in the current medication list of this patient.\n'
2267 '\n'
2268 'Please select those you want added to the medication list.'
2269 )
2270 )
2271 dlg.set_columns (
2272 columns = [_('Newly prescribed drugs')],
2273 columns_right = [_('Add to medication list')]
2274 )
2275 choices = [ (u'%s %s (%s)' % (d['brand'], d['preparation'], u'; '.join(d['components']))) for d in new_drugs ]
2276 dlg.set_choices (
2277 choices = choices,
2278 data = new_drugs
2279 )
2280 dlg.ShowModal()
2281 drugs2add = dlg.get_picks()
2282 dlg.Destroy()
2283
2284 if drugs2add is None:
2285 return
2286
2287 if len(drugs2add) == 0:
2288 return
2289
2290 for drug in drugs2add:
2291
2292 intake = emr.add_substance_intake (
2293 pk_component = drug['pk_components'][0],
2294 episode = emr.add_episode(episode_name = gmMedication.DEFAULT_MEDICATION_HISTORY_EPISODE)['pk_episode'],
2295 )
2296 if intake is None:
2297 continue
2298 intake['intake_is_approved_of'] = True
2299 intake.save()
2300
2301 return
2302
2304 """A grid class for displaying current substance intake.
2305
2306 - does NOT listen to the currently active patient
2307 - thereby it can display any patient at any time
2308 """
2310
2311 wx.grid.Grid.__init__(self, *args, **kwargs)
2312
2313 self.__patient = None
2314 self.__row_data = {}
2315 self.__prev_row = None
2316 self.__prev_tooltip_row = None
2317 self.__prev_cell_0 = None
2318 self.__grouping_mode = u'issue'
2319 self.__filter_show_unapproved = True
2320 self.__filter_show_inactive = True
2321
2322 self.__grouping2col_labels = {
2323 u'issue': [
2324 _('Health issue'),
2325 _('Substance'),
2326 _('Strength'),
2327 _('Schedule'),
2328 _('Started'),
2329 _('Duration / Until'),
2330 _('Brand'),
2331 _('Advice')
2332 ],
2333 u'brand': [
2334 _('Brand'),
2335 _('Schedule'),
2336 _('Substance'),
2337 _('Strength'),
2338 _('Started'),
2339 _('Duration / Until'),
2340 _('Health issue'),
2341 _('Advice')
2342 ],
2343 u'episode': [
2344 _('Episode'),
2345 _('Substance'),
2346 _('Strength'),
2347 _('Schedule'),
2348 _('Started'),
2349 _('Duration / Until'),
2350 _('Brand'),
2351 _('Advice')
2352 ]
2353 }
2354
2355 self.__grouping2order_by_clauses = {
2356 u'issue': u'pk_health_issue nulls first, substance, started',
2357 u'episode': u'pk_health_issue nulls first, episode, substance, started',
2358 u'brand': u'brand nulls last, substance, started'
2359 }
2360
2361 self.__init_ui()
2362 self.__register_events()
2363
2364
2365
2367
2368 sel_block_top_left = self.GetSelectionBlockTopLeft()
2369 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
2370 sel_cols = self.GetSelectedCols()
2371 sel_rows = self.GetSelectedRows()
2372
2373 selected_cells = []
2374
2375
2376 selected_cells += self.GetSelectedCells()
2377
2378
2379 selected_cells += list (
2380 (row, col)
2381 for row in sel_rows
2382 for col in xrange(self.GetNumberCols())
2383 )
2384
2385
2386 selected_cells += list (
2387 (row, col)
2388 for row in xrange(self.GetNumberRows())
2389 for col in sel_cols
2390 )
2391
2392
2393 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
2394 selected_cells += [
2395 (row, col)
2396 for row in xrange(top_left[0], bottom_right[0] + 1)
2397 for col in xrange(top_left[1], bottom_right[1] + 1)
2398 ]
2399
2400 return set(selected_cells)
2401
2403 rows = {}
2404
2405 for row, col in self.get_selected_cells():
2406 rows[row] = True
2407
2408 return rows.keys()
2409
2412
2414
2415 self.empty_grid()
2416
2417 if self.__patient is None:
2418 return
2419
2420 emr = self.__patient.get_emr()
2421 meds = emr.get_current_substance_intakes (
2422 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
2423 include_unapproved = self.__filter_show_unapproved,
2424 include_inactive = self.__filter_show_inactive
2425 )
2426 if not meds:
2427 return
2428
2429 self.BeginBatch()
2430
2431
2432 labels = self.__grouping2col_labels[self.__grouping_mode]
2433 if self.__filter_show_unapproved:
2434 self.AppendCols(numCols = len(labels) + 1)
2435 else:
2436 self.AppendCols(numCols = len(labels))
2437 for col_idx in range(len(labels)):
2438 self.SetColLabelValue(col_idx, labels[col_idx])
2439 if self.__filter_show_unapproved:
2440 self.SetColLabelValue(len(labels), u'OK?')
2441 self.SetColSize(len(labels), 40)
2442
2443 self.AppendRows(numRows = len(meds))
2444
2445
2446 for row_idx in range(len(meds)):
2447 med = meds[row_idx]
2448 self.__row_data[row_idx] = med
2449
2450 if med['is_currently_active'] is True:
2451 atcs = []
2452 if med['atc_substance'] is not None:
2453 atcs.append(med['atc_substance'])
2454
2455
2456
2457 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],))
2458 if allg not in [None, False]:
2459 attr = self.GetOrCreateCellAttr(row_idx, 0)
2460 if allg['type'] == u'allergy':
2461 attr.SetTextColour('red')
2462 else:
2463
2464
2465
2466 attr.SetTextColour('magenta')
2467 self.SetRowAttr(row_idx, attr)
2468 else:
2469 attr = self.GetOrCreateCellAttr(row_idx, 0)
2470 attr.SetTextColour('grey')
2471 self.SetRowAttr(row_idx, attr)
2472
2473 if self.__grouping_mode == u'episode':
2474 if med['pk_episode'] is None:
2475 self.__prev_cell_0 = None
2476 epi = gmTools.u_diameter
2477 else:
2478 if self.__prev_cell_0 == med['episode']:
2479 epi = u''
2480 else:
2481 self.__prev_cell_0 = med['episode']
2482 epi = gmTools.coalesce(med['episode'], u'')
2483 self.SetCellValue(row_idx, 0, gmTools.wrap(text = epi, width = 40))
2484
2485 self.SetCellValue(row_idx, 1, med['substance'])
2486 self.SetCellValue(row_idx, 2, u'%s %s' % (med['amount'], med['unit']))
2487 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
2488 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
2489
2490 if med['is_long_term']:
2491 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
2492 else:
2493 if med['discontinued'] is None:
2494 if med['duration'] is None:
2495 self.SetCellValue(row_idx, 5, u'')
2496 else:
2497 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
2498 else:
2499 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
2500
2501 if med['pk_brand'] is None:
2502 brand = u'%s (%s)' % (gmTools.u_diameter, med['preparation'])
2503 else:
2504 if med['fake_brand']:
2505 brand = u'%s (%s)' % (
2506 gmTools.coalesce(med['brand'], u'', _('%s <fake>')),
2507 med['preparation']
2508 )
2509 else:
2510 brand = u'%s (%s)' % (
2511 gmTools.coalesce(med['brand'], u''),
2512 med['preparation']
2513 )
2514 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35))
2515
2516 elif self.__grouping_mode == u'issue':
2517 if med['pk_health_issue'] is None:
2518 self.__prev_cell_0 = None
2519 issue = u'%s%s' % (
2520 gmTools.u_diameter,
2521 gmTools.coalesce(med['episode'], u'', u' (%s)')
2522 )
2523 else:
2524 if self.__prev_cell_0 == med['health_issue']:
2525 issue = u''
2526 else:
2527 self.__prev_cell_0 = med['health_issue']
2528 issue = med['health_issue']
2529 self.SetCellValue(row_idx, 0, gmTools.wrap(text = issue, width = 40))
2530
2531 self.SetCellValue(row_idx, 1, med['substance'])
2532 self.SetCellValue(row_idx, 2, u'%s %s' % (med['amount'], med['unit']))
2533 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
2534 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
2535
2536 if med['is_long_term']:
2537 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
2538 else:
2539 if med['discontinued'] is None:
2540 if med['duration'] is None:
2541 self.SetCellValue(row_idx, 5, u'')
2542 else:
2543 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
2544 else:
2545 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
2546
2547 if med['pk_brand'] is None:
2548 brand = u'%s (%s)' % (gmTools.u_diameter, med['preparation'])
2549 else:
2550 if med['fake_brand']:
2551 brand = u'%s (%s)' % (
2552 gmTools.coalesce(med['brand'], u'', _('%s <fake>')),
2553 med['preparation']
2554 )
2555 else:
2556 brand = u'%s (%s)' % (
2557 gmTools.coalesce(med['brand'], u''),
2558 med['preparation']
2559 )
2560 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35))
2561
2562 elif self.__grouping_mode == u'brand':
2563
2564 if med['pk_brand'] is None:
2565 self.__prev_cell_0 = None
2566 brand = u'%s (%s)' % (
2567 gmTools.u_diameter,
2568 med['preparation']
2569 )
2570 else:
2571 if self.__prev_cell_0 == med['brand']:
2572 brand = u''
2573 else:
2574 self.__prev_cell_0 = med['brand']
2575 if med['fake_brand']:
2576 brand = u'%s (%s)' % (
2577 gmTools.coalesce(med['brand'], u'', _('%s <fake>')),
2578 med['preparation']
2579 )
2580 else:
2581 brand = u'%s (%s)' % (
2582 gmTools.coalesce(med['brand'], u''),
2583 med['preparation']
2584 )
2585 self.SetCellValue(row_idx, 0, gmTools.wrap(text = brand, width = 35))
2586
2587 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
2588 self.SetCellValue(row_idx, 2, med['substance'])
2589 self.SetCellValue(row_idx, 3, u'%s %s' % (med['amount'], med['unit']))
2590 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
2591
2592 if med['is_long_term']:
2593 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
2594 else:
2595 if med['discontinued'] is None:
2596 if med['duration'] is None:
2597 self.SetCellValue(row_idx, 5, u'')
2598 else:
2599 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
2600 else:
2601 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
2602
2603 if med['pk_health_issue'] is None:
2604 issue = u'%s%s' % (
2605 gmTools.u_diameter,
2606 gmTools.coalesce(med['episode'], u'', u' (%s)')
2607 )
2608 else:
2609 issue = gmTools.coalesce(med['health_issue'], u'')
2610 self.SetCellValue(row_idx, 6, gmTools.wrap(text = issue, width = 40))
2611
2612 else:
2613 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
2614
2615 if med['notes'] is not None:
2616 self.SetCellValue(row_idx, 7, gmTools.wrap(text = med['notes'], width = 50))
2617
2618 if self.__filter_show_unapproved:
2619 self.SetCellValue (
2620 row_idx,
2621 len(labels),
2622 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
2623 )
2624
2625
2626
2627 self.AutoSize()
2628 self.EndBatch()
2629
2631 self.BeginBatch()
2632 self.ClearGrid()
2633
2634
2635 if self.GetNumberRows() > 0:
2636 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
2637 if self.GetNumberCols() > 0:
2638 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
2639 self.EndBatch()
2640 self.__row_data = {}
2641 self.__prev_cell_0 = None
2642
2644
2645 if len(self.__row_data) == 0:
2646 return
2647
2648 sel_rows = self.get_selected_rows()
2649 if len(sel_rows) != 1:
2650 return
2651
2652 drug_db = get_drug_database()
2653 if drug_db is None:
2654 return
2655
2656 intake = self.get_selected_data()[0]
2657 if intake['brand'] is None:
2658 drug_db.show_info_on_substance(substance_intake = intake)
2659 else:
2660 drug_db.show_info_on_drug(substance_intake = intake)
2661
2669
2672
2682
2688
2702
2705
2719
2733
2749
2753
2856
2857
2858
2860 self.CreateGrid(0, 1)
2861 self.EnableEditing(0)
2862 self.EnableDragGridSize(1)
2863 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
2864
2865 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
2866
2867 self.SetRowLabelSize(0)
2868 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
2869
2870
2871
2873 return self.__patient
2874
2878
2879 patient = property(_get_patient, _set_patient)
2880
2882 return self.__grouping_mode
2883
2887
2888 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
2889
2891 return self.__filter_show_unapproved
2892
2896
2897 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
2898
2900 return self.__filter_show_inactive
2901
2905
2906 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
2907
2908
2909
2911
2912 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
2913
2914
2915
2916
2917 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
2918
2920 """Calculate where the mouse is and set the tooltip dynamically."""
2921
2922
2923
2924 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938 row, col = self.XYToCell(x, y)
2939
2940 if row == self.__prev_tooltip_row:
2941 return
2942
2943 self.__prev_tooltip_row = row
2944
2945 try:
2946 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
2947 except KeyError:
2948 pass
2949
2954
2955 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
2956
2957 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
2958
2959 """Panel holding a grid with current substances. Used as notebook page."""
2960
2967
2968
2969
2971 """Populate cells with data from model."""
2972 pat = gmPerson.gmCurrentPatient()
2973 if pat.connected:
2974 self._grid_substances.patient = pat
2975 self.__refresh_gfr(pat)
2976 else:
2977 self._grid_substances.patient = None
2978 self.__clear_gfr()
2979 return True
2980
2982 gfr = patient.emr.get_most_recent_results(loinc = gmLOINC.LOINC_gfr_quantity, no_of_results = 1)
2983 if gfr is None:
2984 calc = gmClinicalCalculator.cClinicalCalculator()
2985 calc.patient = patient
2986 gfr = calc.eGFR
2987 if gfr.numeric_value is None:
2988 msg = _('GFR: ?')
2989 tt = gfr.message
2990 else:
2991 msg = _('eGFR: %.1f (%s)') % (
2992 gfr.numeric_value,
2993 gmDateTime.pydt_strftime (
2994 gfr.date_valid,
2995 format = '%b %Y'
2996 )
2997 )
2998 tt = gfr.format (
2999 left_margin = 0,
3000 width = 50,
3001 eol = u'\n',
3002 with_formula = True,
3003 with_warnings = True,
3004 with_variables = False,
3005 with_sub_results = True,
3006 return_list = False
3007 )
3008 else:
3009 msg = u'%s: %s %s (%s)\n' % (
3010 gfr['unified_abbrev'],
3011 gfr['unified_val'],
3012 gmTools.coalesce(gfr['abnormality_indicator'], u'', u' (%s)'),
3013 gmDateTime.pydt_strftime (
3014 gfr['clin_when'],
3015 format = '%b %Y'
3016 )
3017 )
3018 tt = _('GFR reported by path lab')
3019
3020 self._LBL_gfr.SetLabel(msg)
3021 self._LBL_gfr.SetToolTipString(tt)
3022 self._LBL_gfr.Refresh()
3023 self.Layout()
3024
3026 self._LBL_gfr.SetLabel(_('GFR: ?'))
3027 self._LBL_gfr.Refresh()
3028 self.Layout()
3029
3030
3031
3033 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
3034 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._on_post_patient_selection)
3035 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
3036
3037
3038
3040 wx.CallAfter(self.__on_pre_patient_selection)
3041
3043 self._grid_substances.patient = None
3044
3046 wx.CallAfter(self.__on_post_patient_selection)
3047
3049 self._schedule_data_reget()
3050
3053
3056
3059
3062
3065
3068
3071
3074
3077
3080
3083
3086
3089
3092
3095
3098
3099
3100
3101 if __name__ == '__main__':
3102
3103 if len(sys.argv) < 2:
3104 sys.exit()
3105
3106 if sys.argv[1] != 'test':
3107 sys.exit()
3108
3109 from Gnumed.business import gmPersonSearch
3110
3111 pat = gmPersonSearch.ask_for_patient()
3112 if pat is None:
3113 sys.exit()
3114 gmPerson.set_active_patient(patient = pat)
3115
3116
3117 app = wx.PyWidgetTester(size = (600, 600))
3118
3119
3120
3121 manage_substance_intakes()
3122
3123
3124