| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed medication/substances handling widgets.
2 """
3 #================================================================
4 __version__ = "$Revision: 1.33 $"
5 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
6
7 import logging, sys, os.path, webbrowser, decimal
8
9
10 import wx, wx.grid
11
12
13 if __name__ == '__main__':
14 sys.path.insert(0, '../../')
15 from Gnumed.pycommon import gmDispatcher, gmCfg, gmShellAPI, gmTools, gmDateTime
16 from Gnumed.pycommon import gmMatchProvider, gmI18N, gmPrinting, gmCfg2
17 from Gnumed.business import gmPerson, gmATC, gmSurgery, gmMedication, gmForms
18 from Gnumed.wxpython import gmGuiHelpers, gmRegetMixin, gmAuthWidgets, gmEditArea, gmMacro
19 from Gnumed.wxpython import gmCfgWidgets, gmListWidgets, gmPhraseWheel, gmFormWidgets
20 from Gnumed.wxpython import gmAllergyWidgets
21
22
23 _log = logging.getLogger('gm.ui')
24 _log.info(__version__)
25
26 #============================================================
27 # generic drug database access
28 #============================================================
30 gmCfgWidgets.configure_string_from_list_option (
31 parent = parent,
32 message = _(
33 '\n'
34 'Please select the default drug data source from the list below.\n'
35 '\n'
36 'Note that to actually use it you need to have the database installed, too.'
37 ),
38 option = 'external.drug_data.default_source',
39 bias = 'user',
40 default_value = None,
41 choices = gmMedication.drug_data_source_interfaces.keys(),
42 columns = [_('Drug data source')],
43 data = gmMedication.drug_data_source_interfaces.keys(),
44 caption = _('Configuring default drug data source')
45 )
46 #============================================================
48 dbcfg = gmCfg.cCfgSQL()
49
50 default_db = dbcfg.get2 (
51 option = 'external.drug_data.default_source',
52 workplace = gmSurgery.gmCurrentPractice().active_workplace,
53 bias = 'workplace'
54 )
55
56 if default_db is None:
57 gmDispatcher.send('statustext', msg = _('No default drug database configured.'), beep = True)
58 configure_drug_data_source(parent = parent)
59 default_db = dbcfg.get2 (
60 option = 'external.drug_data.default_source',
61 workplace = gmSurgery.gmCurrentPractice().active_workplace,
62 bias = 'workplace'
63 )
64 if default_db is None:
65 gmGuiHelpers.gm_show_error (
66 aMessage = _('There is no default drug database configured.'),
67 aTitle = _('Jumping to drug database')
68 )
69 return None
70
71 try:
72 drug_db = gmMedication.drug_data_source_interfaces[default_db]()
73 except KeyError:
74 _log.error('faulty default drug data source configuration: %s', default_db)
75 configure_drug_data_source(parent = parent)
76 default_db = dbcfg.get2 (
77 option = 'external.drug_data.default_source',
78 workplace = gmSurgery.gmCurrentPractice().active_workplace,
79 bias = 'workplace'
80 )
81 if default_db is None:
82 return None
83
84 pat = gmPerson.gmCurrentPatient()
85 if pat.connected:
86 drug_db.patient = pat
87
88 return drug_db
89 #============================================================
91 dbcfg = gmCfg.cCfgSQL()
92 drug_db = get_drug_database()
93 if drug_db is None:
94 return
95 drug_db.switch_to_frontend(blocking = False)
96
97 #============================================================
99
100 dbcfg = gmCfg.cCfgSQL()
101
102 ifap_cmd = dbcfg.get2 (
103 option = 'external.ifap-win.shell_command',
104 workplace = gmSurgery.gmCurrentPractice().active_workplace,
105 bias = 'workplace',
106 default = 'wine "C:\Ifapwin\WIAMDB.EXE"'
107 )
108 found, binary = gmShellAPI.detect_external_binary(ifap_cmd)
109 if not found:
110 gmDispatcher.send('statustext', msg = _('Cannot call IFAP via [%s].') % ifap_cmd)
111 return False
112 ifap_cmd = binary
113
114 if import_drugs:
115 transfer_file = os.path.expanduser(dbcfg.get2 (
116 option = 'external.ifap-win.transfer_file',
117 workplace = gmSurgery.gmCurrentPractice().active_workplace,
118 bias = 'workplace',
119 default = '~/.wine/drive_c/Ifapwin/ifap2gnumed.csv'
120 ))
121 # file must exist for Ifap to write into it
122 try:
123 f = open(transfer_file, 'w+b').close()
124 except IOError:
125 _log.exception('Cannot create IFAP <-> GNUmed transfer file [%s]', transfer_file)
126 gmDispatcher.send('statustext', msg = _('Cannot create IFAP <-> GNUmed transfer file [%s].') % transfer_file)
127 return False
128
129 wx.BeginBusyCursor()
130 gmShellAPI.run_command_in_shell(command = ifap_cmd, blocking = import_drugs)
131 wx.EndBusyCursor()
132
133 if import_drugs:
134 # COMMENT: this file must exist PRIOR to invoking IFAP
135 # COMMENT: or else IFAP will not write data into it ...
136 try:
137 csv_file = open(transfer_file, 'rb') # FIXME: encoding
138 except:
139 _log.exception('cannot access [%s]', fname)
140 csv_file = None
141
142 if csv_file is not None:
143 import csv
144 csv_lines = csv.DictReader (
145 csv_file,
146 fieldnames = u'PZN Handelsname Form Abpackungsmenge Einheit Preis1 Hersteller Preis2 rezeptpflichtig Festbetrag Packungszahl Packungsgr\xf6\xdfe'.split(),
147 delimiter = ';'
148 )
149 pat = gmPerson.gmCurrentPatient()
150 emr = pat.get_emr()
151 # dummy episode for now
152 epi = emr.add_episode(episode_name = _('Current medication'))
153 for line in csv_lines:
154 narr = u'%sx %s %s %s (\u2258 %s %s) von %s (%s)' % (
155 line['Packungszahl'].strip(),
156 line['Handelsname'].strip(),
157 line['Form'].strip(),
158 line[u'Packungsgr\xf6\xdfe'].strip(),
159 line['Abpackungsmenge'].strip(),
160 line['Einheit'].strip(),
161 line['Hersteller'].strip(),
162 line['PZN'].strip()
163 )
164 emr.add_clin_narrative(note = narr, soap_cat = 's', episode = epi)
165 csv_file.close()
166
167 return True
168
169 #============================================================
170 # ATC related widgets
171 #============================================================
172
174
175 if parent is None:
176 parent = wx.GetApp().GetTopWindow()
177 #------------------------------------------------------------
178 def refresh(lctrl):
179 atcs = gmATC.get_reference_atcs()
180
181 items = [ [
182 a['atc'],
183 a['term'],
184 u'%s' % gmTools.coalesce(a['ddd'], u''),
185 gmTools.coalesce(a['unit'], u''),
186 gmTools.coalesce(a['administrative_route'], u''),
187 gmTools.coalesce(a['comment'], u''),
188 a['version'],
189 a['lang']
190 ] for a in atcs ]
191 lctrl.set_string_items(items)
192 lctrl.set_data(atcs)
193 #------------------------------------------------------------
194 gmListWidgets.get_choices_from_list (
195 parent = parent,
196 msg = _('\nThe ATC codes as known to GNUmed.\n'),
197 caption = _('Showing ATC codes.'),
198 columns = [ u'ATC', _('Term'), u'DDD', _('Unit'), _(u'Route'), _('Comment'), _('Version'), _('Language') ],
199 single_selection = True,
200 refresh_callback = refresh
201 )
202
203 #============================================================
205
206 dlg = wx.FileDialog (
207 parent = None,
208 message = _('Choose an ATC import config file'),
209 defaultDir = os.path.expanduser(os.path.join('~', 'gnumed')),
210 defaultFile = '',
211 wildcard = "%s (*.conf)|*.conf|%s (*)|*" % (_('config files'), _('all files')),
212 style = wx.OPEN | wx.HIDE_READONLY | wx.FILE_MUST_EXIST
213 )
214
215 result = dlg.ShowModal()
216 if result == wx.ID_CANCEL:
217 return
218
219 cfg_file = dlg.GetPath()
220 dlg.Destroy()
221
222 conn = gmAuthWidgets.get_dbowner_connection(procedure = _('importing ATC reference data'))
223 if conn is None:
224 return False
225
226 wx.BeginBusyCursor()
227
228 if gmATC.atc_import(cfg_fname = cfg_file, conn = conn):
229 gmDispatcher.send(signal = 'statustext', msg = _('Successfully imported ATC reference data.'))
230 else:
231 gmDispatcher.send(signal = 'statustext', msg = _('Importing ATC reference data failed.'), beep = True)
232
233 wx.EndBusyCursor()
234 return True
235
236 #============================================================
237
239
241
242 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
243
244 query = u"""
245
246 SELECT DISTINCT ON (label)
247 atc_code,
248 label
249 FROM (
250
251 SELECT
252 code as atc_code,
253 (code || ': ' || term || coalesce(' (' || ddd || unit || ')', ''))
254 AS label
255 FROM ref.atc
256 WHERE
257 term %(fragment_condition)s
258 OR
259 code %(fragment_condition)s
260
261 UNION ALL
262
263 SELECT
264 atc_code,
265 (atc_code || ': ' || description)
266 AS label
267 FROM ref.consumable_substance
268 WHERE
269 description %(fragment_condition)s
270 OR
271 atc_code %(fragment_condition)s
272
273 UNION ALL
274
275 SELECT
276 atc_code,
277 (atc_code || ': ' || description || ' (' || preparation || ')')
278 AS label
279 FROM ref.branded_drug
280 WHERE
281 description %(fragment_condition)s
282 OR
283 atc_code %(fragment_condition)s
284
285 -- it would be nice to be able to include clin.vacc_indication but that's hard to do in SQL
286
287 ) AS candidates
288 WHERE atc_code IS NOT NULL
289 ORDER BY label
290 LIMIT 50"""
291
292 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
293 mp.setThresholds(1, 2, 4)
294 # mp.word_separators = '[ \t=+&:@]+'
295 self.SetToolTipString(_('Select an ATC (Anatomical-Therapeutic-Chemical) code.'))
296 self.matcher = mp
297 self.selection_only = True
298
299 #============================================================
300 # consumable substances widgets
301 #------------------------------------------------------------
303
304 if parent is None:
305 parent = wx.GetApp().GetTopWindow()
306 #------------------------------------------------------------
307 def add_from_db(substance):
308 drug_db = get_drug_database(parent = parent)
309 if drug_db is None:
310 return False
311 drug_db.import_drugs()
312 return True
313 #------------------------------------------------------------
314 def edit(substance=None):
315 return edit_consumable_substance(parent = parent, substance = substance, single_entry = (substance is not None))
316 #------------------------------------------------------------
317 def delete(substance):
318 if substance.is_in_use_by_patients:
319 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete this substance. It is in use.'), beep = True)
320 return False
321
322 return gmMedication.delete_consumable_substance(substance = substance['pk'])
323 #------------------------------------------------------------
324 def refresh(lctrl):
325 substs = gmMedication.get_consumable_substances(order_by = 'description')
326 items = [ [
327 s['description'],
328 s['amount'],
329 s['unit'],
330 gmTools.coalesce(s['atc_code'], u''),
331 s['pk']
332 ] for s in substs ]
333 lctrl.set_string_items(items)
334 lctrl.set_data(substs)
335 #------------------------------------------------------------
336 msg = _('\nThese are the consumable substances registered with GNUmed.\n')
337
338 gmListWidgets.get_choices_from_list (
339 parent = parent,
340 msg = msg,
341 caption = _('Showing consumable substances.'),
342 columns = [_('Substance'), _('Amount'), _('Unit'), 'ATC', u'#'],
343 single_selection = True,
344 new_callback = edit,
345 edit_callback = edit,
346 delete_callback = delete,
347 refresh_callback = refresh,
348 left_extra_button = (_('Import'), _('Import consumable substances from a drug database.'), add_from_db)
349 )
350
351 #------------------------------------------------------------
353
354 if substance is not None:
355 if substance.is_in_use_by_patients:
356 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit this substance. It is in use.'), beep = True)
357 return False
358
359 ea = cConsumableSubstanceEAPnl(parent = parent, id = -1)
360 ea.data = substance
361 ea.mode = gmTools.coalesce(substance, 'new', 'edit')
362 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
363 dlg.SetTitle(gmTools.coalesce(substance, _('Adding new consumable substance'), _('Editing consumable substance')))
364 if dlg.ShowModal() == wx.ID_OK:
365 dlg.Destroy()
366 return True
367 dlg.Destroy()
368 return False
369
370 #============================================================
371 from Gnumed.wxGladeWidgets import wxgConsumableSubstanceEAPnl
372
373 -class cConsumableSubstanceEAPnl(wxgConsumableSubstanceEAPnl.wxgConsumableSubstanceEAPnl, gmEditArea.cGenericEditAreaMixin):
374
376
377 try:
378 data = kwargs['substance']
379 del kwargs['substance']
380 except KeyError:
381 data = None
382
383 wxgConsumableSubstanceEAPnl.wxgConsumableSubstanceEAPnl.__init__(self, *args, **kwargs)
384 gmEditArea.cGenericEditAreaMixin.__init__(self)
385
386 # Code using this mixin should set mode and data
387 # after instantiating the class:
388 self.mode = 'new'
389 self.data = data
390 if data is not None:
391 self.mode = 'edit'
392
393 # self.__init_ui()
394 #----------------------------------------------------------------
395 # def __init_ui(self):
396 # self._PRW_atc.selection_only = False
397 #----------------------------------------------------------------
398 # generic Edit Area mixin API
399 #----------------------------------------------------------------
401
402 validity = True
403
404 if self._TCTRL_substance.GetValue().strip() == u'':
405 validity = False
406 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = False)
407 self._TCTRL_substance.SetFocus()
408 else:
409 self.display_tctrl_as_valid(tctrl = self._TCTRL_substance, valid = True)
410
411 try:
412 decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.'))
413 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
414 except (TypeError, decimal.InvalidOperation):
415 validity = False
416 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
417 self._TCTRL_amount.SetFocus()
418
419 if self._PRW_unit.GetValue().strip() == u'':
420 validity = False
421 self._PRW_unit.display_as_valid(valid = False)
422 self._TCTRL_substance.SetFocus()
423 else:
424 self._PRW_unit.display_as_valid(valid = True)
425
426 if validity is False:
427 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. Missing essential input.'))
428
429 return validity
430 #----------------------------------------------------------------
432 subst = gmMedication.create_consumable_substance (
433 substance = self._TCTRL_substance.GetValue().strip(),
434 atc = self._PRW_atc.GetData(),
435 amount = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.')),
436 unit = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None))
437 )
438 success, data = subst.save()
439 if not success:
440 err, msg = data
441 _log.error(err)
442 _log.error(msg)
443 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
444 return False
445
446 self.data = subst
447 return True
448 #----------------------------------------------------------------
450 self.data['description'] = self._TCTRL_substance.GetValue().strip()
451 self.data['atc_code'] = self._PRW_atc.GetData()
452 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', '.'))
453 self.data['unit'] = gmTools.coalesce(self._PRW_unit.GetData(), self._PRW_unit.GetValue().strip(), function_initial = ('strip', None))
454 success, data = self.data.save()
455
456 if not success:
457 err, msg = data
458 _log.error(err)
459 _log.error(msg)
460 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save consumable substance. %s') % msg, beep = True)
461 return False
462
463 return True
464 #----------------------------------------------------------------
466 self._TCTRL_substance.SetValue(u'')
467 self._TCTRL_amount.SetValue(u'')
468 self._PRW_unit.SetText(u'', None)
469 self._PRW_atc.SetText(u'', None)
470
471 self._TCTRL_substance.SetFocus()
472 #----------------------------------------------------------------
474 self._TCTRL_substance.SetValue(self.data['description'])
475 self._TCTRL_amount.SetValue(u'%s' % self.data['amount'])
476 self._PRW_unit.SetText(self.data['unit'], self.data['unit'])
477 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc_code'], u''), self.data['atc_code'])
478
479 self._TCTRL_substance.SetFocus()
480 #----------------------------------------------------------------
483
484 #============================================================
485 # drug component widgets
486 #------------------------------------------------------------
488
489 if parent is None:
490 parent = wx.GetApp().GetTopWindow()
491
492 #------------------------------------------------------------
493 def edit(component=None):
494 substance = gmMedication.cConsumableSubstance(aPK_obj = component['pk_consumable_substance'])
495 return edit_consumable_substance(parent = parent, substance = substance, single_entry = True)
496 #------------------------------------------------------------
497 def delete(component):
498 if component.is_in_use_by_patients:
499 gmDispatcher.send(signal = 'statustext', msg = _('Cannot remove this component from the drug. It is in use.'), beep = True)
500 return False
501
502 return component.containing_drug.remove_component(substance = component['pk_component'])
503 #------------------------------------------------------------
504 def refresh(lctrl):
505 comps = gmMedication.get_drug_components()
506 items = [ [
507 u'%s%s' % (c['brand'], gmTools.coalesce(c['atc_brand'], u'', u' [%s]')),
508 u'%s%s' % (c['substance'], gmTools.coalesce(c['atc_substance'], u'', u' [%s]')),
509 u'%s%s' % (c['amount'], c['unit']),
510 c['preparation'],
511 gmTools.coalesce(c['external_code_brand'], u'', u'%%s [%s]' % c['external_code_type_brand']),
512 c['pk_component']
513 ] for c in comps ]
514 lctrl.set_string_items(items)
515 lctrl.set_data(comps)
516 #------------------------------------------------------------
517 msg = _('\nThese are the components in the drug brands known to GNUmed.\n')
518
519 gmListWidgets.get_choices_from_list (
520 parent = parent,
521 msg = msg,
522 caption = _('Showing drug brand components.'),
523 columns = [_('Brand'), _('Substance'), _('Strength'), _('Preparation'), _('Code'), u'#'],
524 single_selection = True,
525 #new_callback = edit,
526 edit_callback = edit,
527 delete_callback = delete,
528 refresh_callback = refresh
529 )
530
531 #------------------------------------------------------------
533 ea = cDrugComponentEAPnl(parent = parent, id = -1)
534 ea.data = drug_component
535 ea.mode = gmTools.coalesce(drug_component, 'new', 'edit')
536 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
537 dlg.SetTitle(gmTools.coalesce(drug_component, _('Adding new drug component'), _('Editing drug component')))
538 if dlg.ShowModal() == wx.ID_OK:
539 dlg.Destroy()
540 return True
541 dlg.Destroy()
542 return False
543
544 #============================================================
545 from Gnumed.wxGladeWidgets import wxgDrugComponentEAPnl
546
547 -class cDrugComponentEAPnl(wxgDrugComponentEAPnl.wxgDrugComponentEAPnl, gmEditArea.cGenericEditAreaMixin):
548
550
551 try:
552 data = kwargs['component']
553 del kwargs['component']
554 except KeyError:
555 data = None
556
557 wxgDrugComponentEAPnl.wxgDrugComponentEAPnl.__init__(self, *args, **kwargs)
558 gmEditArea.cGenericEditAreaMixin.__init__(self)
559
560 # Code using this mixin should set mode and data
561 # after instantiating the class:
562 self.mode = 'new'
563 self.data = data
564 if data is not None:
565 self.mode = 'edit'
566
567 #self.__init_ui()
568 #----------------------------------------------------------------
569 # def __init_ui(self):
570 # # adjust phrasewheels etc
571 #----------------------------------------------------------------
572 # generic Edit Area mixin API
573 #----------------------------------------------------------------
575 if self.data is not None:
576 if self.data['is_in_use']:
577 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug component. It is in use.'), beep = True)
578 return False
579
580 validity = True
581
582 if self._PRW_substance.GetData() is None:
583 validity = False
584 self._PRW_substance.display_as_valid(False)
585 else:
586 self._PRW_substance.display_as_valid(True)
587
588 val = self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1)
589 try:
590 decimal.Decimal(val)
591 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = True)
592 except:
593 validity = False
594 self.display_tctrl_as_valid(tctrl = self._TCTRL_amount, valid = False)
595
596 if self._PRW_unit.GetValue().strip() == u'':
597 validity = False
598 self._PRW_unit.display_as_valid(False)
599 else:
600 self._PRW_unit.display_as_valid(True)
601
602 if validity is False:
603 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save drug component. Invalid or missing essential input.'))
604
605 return validity
606 #----------------------------------------------------------------
608 # save the data as a new instance
609 data = 1
610 data[''] = 1
611 data[''] = 1
612 # data.save()
613
614 # must be done very late or else the property access
615 # will refresh the display such that later field
616 # access will return empty values
617 # self.data = data
618 return False
619 return True
620 #----------------------------------------------------------------
622 self.data['pk_consumable_substance'] = self._PRW_substance.GetData()
623 self.data['amount'] = decimal.Decimal(self._TCTRL_amount.GetValue().strip().replace(',', u'.', 1))
624 self.data['unit'] = self._PRW_unit.GetValue().strip()
625 return self.data.save()
626 #----------------------------------------------------------------
628 self._TCTRL_brand.SetValue(u'')
629 self._TCTRL_components.SetValue(u'')
630 self._TCTRL_codes.SetValue(u'')
631 self._PRW_substance.SetText(u'', None)
632 self._TCTRL_amount.SetValue(u'')
633 self._PRW_unit.SetText(u'', None)
634
635 self._PRW_substance.SetFocus()
636 #----------------------------------------------------------------
638 self._TCTRL_brand.SetValue(u'%s (%s)' % (self.data['brand'], self.data['preparation']))
639 self._TCTRL_components.SetValue(u' / '.join(self.data.containing_drug['components']))
640 details = []
641 if self.data['atc_brand'] is not None:
642 details.append(u'ATC: %s' % self.data['atc_brand'])
643 if self.data['external_code_brand'] is not None:
644 details.append(u'%s: %s' % (self.data['external_code_type_brand'], self.data['external_code_brand']))
645 self._TCTRL_codes.SetValue(u'; '.join(details))
646
647 self._PRW_substance.SetText(self.data['substance'], self.data['pk_consumable_substance'])
648 self._TCTRL_amount.SetValue(u'%s' % self.data['amount'])
649 self._PRW_unit.SetText(self.data['unit'], self.data['unit'])
650
651 self._PRW_substance.SetFocus()
652 #----------------------------------------------------------------
662
663 #============================================================
665
667
668 mp = gmMedication.cDrugComponentMatchProvider()
669 mp.setThresholds(2, 3, 4)
670 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
671 self.SetToolTipString(_('A drug component with optional strength.'))
672 self.matcher = mp
673 self.selection_only = False
674 #============================================================
675 #============================================================
677
679
680 query = u"""
681 (
682 SELECT DISTINCT ON (preparation)
683 preparation as prep, preparation
684 FROM ref.branded_drug
685 WHERE preparation %(fragment_condition)s
686 ) UNION (
687 SELECT DISTINCT ON (preparation)
688 preparation as prep, preparation
689 FROM clin.substance_intake
690 WHERE preparation %(fragment_condition)s
691 )
692 ORDER BY prep
693 limit 30"""
694
695 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
696 mp.setThresholds(1, 2, 4)
697 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
698 self.SetToolTipString(_('The preparation (form) of the substance or brand.'))
699 self.matcher = mp
700 self.selection_only = False
701 #============================================================
703
705
706 mp = gmMedication.cSubstanceMatchProvider()
707 mp.setThresholds(1, 2, 4)
708 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
709 self.SetToolTipString(_('The substance with optional strength.'))
710 self.matcher = mp
711 self.selection_only = False
712 self.phrase_separators = None
713 #============================================================
714 # branded drugs widgets
715 #------------------------------------------------------------
717
718 if brand is not None:
719 if brand['is_in_use']:
720 gmGuiHelpers.gm_show_info (
721 aTitle = _('Managing components of a drug'),
722 aMessage = _(
723 'Cannot manage the components of the branded drug product\n'
724 '\n'
725 ' "%s" (%s)\n'
726 '\n'
727 'because it is currently taken by patients.\n'
728 ) % (brand['brand'], brand['preparation'])
729 )
730 return False
731 #--------------------------------------------------------
732 if parent is None:
733 parent = wx.GetApp().GetTopWindow()
734 #--------------------------------------------------------
735 if brand is None:
736 msg = _('Pick the substances which are components of this drug.')
737 right_col = _('Components of drug')
738 comp_substs = []
739 else:
740 right_col = u'%s (%s)' % (brand['brand'], brand['preparation'])
741 msg = _(
742 'Adjust the components of "%s"\n'
743 '\n'
744 'The drug must contain at least one component. Any given\n'
745 'substance can only be included once per drug.'
746 ) % right_col
747 comp_substs = [ c.substance for c in brand.components ]
748
749 substs = gmMedication.get_consumable_substances(order_by = 'description')
750 choices = [ u'%s %s%s' % (s['description'], s['amount'], s['unit']) for s in substs ]
751 picks = [ u'%s %s%s' % (c['description'], c['amount'], c['unit']) for c in comp_substs ]
752
753 picker = gmListWidgets.cItemPickerDlg (
754 parent,
755 -1,
756 title = _('Managing components of a drug ...'),
757 msg = msg
758 )
759 picker.set_columns(['Substances'], [right_col])
760 picker.set_choices(choices = choices, data = substs)
761 picker.set_picks(picks = picks, data = comp_substs)
762
763 btn_pressed = picker.ShowModal()
764 substs = picker.get_picks()
765 picker.Destroy()
766
767 if btn_pressed != wx.ID_OK:
768 return (False, None)
769
770 if brand is not None:
771 brand.set_substances_as_components(substances = substs)
772
773 return (True, substs)
774 #------------------------------------------------------------
776
777 if parent is None:
778 parent = wx.GetApp().GetTopWindow()
779 #------------------------------------------------------------
780 def add_from_db(brand):
781 drug_db = get_drug_database(parent = parent)
782 if drug_db is None:
783 return False
784 drug_db.import_drugs()
785 return True
786 #------------------------------------------------------------
787 def get_tooltip(brand=None):
788 tt = u'%s %s\n' % (brand['brand'], brand['preparation'])
789 tt += u'\n'
790 tt += u'%s%s%s\n' % (
791 gmTools.bool2subst(brand.is_vaccine, u'%s, ' % _('Vaccine'), u''),
792 u'%s, ' % gmTools.bool2subst(brand['is_in_use'], _('in use'), _('not in use')),
793 gmTools.bool2subst(brand['is_fake_brand'], _('fake'), u'')
794 )
795 tt += gmTools.coalesce(brand['atc'], u'', _('ATC: %s\n'))
796 tt += gmTools.coalesce(brand['external_code'], u'', u'%s: %%s\n' % brand['external_code_type'])
797 if brand['components'] is not None:
798 tt += u'- %s' % u'\n- '.join(brand['components'])
799 return tt
800 #------------------------------------------------------------
801 def edit(brand=None):
802 if brand.is_vaccine:
803 gmGuiHelpers.gm_show_info (
804 aTitle = _('Editing medication'),
805 aMessage = _(
806 'Cannot edit the medication\n'
807 '\n'
808 ' "%s" (%s)\n'
809 '\n'
810 'because it is a vaccine. Please edit it\n'
811 'from the vaccine management section !\n'
812 ) % (brand['brand'], brand['preparation'])
813 )
814 return False
815
816 return edit_branded_drug(parent = parent, branded_drug = brand, single_entry = True)
817 #------------------------------------------------------------
818 def delete(brand):
819 if brand.is_vaccine:
820 gmGuiHelpers.gm_show_info (
821 aTitle = _('Deleting medication'),
822 aMessage = _(
823 'Cannot delete the medication\n'
824 '\n'
825 ' "%s" (%s)\n'
826 '\n'
827 'because it is a vaccine. Please delete it\n'
828 'from the vaccine management section !\n'
829 ) % (brand['brand'], brand['preparation'])
830 )
831 return False
832 gmMedication.delete_branded_drug(brand = brand['pk_brand'])
833 return True
834 #------------------------------------------------------------
835 def new():
836 return edit_branded_drug(parent = parent, branded_drug = None, single_entry = False)
837 #------------------------------------------------------------
838 def refresh(lctrl):
839 drugs = gmMedication.get_branded_drugs()
840 items = [ [
841 u'%s%s' % (
842 d['brand'],
843 gmTools.bool2subst(d['is_fake_brand'], ' (%s)' % _('fake'), u'')
844 ),
845 d['preparation'],
846 gmTools.coalesce(d['atc'], u''),
847 gmTools.coalesce(d['components'], u''),
848 gmTools.coalesce(d['external_code'], u'', u'%%s [%s]' % d['external_code_type']),
849 d['pk_brand']
850 ] for d in drugs ]
851 lctrl.set_string_items(items)
852 lctrl.set_data(drugs)
853 #------------------------------------------------------------
854 msg = _('\nThese are the drug brands known to GNUmed.\n')
855
856 gmListWidgets.get_choices_from_list (
857 parent = parent,
858 msg = msg,
859 caption = _('Showing branded drugs.'),
860 columns = [_('Name'), _('Preparation'), _('ATC'), _('Components'), _('Code'), u'#'],
861 single_selection = True,
862 ignore_OK_button = ignore_OK_button,
863 refresh_callback = refresh,
864 new_callback = new,
865 edit_callback = edit,
866 delete_callback = delete,
867 list_tooltip_callback = get_tooltip,
868 left_extra_button = (_('Import'), _('Import substances and brands from a drug database.'), add_from_db)
869 #, middle_extra_button = (_('Clone'), _('Clone selected drug into a new entry for editing.'), clone_from_existing)
870 #, right_extra_button = (_('Reassign'), _('Reassign all patients taking the selected drug to another drug.'), reassign_patients)
871 )
872
873 #------------------------------------------------------------
875 if branded_drug is not None:
876 if branded_drug['is_in_use']:
877 gmGuiHelpers.gm_show_info (
878 aTitle = _('Editing drug'),
879 aMessage = _(
880 'Cannot edit the branded drug product\n'
881 '\n'
882 ' "%s" (%s)\n'
883 '\n'
884 'because it is currently taken by patients.\n'
885 ) % (branded_drug['brand'], branded_drug['preparation'])
886 )
887 return False
888
889 ea = cBrandedDrugEAPnl(parent = parent, id = -1)
890 ea.data = branded_drug
891 ea.mode = gmTools.coalesce(branded_drug, 'new', 'edit')
892 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = single_entry)
893 dlg.SetTitle(gmTools.coalesce(branded_drug, _('Adding new drug brand'), _('Editing drug brand')))
894 if dlg.ShowModal() == wx.ID_OK:
895 dlg.Destroy()
896 return True
897 dlg.Destroy()
898 return False
899
900 #============================================================
901 from Gnumed.wxGladeWidgets import wxgBrandedDrugEAPnl
902
903 -class cBrandedDrugEAPnl(wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl, gmEditArea.cGenericEditAreaMixin):
904
906
907 try:
908 data = kwargs['drug']
909 del kwargs['drug']
910 except KeyError:
911 data = None
912
913 wxgBrandedDrugEAPnl.wxgBrandedDrugEAPnl.__init__(self, *args, **kwargs)
914 gmEditArea.cGenericEditAreaMixin.__init__(self)
915
916 self.mode = 'new'
917 self.data = data
918 if data is not None:
919 self.mode = 'edit'
920 self.__component_substances = data.components_as_substances
921
922 #self.__init_ui()
923 #----------------------------------------------------------------
924 # def __init_ui(self):
925 # adjust external type PRW
926 #----------------------------------------------------------------
927 # generic Edit Area mixin API
928 #----------------------------------------------------------------
930
931 if self.data is not None:
932 if self.data['is_in_use']:
933 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit drug brand. It is in use.'), beep = True)
934 return False
935
936 validity = True
937
938 if self._PRW_brand.GetValue().strip() == u'':
939 validity = False
940 self._PRW_brand.display_as_valid(False)
941 else:
942 self._PRW_brand.display_as_valid(True)
943
944 if self._PRW_preparation.GetValue().strip() == u'':
945 validity = False
946 self._PRW_preparation.display_as_valid(False)
947 else:
948 self._PRW_preparation.display_as_valid(True)
949
950 if validity is False:
951 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save branded drug. Invalid or missing essential input.'))
952
953 return validity
954 #----------------------------------------------------------------
956
957 drug = gmMedication.create_branded_drug (
958 brand_name = self._PRW_brand.GetValue().strip(),
959 preparation = gmTools.coalesce (
960 self._PRW_preparation.GetData(),
961 self._PRW_preparation.GetValue()
962 ).strip(),
963 return_existing = True
964 )
965 drug['is_fake_brand'] = self._CHBOX_is_fake.GetValue()
966 drug['atc'] = self._PRW_atc.GetData()
967 code = self._TCTRL_external_code.GetValue().strip()
968 if code != u'':
969 drug['external_code'] = code
970 drug['external_code_type'] = self._PRW_external_code_type.GetData().strip()
971
972 drug.save()
973
974 if len(self.__component_substances) > 0:
975 drug.set_substances_as_components(substances = self.__component_substances)
976
977 self.data = drug
978
979 return True
980 #----------------------------------------------------------------
982 self.data['brand'] = self._PRW_brand.GetValue().strip()
983 self.data['preparation'] = gmTools.coalesce (
984 self._PRW_preparation.GetData(),
985 self._PRW_preparation.GetValue()
986 ).strip()
987 self.data['is_fake_brand'] = self._CHBOX_is_fake.GetValue()
988 self.data['atc'] = self._PRW_atc.GetData()
989 code = self._TCTRL_external_code.GetValue().strip()
990 if code != u'':
991 self.data['external_code'] = code
992 self.data['external_code_type'] = self._PRW_external_code_type.GetData().strip()
993 success, data = self.data.save()
994 if not success:
995 err, msg = data
996 _log.error('problem saving')
997 _log.error('%s', err)
998 _log.error('%s', msg)
999 return (success is True)
1000 #----------------------------------------------------------------
1002 self._PRW_brand.SetText(u'', None)
1003 self._PRW_preparation.SetText(u'', None)
1004 self._CHBOX_is_fake.SetValue(False)
1005 self._TCTRL_components.SetValue(u'')
1006 self._PRW_atc.SetText(u'', None)
1007 self._TCTRL_external_code.SetValue(u'')
1008 self._PRW_external_code_type.SetText(u'', None)
1009
1010 self._PRW_brand.SetFocus()
1011
1012 self.__component_substances = []
1013 #----------------------------------------------------------------
1016 #----------------------------------------------------------------
1018 self._PRW_brand.SetText(self.data['brand'], self.data['pk_brand'])
1019 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation'])
1020 self._CHBOX_is_fake.SetValue(self.data['is_fake_brand'])
1021 comps = u''
1022 if self.data['components'] is not None:
1023 comps = u'- %s' % u'\n- '.join(self.data['components'])
1024 self._TCTRL_components.SetValue(comps)
1025 self._PRW_atc.SetText(gmTools.coalesce(self.data['atc'], u''), self.data['atc'])
1026 self._TCTRL_external_code.SetValue(gmTools.coalesce(self.data['external_code'], u''))
1027 t = gmTools.coalesce(self.data['external_code_type'], u'')
1028 self._PRW_external_code_type.SetText(t, t)
1029
1030 self._PRW_brand.SetFocus()
1031
1032 self.__component_substances = self.data.components_as_substances
1033 #----------------------------------------------------------------
1034 # event handler
1035 #----------------------------------------------------------------
1045 #============================================================
1047
1049
1050 query = u"""
1051 SELECT
1052 pk,
1053 (description || ' (' || preparation || ')' || coalesce(' [' || atc_code || ']', ''))
1054 AS brand
1055 FROM ref.branded_drug
1056 WHERE description %(fragment_condition)s
1057 ORDER BY brand
1058 LIMIT 50"""
1059
1060 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1061 mp.setThresholds(2, 3, 4)
1062 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1063 self.SetToolTipString(_('The brand name of the drug.'))
1064 self.matcher = mp
1065 self.selection_only = False
1066
1067 #============================================================
1068 # current substance intake widgets
1069 #------------------------------------------------------------
1071
1073
1074 query = u"""
1075 SELECT DISTINCT ON (sched)
1076 schedule as sched,
1077 schedule
1078 FROM clin.substance_intake
1079 WHERE schedule %(fragment_condition)s
1080 ORDER BY sched
1081 LIMIT 50"""
1082
1083 mp = gmMatchProvider.cMatchProvider_SQL2(queries = query)
1084 mp.setThresholds(1, 2, 4)
1085 mp.word_separators = '[ \t=+&:@]+'
1086 gmPhraseWheel.cPhraseWheel.__init__(self, *args, **kwargs)
1087 self.SetToolTipString(_('The schedule for taking this substance.'))
1088 self.matcher = mp
1089 self.selection_only = False
1090 #============================================================
1092
1093 if intake['is_currently_active']:
1094 intake['discontinued'] = gmDateTime.pydt_now_here()
1095 if intake['discontinue_reason'] is None:
1096 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), _('discontinued due to allergy or intolerance'))
1097 else:
1098 if not intake['discontinue_reason'].startswith(_('not tolerated:')):
1099 intake['discontinue_reason'] = u'%s %s' % (_('not tolerated:'), intake['discontinue_reason'])
1100 if not intake.save():
1101 return False
1102
1103 allg = intake.turn_into_allergy(encounter_id = emr.active_encounter['pk_encounter'])
1104
1105 brand = intake.containing_drug
1106 if brand is not None:
1107 comps = [ c['substance'] for c in brand.components ]
1108 if len(comps) > 1:
1109 gmGuiHelpers.gm_show_info (
1110 aTitle = _(u'Documented an allergy'),
1111 aMessage = _(
1112 u'An allergy was documented against the substance:\n'
1113 u'\n'
1114 u' [%s]\n'
1115 u'\n'
1116 u'This substance was taken with the multi-component brand:\n'
1117 u'\n'
1118 u' [%s (%s)]\n'
1119 u'\n'
1120 u'Note that ALL components of this brand were discontinued.'
1121 ) % (
1122 intake['substance'],
1123 intake['brand'],
1124 u' & '.join(comps)
1125 )
1126 )
1127
1128 if parent is None:
1129 parent = wx.GetApp().GetTopWindow()
1130
1131 dlg = gmAllergyWidgets.cAllergyManagerDlg(parent = parent, id = -1)
1132 dlg.ShowModal()
1133
1134 return True
1135 #============================================================
1136 from Gnumed.wxGladeWidgets import wxgCurrentMedicationEAPnl
1137
1138 -class cSubstanceIntakeEAPnl(wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl, gmEditArea.cGenericEditAreaMixin):
1139
1141
1142 try:
1143 data = kwargs['substance']
1144 del kwargs['substance']
1145 except KeyError:
1146 data = None
1147
1148 wxgCurrentMedicationEAPnl.wxgCurrentMedicationEAPnl.__init__(self, *args, **kwargs)
1149 gmEditArea.cGenericEditAreaMixin.__init__(self)
1150
1151 self.mode = 'new'
1152 self.data = data
1153 if data is not None:
1154 self.mode = 'edit'
1155
1156 self.__init_ui()
1157 #----------------------------------------------------------------
1159
1160 self._PRW_component.add_callback_on_lose_focus(callback = self._on_leave_component)
1161 self._PRW_component.selection_only = True
1162
1163 self._PRW_substance.add_callback_on_lose_focus(callback = self._on_leave_substance)
1164 self._PRW_substance.selection_only = True
1165 #----------------------------------------------------------------
1167 emr = gmPerson.gmCurrentPatient().get_emr()
1168
1169 state = emr.allergy_state
1170 if state['last_confirmed'] is None:
1171 confirmed = _('never')
1172 else:
1173 confirmed = state['last_confirmed'].strftime('%Y %B %d').decode(gmI18N.get_encoding())
1174 msg = _(u'%s, last confirmed %s\n') % (state.state_string, confirmed)
1175 msg += gmTools.coalesce(state['comment'], u'', _('Comment (%s): %%s\n') % state['modified_by'])
1176 msg += u'\n'
1177
1178 for allergy in emr.get_allergies():
1179 msg += u'%s (%s, %s): %s\n' % (
1180 allergy['descriptor'],
1181 allergy['l10n_type'],
1182 gmTools.bool2subst(allergy['definite'], _('definite'), _('suspected'), u'?'),
1183 gmTools.coalesce(allergy['reaction'], _('reaction not recorded'))
1184 )
1185
1186 self._LBL_allergies.SetLabel(msg)
1187 #----------------------------------------------------------------
1188 # generic Edit Area mixin API
1189 #----------------------------------------------------------------
1191
1192 validity = True
1193
1194 has_component = (self._PRW_component.GetData() is not None)
1195 has_substance = (self._PRW_substance.GetValue().strip() != u'')
1196
1197 # must have either brand or substance
1198 if (has_component is False) and (has_substance is False):
1199 self._PRW_substance.display_as_valid(False)
1200 self._PRW_component.display_as_valid(False)
1201 validity = False
1202 else:
1203 self._PRW_substance.display_as_valid(True)
1204 self._PRW_component.display_as_valid(True)
1205
1206 # brands already have a preparation, so only required for substances
1207 if not has_component:
1208 if self._PRW_preparation.GetValue().strip() == u'':
1209 self._PRW_preparation.display_as_valid(False)
1210 validity = False
1211 else:
1212 self._PRW_preparation.display_as_valid(True)
1213
1214 # episode must be set if intake is to be approved of
1215 if self._CHBOX_approved.IsChecked():
1216 if self._PRW_episode.GetValue().strip() == u'':
1217 self._PRW_episode.display_as_valid(False)
1218 validity = False
1219 else:
1220 self._PRW_episode.display_as_valid(True)
1221
1222 # # huh ?
1223 # if self._CHBOX_approved.IsChecked() is True:
1224 # self._PRW_duration.display_as_valid(True)
1225 # else:
1226 # if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1227 # self._PRW_duration.display_as_valid(True)
1228 # else:
1229 # if gmDateTime.str2interval(self._PRW_duration.GetValue()) is None:
1230 # self._PRW_duration.display_as_valid(False)
1231 # validity = False
1232 # else:
1233 # self._PRW_duration.display_as_valid(True)
1234
1235 # end must be > start if at all
1236 end = self._DP_discontinued.GetData()
1237 if end is not None:
1238 start = self._DP_started.GetData()
1239 if start > end:
1240 self._DP_started.display_as_valid(False)
1241 self._DP_discontinued.display_as_valid(False)
1242 validity = False
1243 else:
1244 self._DP_started.display_as_valid(True)
1245 self._DP_discontinued.display_as_valid(True)
1246
1247 if validity is False:
1248 gmDispatcher.send(signal = 'statustext', msg = _('Cannot save substance intake. Invalid or missing essential input.'))
1249
1250 return validity
1251 #----------------------------------------------------------------
1253
1254 emr = gmPerson.gmCurrentPatient().get_emr()
1255 epi = self._PRW_episode.GetData(can_create = True)
1256
1257 if self._PRW_substance.GetData() is None:
1258 # auto-creates all components as intakes
1259 intake = emr.add_substance_intake (
1260 pk_component = self._PRW_component.GetData(),
1261 episode = epi
1262 )
1263 else:
1264 intake = emr.add_substance_intake (
1265 pk_substance = self._PRW_substance.GetData(),
1266 episode = epi,
1267 preparation = self._PRW_preparation.GetValue().strip()
1268 )
1269
1270 intake['started'] = self._DP_started.GetData()
1271 intake['discontinued'] = self._DP_discontinued.GetData()
1272 if intake['discontinued'] is None:
1273 intake['discontinue_reason'] = None
1274 else:
1275 intake['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1276 intake['schedule'] = self._PRW_schedule.GetValue().strip()
1277 intake['aim'] = self._PRW_aim.GetValue().strip()
1278 intake['notes'] = self._PRW_notes.GetValue().strip()
1279 intake['is_long_term'] = self._CHBOX_long_term.IsChecked()
1280 intake['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1281 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1282 intake['duration'] = None
1283 else:
1284 intake['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1285 intake.save()
1286
1287 self.data = intake
1288
1289 return True
1290 #----------------------------------------------------------------
1292
1293 # auto-applies to all components of drug if any:
1294 self.data['started'] = self._DP_started.GetData()
1295 self.data['discontinued'] = self._DP_discontinued.GetData()
1296 if self.data['discontinued'] is None:
1297 self.data['discontinue_reason'] = None
1298 else:
1299 self.data['discontinue_reason'] = self._PRW_discontinue_reason.GetValue().strip()
1300 self.data['schedule'] = self._PRW_schedule.GetValue()
1301 self.data['is_long_term'] = self._CHBOX_long_term.IsChecked()
1302 self.data['intake_is_approved_of'] = self._CHBOX_approved.IsChecked()
1303 if self._PRW_duration.GetValue().strip() in [u'', gmTools.u_infinity]:
1304 self.data['duration'] = None
1305 else:
1306 self.data['duration'] = gmDateTime.str2interval(self._PRW_duration.GetValue())
1307
1308 # applies to non-component substances only
1309 self.data['preparation'] = self._PRW_preparation.GetValue()
1310
1311 # per-component
1312 self.data['aim'] = self._PRW_aim.GetValue()
1313 self.data['notes'] = self._PRW_notes.GetValue()
1314 self.data['pk_episode'] = self._PRW_episode.GetData(can_create = True)
1315
1316 self.data.save()
1317
1318 return True
1319 #----------------------------------------------------------------
1321 self._PRW_component.SetText(u'', None)
1322 self._TCTRL_brand_ingredients.SetValue(u'')
1323 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1324
1325 self._PRW_substance.SetText(u'', None)
1326 self._PRW_substance.Enable(True)
1327
1328 self._PRW_preparation.SetText(u'', None)
1329 self._PRW_preparation.Enable(True)
1330
1331 self._PRW_schedule.SetText(u'', None)
1332 self._PRW_duration.SetText(u'', None)
1333 self._PRW_aim.SetText(u'', None)
1334 self._PRW_notes.SetText(u'', None)
1335 self._PRW_episode.SetText(u'', None)
1336
1337 self._CHBOX_long_term.SetValue(False)
1338 self._CHBOX_approved.SetValue(True)
1339
1340 self._DP_started.SetData(gmDateTime.pydt_now_here())
1341 self._DP_discontinued.SetData(None)
1342 self._PRW_discontinue_reason.SetValue(u'')
1343
1344 self.__refresh_allergies()
1345
1346 self._PRW_component.SetFocus()
1347 #----------------------------------------------------------------
1349
1350 self._TCTRL_brand_ingredients.SetValue(u'')
1351 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1352
1353 if self.data['pk_brand'] is None:
1354 self.__refresh_from_existing_substance()
1355 else:
1356 self.__refresh_from_existing_component()
1357
1358 self._PRW_component.Enable(False)
1359 self._PRW_substance.Enable(False)
1360
1361 if self.data['is_long_term']:
1362 self._CHBOX_long_term.SetValue(True)
1363 self._PRW_duration.Enable(False)
1364 self._PRW_duration.SetText(gmTools.u_infinity, None)
1365 self._BTN_discontinued_as_planned.Enable(False)
1366 else:
1367 self._CHBOX_long_term.SetValue(False)
1368 self._PRW_duration.Enable(True)
1369 self._BTN_discontinued_as_planned.Enable(True)
1370 if self.data['duration'] is None:
1371 self._PRW_duration.SetText(u'', None)
1372 else:
1373 self._PRW_duration.SetText(gmDateTime.format_interval(self.data['duration'], gmDateTime.acc_days), self.data['duration'])
1374 self._PRW_aim.SetText(gmTools.coalesce(self.data['aim'], u''), self.data['aim'])
1375 self._PRW_notes.SetText(gmTools.coalesce(self.data['notes'], u''), self.data['notes'])
1376 self._PRW_episode.SetData(self.data['pk_episode'])
1377 self._PRW_schedule.SetText(gmTools.coalesce(self.data['schedule'], u''), self.data['schedule'])
1378
1379 self._CHBOX_approved.SetValue(self.data['intake_is_approved_of'])
1380
1381 self._DP_started.SetData(self.data['started'])
1382 self._DP_discontinued.SetData(self.data['discontinued'])
1383 self._PRW_discontinue_reason.SetValue(gmTools.coalesce(self.data['discontinue_reason'], u''))
1384 if self.data['discontinued'] is not None:
1385 self._PRW_discontinue_reason.Enable()
1386
1387 self.__refresh_allergies()
1388
1389 self._PRW_schedule.SetFocus()
1390 #----------------------------------------------------------------
1392 self._LBL_component.Enable(False)
1393 self._PRW_component.SetText(u'', None)
1394 self._PRW_component.display_as_valid(True)
1395
1396 self._PRW_substance.SetText (
1397 u'%s %s%s' % (self.data['substance'], self.data['amount'], self.data['unit']),
1398 self.data['pk_substance']
1399 )
1400
1401 self._PRW_preparation.SetText(gmTools.coalesce(self.data['preparation'], u''), self.data['preparation'])
1402 self._PRW_preparation.Enable(True)
1403 #----------------------------------------------------------------
1405 self._PRW_component.SetText (
1406 u'%s %s%s (%s)' % (self.data['substance'], self.data['amount'], self.data['unit'], self.data['brand']),
1407 self.data['pk_drug_component']
1408 )
1409
1410 brand = gmMedication.cBrandedDrug(aPK_obj = self.data['pk_brand'])
1411 if brand['components'] is not None:
1412 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components']))
1413 tt = u'%s:\n\n- %s' % (
1414 self.data['brand'],
1415 u'\n- '.join(brand['components'])
1416 )
1417 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1418
1419 self._LBL_or.Enable(False)
1420 self._LBL_substance.Enable(False)
1421 self._PRW_substance.SetText(u'', None)
1422 self._PRW_substance.display_as_valid(True)
1423
1424 self._PRW_preparation.SetText(self.data['preparation'], self.data['preparation'])
1425 self._PRW_preparation.Enable(False)
1426 #----------------------------------------------------------------
1429 #----------------------------------------------------------------
1430 # event handlers
1431 #----------------------------------------------------------------
1433 if self._PRW_component.GetData() is None:
1434 self._LBL_or.Enable(True)
1435 self._PRW_component.SetText(u'', None)
1436 self._LBL_substance.Enable(True)
1437 self._PRW_substance.Enable(True)
1438 self._LBL_preparation.Enable(True)
1439 self._PRW_preparation.Enable(True)
1440 self._PRW_preparation.SetText(u'', None)
1441 self._TCTRL_brand_ingredients.SetValue(u'')
1442 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1443 else:
1444 self._LBL_or.Enable(False)
1445 self._LBL_substance.Enable(False)
1446 self._PRW_substance.SetText(u'', None)
1447 self._PRW_substance.display_as_valid(True)
1448 self._PRW_substance.Enable(False)
1449 self._LBL_preparation.Enable(False)
1450 self._PRW_preparation.Enable(False)
1451 comp = gmMedication.cDrugComponent(aPK_obj = self._PRW_component.GetData())
1452 self._PRW_preparation.SetText(comp['preparation'], comp['preparation'])
1453 brand = comp.containing_drug
1454 if brand['components'] is not None:
1455 self._TCTRL_brand_ingredients.SetValue(u'; '.join(brand['components']))
1456 tt = u'%s:\n\n- %s' % (
1457 self.data['brand'],
1458 u'\n- '.join(brand['components'])
1459 )
1460 self._TCTRL_brand_ingredients.SetToolTipString(tt)
1461 #----------------------------------------------------------------
1463 if self._PRW_substance.GetData() is None:
1464 self._LBL_or.Enable(True)
1465 self._LBL_component.Enable(True)
1466 self._PRW_component.Enable(True)
1467 self._PRW_substance.SetText(u'', None)
1468 else:
1469 self._LBL_or.Enable(False)
1470 self._LBL_component.Enable(False)
1471 self._PRW_component.SetText(u'', None)
1472 self._PRW_component.display_as_valid(True)
1473 self._PRW_component.Enable(False)
1474 self._LBL_preparation.Enable(True)
1475 self._PRW_preparation.Enable(True)
1476 self._TCTRL_brand_ingredients.SetValue(u'')
1477 self._TCTRL_brand_ingredients.SetToolTipString(u'')
1478 #----------------------------------------------------------------
1480 if self._DP_discontinued.GetData() is None:
1481 self._PRW_discontinue_reason.Enable(False)
1482 else:
1483 self._PRW_discontinue_reason.Enable(True)
1484 #----------------------------------------------------------------
1487 #----------------------------------------------------------------
1490 #----------------------------------------------------------------
1520 #----------------------------------------------------------------
1522 if self._CHBOX_long_term.IsChecked() is True:
1523 self._PRW_duration.Enable(False)
1524 self._BTN_discontinued_as_planned.Enable(False)
1525 self._PRW_discontinue_reason.Enable(False)
1526 else:
1527 self._PRW_duration.Enable(True)
1528 self._BTN_discontinued_as_planned.Enable(True)
1529 self._PRW_discontinue_reason.Enable(True)
1530
1531 self.__refresh_allergies()
1532 #----------------------------------------------------------------
1534 if not self.save():
1535 return False
1536
1537 return turn_substance_intake_into_allergy (
1538 parent = self,
1539 intake = self.data,
1540 emr = gmPerson.gmCurrentPatient().get_emr()
1541 )
1542 #============================================================
1544
1545 subst = gmMedication.cSubstanceIntakeEntry(aPK_obj = substance)
1546 msg = _(
1547 '\n'
1548 '[%s]\n'
1549 '\n'
1550 'It may be prudent to edit (before deletion) the details\n'
1551 'of this substance intake entry so as to leave behind\n'
1552 'some indication of why it was deleted.\n'
1553 ) % subst.format()
1554
1555 dlg = gmGuiHelpers.c3ButtonQuestionDlg (
1556 parent,
1557 -1,
1558 caption = _('Deleting medication / substance intake'),
1559 question = msg,
1560 button_defs = [
1561 {'label': _('&Edit'), 'tooltip': _('Allow editing of substance intake entry before deletion.'), 'default': True},
1562 {'label': _('&Delete'), 'tooltip': _('Delete immediately without editing first.')},
1563 {'label': _('&Cancel'), 'tooltip': _('Abort. Do not delete or edit substance intake entry.')}
1564 ]
1565 )
1566
1567 edit_first = dlg.ShowModal()
1568 dlg.Destroy()
1569
1570 if edit_first == wx.ID_CANCEL:
1571 return
1572
1573 if edit_first == wx.ID_YES:
1574 edit_intake_of_substance(parent = parent, substance = subst)
1575 delete_it = gmGuiHelpers.gm_show_question (
1576 aMessage = _('Now delete substance intake entry ?'),
1577 aTitle = _('Deleting medication / substance intake')
1578 )
1579 else:
1580 delete_it = True
1581
1582 if not delete_it:
1583 return
1584
1585 gmMedication.delete_substance_intake(substance = substance)
1586 #------------------------------------------------------------
1588 ea = cSubstanceIntakeEAPnl(parent = parent, id = -1, substance = substance)
1589 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = (substance is not None))
1590 dlg.SetTitle(gmTools.coalesce(substance, _('Adding substance intake'), _('Editing substance intake')))
1591 dlg.left_extra_button = (
1592 _('Allergy'),
1593 _('Document an allergy against this substance.'),
1594 ea.turn_into_allergy
1595 )
1596 if dlg.ShowModal() == wx.ID_OK:
1597 dlg.Destroy()
1598 return True
1599 dlg.Destroy()
1600 return False
1601
1602 #============================================================
1603 # current substances grid
1604 #------------------------------------------------------------
1606
1607 if parent is None:
1608 parent = wx.GetApp().GetTopWindow()
1609
1610 template = gmFormWidgets.manage_form_templates (
1611 parent = parent,
1612 template_types = ['current medication list']
1613 )
1614 option = u'form_templates.medication_list'
1615
1616 if template is None:
1617 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
1618 return None
1619
1620 if template['engine'] != u'L':
1621 gmDispatcher.send(signal = 'statustext', msg = _('No medication list template configured.'), beep = True)
1622 return None
1623
1624 dbcfg = gmCfg.cCfgSQL()
1625 dbcfg.set (
1626 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1627 option = option,
1628 value = u'%s - %s' % (template['name_long'], template['external_version'])
1629 )
1630
1631 return template
1632 #------------------------------------------------------------
1634
1635 if parent is None:
1636 parent = wx.GetApp().GetTopWindow()
1637
1638 # 1) get template
1639 dbcfg = gmCfg.cCfgSQL()
1640 option = u'form_templates.medication_list'
1641
1642 template = dbcfg.get2 (
1643 option = option,
1644 workplace = gmSurgery.gmCurrentPractice().active_workplace,
1645 bias = 'user'
1646 )
1647
1648 if template is None:
1649 template = configure_medication_list_template(parent = parent)
1650 if template is None:
1651 gmGuiHelpers.gm_show_error (
1652 aMessage = _('There is no medication list template configured.'),
1653 aTitle = _('Printing medication list')
1654 )
1655 return False
1656 else:
1657 try:
1658 name, ver = template.split(u' - ')
1659 except:
1660 _log.exception('problem splitting medication list template name [%s]', template)
1661 gmDispatcher.send(signal = 'statustext', msg = _('Problem loading medication list template.'), beep = True)
1662 return False
1663 template = gmForms.get_form_template(name_long = name, external_version = ver)
1664 if template is None:
1665 gmGuiHelpers.gm_show_error (
1666 aMessage = _('Cannot load medication list template [%s - %s]') % (name, ver),
1667 aTitle = _('Printing medication list')
1668 )
1669 return False
1670
1671 # 2) process template
1672 try:
1673 meds_list = template.instantiate()
1674 except KeyError:
1675 _log.exception('cannot instantiate medication list template [%s]', template)
1676 gmGuiHelpers.gm_show_error (
1677 aMessage = _('Invalid medication list template [%s - %s (%s)]') % (name, ver, template['engine']),
1678 aTitle = _('Printing medication list')
1679 )
1680 return False
1681
1682 ph = gmMacro.gmPlaceholderHandler()
1683 #ph.debug = True
1684 meds_list.substitute_placeholders(data_source = ph)
1685 pdf_name = meds_list.generate_output()
1686 if pdf_name is None:
1687 gmGuiHelpers.gm_show_error (
1688 aMessage = _('Error generating the medication list.'),
1689 aTitle = _('Printing medication list')
1690 )
1691 return False
1692
1693 # 3) print template
1694 printed = gmPrinting.print_file(filename = pdf_name, jobtype = 'medication_list')
1695 if not printed:
1696 gmGuiHelpers.gm_show_error (
1697 aMessage = _('Error printing the medication list.'),
1698 aTitle = _('Printing medication list')
1699 )
1700 return False
1701
1702 pat = gmPerson.gmCurrentPatient()
1703 emr = pat.get_emr()
1704 epi = emr.add_episode(episode_name = 'administration', is_open = False)
1705 emr.add_clin_narrative (
1706 soap_cat = None,
1707 note = _('medication list printed from template [%s - %s]') % (template['name_long'], template['external_version']),
1708 episode = epi
1709 )
1710
1711 return True
1712 #------------------------------------------------------------
1713 -def update_substance_intake_list_from_prescription(parent=None, prescribed_drugs=None, emr=None):
1714
1715 if len(prescribed_drugs) == 0:
1716 return
1717
1718 curr_brands = [ i['pk_brand'] for i in emr.get_current_substance_intake() if i['pk_brand'] is not None ]
1719 new_drugs = []
1720 for drug in prescribed_drugs:
1721 if drug['pk_brand'] not in curr_brands:
1722 new_drugs.append(drug)
1723
1724 if len(new_drugs) == 0:
1725 return
1726
1727 if parent is None:
1728 parent = wx.GetApp().GetTopWindow()
1729
1730 dlg = gmListWidgets.cItemPickerDlg (
1731 parent,
1732 -1,
1733 msg = _(
1734 'These brands have been prescribed but are not listed\n'
1735 'in the current medication list of this patient.\n'
1736 '\n'
1737 'Please select those you want added to the medication list.'
1738 )
1739 )
1740 dlg.set_columns (
1741 columns = [_('Newly prescribed drugs')],
1742 columns_right = [_('Add to medication list')]
1743 )
1744 choices = [ (u'%s %s (%s)' % (d['brand'], d['preparation'], u'; '.join(d['components']))) for d in new_drugs ]
1745 dlg.set_choices (
1746 choices = choices,
1747 data = new_drugs
1748 )
1749 dlg.ShowModal()
1750 drugs2add = dlg.get_picks()
1751 dlg.Destroy()
1752
1753 if drugs2add is None:
1754 return
1755
1756 if len(drugs2add) == 0:
1757 return
1758
1759 for drug in drugs2add:
1760 # only add first component since all other components get added by a trigger ...
1761 intake = emr.add_substance_intake (
1762 pk_component = drug['pk_components'][0],
1763 episode = emr.add_episode(episode_name = gmMedication.DEFAULT_MEDICATION_HISTORY_EPISODE)['pk_episode'],
1764 )
1765 intake['intake_is_approved_of'] = True
1766 intake.save()
1767
1768 return
1769 #------------------------------------------------------------
1771 """A grid class for displaying current substance intake.
1772
1773 - does NOT listen to the currently active patient
1774 - thereby it can display any patient at any time
1775 """
1777
1778 wx.grid.Grid.__init__(self, *args, **kwargs)
1779
1780 self.__patient = None
1781 self.__row_data = {}
1782 self.__prev_row = None
1783 self.__prev_tooltip_row = None
1784 self.__prev_cell_0 = None
1785 self.__grouping_mode = u'episode'
1786 self.__filter_show_unapproved = True
1787 self.__filter_show_inactive = False
1788
1789 self.__grouping2col_labels = {
1790 u'episode': [
1791 _('Episode'),
1792 _('Substance'),
1793 _('Dose'),
1794 _('Schedule'),
1795 _('Started'),
1796 _('Duration / Until'),
1797 _('Brand')
1798 ],
1799 u'brand': [
1800 _('Brand'),
1801 _('Schedule'),
1802 _('Substance'),
1803 _('Dose'),
1804 _('Started'),
1805 _('Duration / Until'),
1806 _('Episode')
1807 ]
1808 }
1809
1810 self.__grouping2order_by_clauses = {
1811 u'episode': u'pk_health_issue nulls first, episode, substance, started',
1812 u'brand': u'brand nulls last, substance, started'
1813 }
1814
1815 self.__init_ui()
1816 self.__register_events()
1817 #------------------------------------------------------------
1818 # external API
1819 #------------------------------------------------------------
1821
1822 sel_block_top_left = self.GetSelectionBlockTopLeft()
1823 sel_block_bottom_right = self.GetSelectionBlockBottomRight()
1824 sel_cols = self.GetSelectedCols()
1825 sel_rows = self.GetSelectedRows()
1826
1827 selected_cells = []
1828
1829 # individually selected cells (ctrl-click)
1830 selected_cells += self.GetSelectedCells()
1831
1832 # selected rows
1833 selected_cells += list (
1834 (row, col)
1835 for row in sel_rows
1836 for col in xrange(self.GetNumberCols())
1837 )
1838
1839 # selected columns
1840 selected_cells += list (
1841 (row, col)
1842 for row in xrange(self.GetNumberRows())
1843 for col in sel_cols
1844 )
1845
1846 # selection blocks
1847 for top_left, bottom_right in zip(self.GetSelectionBlockTopLeft(), self.GetSelectionBlockBottomRight()):
1848 selected_cells += [
1849 (row, col)
1850 for row in xrange(top_left[0], bottom_right[0] + 1)
1851 for col in xrange(top_left[1], bottom_right[1] + 1)
1852 ]
1853
1854 return set(selected_cells)
1855 #------------------------------------------------------------
1857 rows = {}
1858
1859 for row, col in self.get_selected_cells():
1860 rows[row] = True
1861
1862 return rows.keys()
1863 #------------------------------------------------------------
1865 return [ self.__row_data[row] for row in self.get_selected_rows() ]
1866 #------------------------------------------------------------
1868
1869 self.empty_grid()
1870
1871 if self.__patient is None:
1872 return
1873
1874 emr = self.__patient.get_emr()
1875 meds = emr.get_current_substance_intake (
1876 order_by = self.__grouping2order_by_clauses[self.__grouping_mode],
1877 include_unapproved = self.__filter_show_unapproved,
1878 include_inactive = self.__filter_show_inactive
1879 )
1880 if not meds:
1881 return
1882
1883 self.BeginBatch()
1884
1885 # columns
1886 labels = self.__grouping2col_labels[self.__grouping_mode]
1887 if self.__filter_show_unapproved:
1888 self.AppendCols(numCols = len(labels) + 1)
1889 else:
1890 self.AppendCols(numCols = len(labels))
1891 for col_idx in range(len(labels)):
1892 self.SetColLabelValue(col_idx, labels[col_idx])
1893 if self.__filter_show_unapproved:
1894 self.SetColLabelValue(len(labels), u'OK?')
1895 self.SetColSize(len(labels), 40)
1896
1897 self.AppendRows(numRows = len(meds))
1898
1899 # loop over data
1900 for row_idx in range(len(meds)):
1901 med = meds[row_idx]
1902 self.__row_data[row_idx] = med
1903
1904 if med['is_currently_active'] is True:
1905 atcs = []
1906 if med['atc_substance'] is not None:
1907 atcs.append(med['atc_substance'])
1908 # if med['atc_brand'] is not None:
1909 # atcs.append(med['atc_brand'])
1910 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],), brand = med['brand'])
1911 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (med['substance'],))
1912 if allg not in [None, False]:
1913 attr = self.GetOrCreateCellAttr(row_idx, 0)
1914 if allg['type'] == u'allergy':
1915 attr.SetTextColour('red')
1916 else:
1917 attr.SetTextColour('yellow')
1918 self.SetRowAttr(row_idx, attr)
1919 else:
1920 attr = self.GetOrCreateCellAttr(row_idx, 0)
1921 attr.SetTextColour('grey')
1922 self.SetRowAttr(row_idx, attr)
1923
1924 if self.__grouping_mode == u'episode':
1925 if med['pk_episode'] is None:
1926 self.__prev_cell_0 = None
1927 epi = gmTools.u_diameter
1928 else:
1929 if self.__prev_cell_0 == med['episode']:
1930 epi = u''
1931 else:
1932 self.__prev_cell_0 = med['episode']
1933 epi = gmTools.coalesce(med['episode'], u'')
1934 self.SetCellValue(row_idx, 0, gmTools.wrap(text = epi, width = 40))
1935
1936 self.SetCellValue(row_idx, 1, med['substance'])
1937 self.SetCellValue(row_idx, 2, u'%s%s' % (med['amount'], med['unit']))
1938 self.SetCellValue(row_idx, 3, gmTools.coalesce(med['schedule'], u''))
1939 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1940
1941 if med['is_long_term']:
1942 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1943 else:
1944 if med['discontinued'] is None:
1945 if med['duration'] is None:
1946 self.SetCellValue(row_idx, 5, u'')
1947 else:
1948 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1949 else:
1950 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
1951
1952 if med['pk_brand'] is None:
1953 brand = u''
1954 else:
1955 if med['fake_brand']:
1956 brand = gmTools.coalesce(med['brand'], u'', _('%s (fake)'))
1957 else:
1958 brand = gmTools.coalesce(med['brand'], u'')
1959 self.SetCellValue(row_idx, 6, gmTools.wrap(text = brand, width = 35))
1960
1961 elif self.__grouping_mode == u'brand':
1962
1963 if med['pk_brand'] is None:
1964 self.__prev_cell_0 = None
1965 brand = gmTools.u_diameter
1966 else:
1967 if self.__prev_cell_0 == med['brand']:
1968 brand = u''
1969 else:
1970 self.__prev_cell_0 = med['brand']
1971 if med['fake_brand']:
1972 brand = gmTools.coalesce(med['brand'], u'', _('%s (fake)'))
1973 else:
1974 brand = gmTools.coalesce(med['brand'], u'')
1975 self.SetCellValue(row_idx, 0, gmTools.wrap(text = brand, width = 35))
1976
1977 self.SetCellValue(row_idx, 1, gmTools.coalesce(med['schedule'], u''))
1978 self.SetCellValue(row_idx, 2, med['substance'])
1979 self.SetCellValue(row_idx, 3, u'%s%s' % (med['amount'], med['unit']))
1980 self.SetCellValue(row_idx, 4, med['started'].strftime('%Y-%m-%d'))
1981
1982 if med['is_long_term']:
1983 self.SetCellValue(row_idx, 5, gmTools.u_infinity)
1984 else:
1985 if med['discontinued'] is None:
1986 if med['duration'] is None:
1987 self.SetCellValue(row_idx, 5, u'')
1988 else:
1989 self.SetCellValue(row_idx, 5, gmDateTime.format_interval(med['duration'], gmDateTime.acc_days))
1990 else:
1991 self.SetCellValue(row_idx, 5, med['discontinued'].strftime('%Y-%m-%d'))
1992
1993 if med['pk_episode'] is None:
1994 epi = u''
1995 else:
1996 epi = gmTools.coalesce(med['episode'], u'')
1997 self.SetCellValue(row_idx, 6, gmTools.wrap(text = epi, width = 40))
1998
1999 else:
2000 raise ValueError('unknown grouping mode [%s]' % self.__grouping_mode)
2001
2002 if self.__filter_show_unapproved:
2003 self.SetCellValue (
2004 row_idx,
2005 len(labels),
2006 gmTools.bool2subst(med['intake_is_approved_of'], gmTools.u_checkmark_thin, u'', u'?')
2007 )
2008
2009 #self.SetCellAlignment(row, col, horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
2010
2011 self.AutoSize()
2012 self.EndBatch()
2013 #------------------------------------------------------------
2015 self.BeginBatch()
2016 self.ClearGrid()
2017 # Windows cannot do "nothing", it rather decides to assert()
2018 # on thinking it is supposed to do nothing
2019 if self.GetNumberRows() > 0:
2020 self.DeleteRows(pos = 0, numRows = self.GetNumberRows())
2021 if self.GetNumberCols() > 0:
2022 self.DeleteCols(pos = 0, numCols = self.GetNumberCols())
2023 self.EndBatch()
2024 self.__row_data = {}
2025 self.__prev_cell_0 = None
2026 #------------------------------------------------------------
2028
2029 if len(self.__row_data) == 0:
2030 return
2031
2032 sel_rows = self.get_selected_rows()
2033 if len(sel_rows) != 1:
2034 return
2035
2036 drug_db = get_drug_database()
2037 if drug_db is None:
2038 return
2039
2040 intake = self.get_selected_data()[0] # just in case
2041 if intake['brand'] is None:
2042 drug_db.show_info_on_substance(substance_intake = intake)
2043 else:
2044 drug_db.show_info_on_drug(substance_intake = intake)
2045 #------------------------------------------------------------
2047
2048 if len(self.__row_data) == 0:
2049 return
2050
2051 sel_rows = self.get_selected_rows()
2052
2053 if len(sel_rows) != 1:
2054 return
2055
2056 webbrowser.open (
2057 url = gmMedication.drug2renal_insufficiency_url(search_term = self.get_selected_data()[0]),
2058 new = False,
2059 autoraise = True
2060 )
2061 #------------------------------------------------------------
2063
2064 dbcfg = gmCfg.cCfgSQL()
2065
2066 url = dbcfg.get2 (
2067 option = u'external.urls.report_ADR',
2068 workplace = gmSurgery.gmCurrentPractice().active_workplace,
2069 bias = u'user',
2070 default = u'https://dcgma.org/uaw/meldung.php' # http://www.akdae.de/Arzneimittelsicherheit/UAW-Meldung/UAW-Meldung-online.html
2071 )
2072
2073 webbrowser.open(url = url, new = False, autoraise = True)
2074 #------------------------------------------------------------
2076 drug_db = get_drug_database()
2077 if drug_db is None:
2078 return
2079
2080 drug_db.reviewer = gmPerson.gmCurrentProvider()
2081 update_substance_intake_list_from_prescription (
2082 parent = self,
2083 prescribed_drugs = drug_db.prescribe(),
2084 emr = self.__patient.get_emr()
2085 )
2086 #------------------------------------------------------------
2088
2089 if len(self.__row_data) == 0:
2090 return
2091
2092 drug_db = get_drug_database()
2093 if drug_db is None:
2094 return
2095
2096 if len(self.get_selected_rows()) > 1:
2097 drug_db.check_interactions(substance_intakes = self.get_selected_data())
2098 else:
2099 drug_db.check_interactions(substance_intakes = self.__row_data.values())
2100 #------------------------------------------------------------
2103 #------------------------------------------------------------
2105
2106 rows = self.get_selected_rows()
2107
2108 if len(rows) == 0:
2109 return
2110
2111 if len(rows) > 1:
2112 gmDispatcher.send(signal = 'statustext', msg = _('Cannot edit more than one substance at once.'), beep = True)
2113 return
2114
2115 subst = self.get_selected_data()[0]
2116 edit_intake_of_substance(parent = self, substance = subst)
2117 #------------------------------------------------------------
2119
2120 rows = self.get_selected_rows()
2121
2122 if len(rows) == 0:
2123 return
2124
2125 if len(rows) > 1:
2126 gmDispatcher.send(signal = 'statustext', msg = _('Cannot delete more than one substance at once.'), beep = True)
2127 return
2128
2129 subst = self.get_selected_data()[0]
2130 delete_substance_intake(parent = self, substance = subst['pk_substance_intake'])
2131 #------------------------------------------------------------
2133 rows = self.get_selected_rows()
2134
2135 if len(rows) == 0:
2136 return
2137
2138 if len(rows) > 1:
2139 gmDispatcher.send(signal = 'statustext', msg = _('Cannot create allergy from more than one substance at once.'), beep = True)
2140 return
2141
2142 return turn_substance_intake_into_allergy (
2143 parent = self,
2144 intake = self.get_selected_data()[0],
2145 emr = self.__patient.get_emr()
2146 )
2147 #------------------------------------------------------------
2149 # there could be some filtering/user interaction going on here
2150 print_medication_list(parent = self)
2151 #------------------------------------------------------------
2153
2154 try:
2155 entry = self.__row_data[row]
2156 except KeyError:
2157 return u' '
2158
2159 emr = self.__patient.get_emr()
2160 atcs = []
2161 if entry['atc_substance'] is not None:
2162 atcs.append(entry['atc_substance'])
2163 # if entry['atc_brand'] is not None:
2164 # atcs.append(entry['atc_brand'])
2165 # allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],), brand = entry['brand'])
2166 allg = emr.is_allergic_to(atcs = tuple(atcs), inns = (entry['substance'],))
2167
2168 tt = _('Substance intake entry (%s, %s) [#%s] \n') % (
2169 gmTools.bool2subst (
2170 boolean = entry['is_currently_active'],
2171 true_return = gmTools.bool2subst (
2172 boolean = entry['seems_inactive'],
2173 true_return = _('active, needs check'),
2174 false_return = _('active'),
2175 none_return = _('assumed active')
2176 ),
2177 false_return = _('inactive')
2178 ),
2179 gmTools.bool2subst (
2180 boolean = entry['intake_is_approved_of'],
2181 true_return = _('approved'),
2182 false_return = _('unapproved')
2183 ),
2184 entry['pk_substance_intake']
2185 )
2186
2187 if allg not in [None, False]:
2188 certainty = gmTools.bool2subst(allg['definite'], _('definite'), _('suspected'))
2189 tt += u'\n'
2190 tt += u' !! ---- Cave ---- !!\n'
2191 tt += u' %s (%s): %s (%s)\n' % (
2192 allg['l10n_type'],
2193 certainty,
2194 allg['descriptor'],
2195 gmTools.coalesce(allg['reaction'], u'')[:40]
2196 )
2197 tt += u'\n'
2198
2199 tt += u' ' + _('Substance: %s [#%s]\n') % (entry['substance'], entry['pk_substance'])
2200 tt += u' ' + _('Preparation: %s\n') % entry['preparation']
2201 tt += u' ' + _('Amount per dose: %s%s') % (entry['amount'], entry['unit'])
2202 if entry.ddd is not None:
2203 tt += u' (DDD: %s %s)' % (entry.ddd['ddd'], entry.ddd['unit'])
2204 tt += u'\n'
2205 tt += gmTools.coalesce(entry['atc_substance'], u'', _(' ATC (substance): %s\n'))
2206
2207 tt += u'\n'
2208
2209 tt += gmTools.coalesce (
2210 entry['brand'],
2211 u'',
2212 _(' Brand name: %%s [#%s]\n') % entry['pk_brand']
2213 )
2214 tt += gmTools.coalesce(entry['atc_brand'], u'', _(' ATC (brand): %s\n'))
2215
2216 tt += u'\n'
2217
2218 tt += gmTools.coalesce(entry['schedule'], u'', _(' Regimen: %s\n'))
2219
2220 if entry['is_long_term']:
2221 duration = u' %s %s' % (gmTools.u_right_arrow, gmTools.u_infinity)
2222 else:
2223 if entry['duration'] is None:
2224 duration = u''
2225 else:
2226 duration = u' %s %s' % (gmTools.u_right_arrow, gmDateTime.format_interval(entry['duration'], gmDateTime.acc_days))
2227
2228 tt += _(' Started %s%s%s\n') % (
2229 entry['started'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
2230 duration,
2231 gmTools.bool2subst(entry['is_long_term'], _(' (long-term)'), _(' (short-term)'), u'')
2232 )
2233
2234 if entry['discontinued'] is not None:
2235 tt += _(' Discontinued %s\n') % (
2236 entry['discontinued'].strftime('%Y %B %d').decode(gmI18N.get_encoding()),
2237 )
2238 tt += _(' Reason: %s\n') % entry['discontinue_reason']
2239
2240 tt += u'\n'
2241
2242 tt += gmTools.coalesce(entry['aim'], u'', _(' Aim: %s\n'))
2243 tt += gmTools.coalesce(entry['episode'], u'', _(' Episode: %s\n'))
2244 tt += gmTools.coalesce(entry['notes'], u'', _(' Advice: %s\n'))
2245
2246 tt += u'\n'
2247
2248 tt += _(u'Revision: #%(row_ver)s, %(mod_when)s by %(mod_by)s.') % ({
2249 'row_ver': entry['row_version'],
2250 'mod_when': entry['modified_when'].strftime('%c').decode(gmI18N.get_encoding()),
2251 'mod_by': entry['modified_by']
2252 })
2253
2254 return tt
2255 #------------------------------------------------------------
2256 # internal helpers
2257 #------------------------------------------------------------
2259 self.CreateGrid(0, 1)
2260 self.EnableEditing(0)
2261 self.EnableDragGridSize(1)
2262 self.SetSelectionMode(wx.grid.Grid.wxGridSelectRows)
2263
2264 self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_CENTER)
2265
2266 self.SetRowLabelSize(0)
2267 self.SetRowLabelAlignment(horiz = wx.ALIGN_RIGHT, vert = wx.ALIGN_CENTRE)
2268 #------------------------------------------------------------
2269 # properties
2270 #------------------------------------------------------------
2273
2277
2278 patient = property(_get_patient, _set_patient)
2279 #------------------------------------------------------------
2282
2286
2287 grouping_mode = property(_get_grouping_mode, _set_grouping_mode)
2288 #------------------------------------------------------------
2291
2295
2296 filter_show_unapproved = property(_get_filter_show_unapproved, _set_filter_show_unapproved)
2297 #------------------------------------------------------------
2300
2304
2305 filter_show_inactive = property(_get_filter_show_inactive, _set_filter_show_inactive)
2306 #------------------------------------------------------------
2307 # event handling
2308 #------------------------------------------------------------
2310 # dynamic tooltips: GridWindow, GridRowLabelWindow, GridColLabelWindow, GridCornerLabelWindow
2311 self.GetGridWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_cells)
2312 #self.GetGridRowLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_row_labels)
2313 #self.GetGridColLabelWindow().Bind(wx.EVT_MOTION, self.__on_mouse_over_col_labels)
2314
2315 # editing cells
2316 self.Bind(wx.grid.EVT_GRID_CELL_LEFT_DCLICK, self.__on_cell_left_dclicked)
2317 #------------------------------------------------------------
2319 """Calculate where the mouse is and set the tooltip dynamically."""
2320
2321 # Use CalcUnscrolledPosition() to get the mouse position within the
2322 # entire grid including what's offscreen
2323 x, y = self.CalcUnscrolledPosition(evt.GetX(), evt.GetY())
2324
2325 # use this logic to prevent tooltips outside the actual cells
2326 # apply to GetRowSize, too
2327 # tot = 0
2328 # for col in xrange(self.NumberCols):
2329 # tot += self.GetColSize(col)
2330 # if xpos <= tot:
2331 # self.tool_tip.Tip = 'Tool tip for Column %s' % (
2332 # self.GetColLabelValue(col))
2333 # break
2334 # else: # mouse is in label area beyond the right-most column
2335 # self.tool_tip.Tip = ''
2336
2337 row, col = self.XYToCell(x, y)
2338
2339 if row == self.__prev_tooltip_row:
2340 return
2341
2342 self.__prev_tooltip_row = row
2343
2344 try:
2345 evt.GetEventObject().SetToolTipString(self.get_row_tooltip(row = row))
2346 except KeyError:
2347 pass
2348 #------------------------------------------------------------
2350 row = evt.GetRow()
2351 data = self.__row_data[row]
2352 edit_intake_of_substance(parent = self, substance = data)
2353 #============================================================
2354 from Gnumed.wxGladeWidgets import wxgCurrentSubstancesPnl
2355
2356 -class cCurrentSubstancesPnl(wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl, gmRegetMixin.cRegetOnPaintMixin):
2357
2358 """Panel holding a grid with current substances. Used as notebook page."""
2359
2361
2362 wxgCurrentSubstancesPnl.wxgCurrentSubstancesPnl.__init__(self, *args, **kwargs)
2363 gmRegetMixin.cRegetOnPaintMixin.__init__(self)
2364
2365 self.__register_interests()
2366 #-----------------------------------------------------
2367 # reget-on-paint mixin API
2368 #-----------------------------------------------------
2370 """Populate cells with data from model."""
2371 pat = gmPerson.gmCurrentPatient()
2372 if pat.connected:
2373 self._grid_substances.patient = pat
2374 else:
2375 self._grid_substances.patient = None
2376 return True
2377 #--------------------------------------------------------
2378 # event handling
2379 #--------------------------------------------------------
2381 gmDispatcher.connect(signal = u'pre_patient_selection', receiver = self._on_pre_patient_selection)
2382 gmDispatcher.connect(signal = u'post_patient_selection', receiver = self._schedule_data_reget)
2383 gmDispatcher.connect(signal = u'substance_intake_mod_db', receiver = self._schedule_data_reget)
2384 # active_substance_mod_db
2385 # substance_brand_mod_db
2386 #--------------------------------------------------------
2389 #--------------------------------------------------------
2391 self._grid_substances.patient = None
2392 #--------------------------------------------------------
2395 #--------------------------------------------------------
2398 #--------------------------------------------------------
2401 #--------------------------------------------------------
2404 #--------------------------------------------------------
2407 #--------------------------------------------------------
2409 self._grid_substances.grouping_mode = 'episode'
2410 #--------------------------------------------------------
2412 self._grid_substances.grouping_mode = 'brand'
2413 #--------------------------------------------------------
2416 #--------------------------------------------------------
2419 #--------------------------------------------------------
2422 #--------------------------------------------------------
2425 #--------------------------------------------------------
2428 #--------------------------------------------------------
2431 #--------------------------------------------------------
2434 #============================================================
2435 # main
2436 #------------------------------------------------------------
2437 if __name__ == '__main__':
2438
2439 if len(sys.argv) < 2:
2440 sys.exit()
2441
2442 if sys.argv[1] != 'test':
2443 sys.exit()
2444
2445 from Gnumed.pycommon import gmI18N
2446
2447 gmI18N.activate_locale()
2448 gmI18N.install_domain(domain = 'gnumed')
2449
2450 #----------------------------------------
2451 app = wx.PyWidgetTester(size = (600, 600))
2452 #app.SetWidget(cATCPhraseWheel, -1)
2453 app.SetWidget(cSubstancePhraseWheel, -1)
2454 app.MainLoop()
2455
2456 #============================================================
2457
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Wed May 4 03:58:56 2011 | http://epydoc.sourceforge.net |