1
2 """GNUmed expando based textual progress notes handling widgets."""
3
4 __author__ = "Karsten Hilbert <Karsten.Hilbert@gmx.net>"
5 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
6
7 import sys
8 import logging
9
10
11 import wx
12
13
14 if __name__ == '__main__':
15 sys.path.insert(0, '../../')
16
17 from Gnumed.pycommon import gmI18N
18
19 if __name__ == '__main__':
20 gmI18N.activate_locale()
21 gmI18N.install_domain()
22
23 from Gnumed.pycommon import gmDispatcher
24 from Gnumed.pycommon import gmDateTime
25 from Gnumed.pycommon import gmCfg
26
27 from Gnumed.business import gmPerson
28 from Gnumed.business import gmPraxis
29 from Gnumed.business import gmEMRStructItems
30 from Gnumed.business import gmClinNarrative
31
32 from Gnumed.wxpython import gmGuiHelpers
33 from Gnumed.wxpython import gmTextCtrl
34 from Gnumed.wxpython import gmVisualProgressNoteWidgets
35 from Gnumed.wxpython import gmEMRStructWidgets
36
37 _log = logging.getLogger('gm.ui')
38
39
40 from Gnumed.wxGladeWidgets import wxgProgressNotesEAPnl
41
42 -class cProgressNotesEAPnl(gmTextCtrl.cExpandoTextCtrlHandling_PanelMixin, wxgProgressNotesEAPnl.wxgProgressNotesEAPnl):
43 """An Edit Area like panel for entering progress notes.
44
45 (
46 Subjective: Codes:
47 expando text ctrl
48 Objective: Codes:
49 expando text ctrl
50 Assessment: Codes:
51 expando text ctrl
52 Plan: Codes:
53 expando text ctrl
54 )
55 OR
56 SOAP editor (StyledTextCtrl)
57 AND
58 visual progress notes (panel with images)
59 AND
60 Episode synopsis: Codes:
61 expando text ctrl
62
63 - knows the problem this edit area is about
64 - can deal with issue or episode type problems
65 """
67
68 try:
69 self.problem = kwargs['problem']
70 del kwargs['problem']
71 except KeyError:
72 self.problem = None
73
74 wxgProgressNotesEAPnl.wxgProgressNotesEAPnl.__init__(self, *args, **kwargs)
75
76 dbcfg = gmCfg.cCfgSQL()
77 self.__use_soap_fields = bool(dbcfg.get2 (
78 option = 'horstspace.soap_editor.use_one_field_per_soap_category',
79 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
80 bias = 'user',
81 default = True
82 ))
83
84 self.__soap_fields = [
85 self._TCTRL_Soap,
86 self._TCTRL_sOap,
87 self._TCTRL_soAp,
88 self._TCTRL_soaP
89 ]
90
91 self.__init_ui()
92 self.__register_interests()
93
94 return
95
96
98 if self.__use_soap_fields is False:
99 for field in self.__soap_fields:
100 field.Hide()
101 self._LBL_Soap.Hide()
102 self._PRW_Soap_codes.Hide()
103 self._LBL_sOap.Hide()
104 self._PRW_sOap_codes.Hide()
105 self._LBL_soAp.Hide()
106 self._PRW_soAp_codes.Hide()
107 self._LBL_soaP.Hide()
108 self._PRW_soaP_codes.Hide()
109 self._STC_soap.Show()
110
111 self.refresh_summary()
112 if self.problem is not None:
113 if self.problem['summary'] is None:
114 self._TCTRL_episode_summary.SetValue('')
115 self.refresh_visual_soap()
116
117
121
122
124 self._TCTRL_episode_summary.SetValue('')
125 self._PRW_episode_codes.SetText('', self._PRW_episode_codes.list2data_dict([]))
126 self._LBL_summary.SetLabel(_('Episode synopsis'))
127
128
129 if self.problem is None:
130 return
131
132
133 if self.problem['type'] == 'issue':
134 return
135
136
137 caption = _('Synopsis (%s)') % (
138 gmDateTime.pydt_strftime (
139 self.problem['modified_when'],
140 format = '%B %Y',
141 accuracy = gmDateTime.acc_days
142 )
143 )
144 self._LBL_summary.SetLabel(caption)
145
146 if self.problem['summary'] is not None:
147 self._TCTRL_episode_summary.SetValue(self.problem['summary'].strip())
148
149 val, data = self._PRW_episode_codes.generic_linked_codes2item_dict(self.problem.generic_codes)
150 self._PRW_episode_codes.SetText(val, data)
151
152
172
173
175 self._TCTRL_episode_summary.SetValue('')
176 self._LBL_summary.SetLabel(_('Episode synopsis'))
177 self._PRW_episode_codes.SetText('', self._PRW_episode_codes.list2data_dict([]))
178 self._PNL_visual_soap.clear()
179
180 if self.__use_soap_fields:
181 for field in self.__soap_fields:
182 field.SetValue('')
183 else:
184 self._STC_soap.SetText_from_SOAP()
185
186
209
210
211 - def save(self, emr=None, episode_name_candidates=None, encounter=None):
212
213 if self.empty:
214 return True
215
216
217 if (self.problem is None) or (self.problem['type'] == 'issue'):
218 episode = self.__create_new_episode(emr = emr, episode_name_candidates = episode_name_candidates)
219
220 if episode is None:
221 return False
222
223 else:
224 episode = emr.problem2episode(self.problem)
225
226 if encounter is None:
227 encounter = emr.current_encounter['pk_encounter']
228
229
230
231
232 if self.problem is not None:
233 if self.problem['type'] == 'episode':
234 episode['summary'] = self._TCTRL_episode_summary.GetValue().strip()
235 episode.save()
236
237
238 episode.generic_codes = [ d['data'] for d in self._PRW_episode_codes.GetData() ]
239
240 gmClinNarrative.create_progress_note (
241 soap = self.soap,
242 episode_id = episode['pk_episode'],
243 encounter_id = encounter
244 )
245
246 return True
247
248
249
250
252
253 episode_name_candidates.append(self._TCTRL_episode_summary.GetValue().strip())
254 for candidate in episode_name_candidates:
255 if candidate is None:
256 continue
257 epi_name = candidate.strip().replace('\r', '//').replace('\n', '//')
258 break
259
260 if self.problem is None:
261 msg = _(
262 'Enter a short working name for this new problem\n'
263 '(which will become a new, unassociated episode):\n'
264 )
265 else:
266 issue = emr.problem2issue(self.problem)
267 msg = _(
268 'Enter a short working name for this new\n'
269 'episode under the existing health issue\n'
270 '\n'
271 '"%s":\n'
272 ) % issue['description']
273
274 dlg = wx.TextEntryDialog (
275 self, msg,
276 caption = _('Creating problem (episode) to save notelet under ...'),
277 value = epi_name,
278 style = wx.OK | wx.CANCEL | wx.CENTRE
279 )
280 decision = dlg.ShowModal()
281 if decision != wx.ID_OK:
282 return None
283
284 epi_name = dlg.GetValue().strip()
285 if epi_name == '':
286 gmGuiHelpers.gm_show_error(_('Cannot save a new problem without a name.'), _('saving progress note'))
287 return None
288
289
290 new_episode = emr.add_episode (
291 episode_name = epi_name[:45],
292 pk_health_issue = None,
293 is_open = True,
294 allow_dupes = True
295 )
296 new_episode['summary'] = self._TCTRL_episode_summary.GetValue().strip()
297 new_episode.save()
298
299 if self.problem is not None:
300 issue = emr.problem2issue(self.problem)
301 if not gmEMRStructWidgets.move_episode_to_issue(episode = new_episode, target_issue = issue, save_to_backend = True):
302 gmGuiHelpers.gm_show_warning (
303 _(
304 'The new episode:\n'
305 '\n'
306 ' "%s"\n'
307 '\n'
308 'will remain unassociated despite the editor\n'
309 'having been invoked from the health issue:\n'
310 '\n'
311 ' "%s"'
312 ) % (
313 new_episode['description'],
314 issue['description']
315 ),
316 _('saving progress note')
317 )
318
319 return new_episode
320
321
322
323
330
331
332
333
335 if not self.__use_soap_fields:
336 return self._STC_soap.soap
337
338 soap = {}
339 tmp = self._TCTRL_Soap.GetValue().strip()
340 if tmp != '':
341 soap['s'] = [tmp]
342 tmp = self._TCTRL_sOap.GetValue().strip()
343 if tmp != '':
344 soap['o'] = [tmp]
345 tmp = self._TCTRL_soAp.GetValue().strip()
346 if tmp != '':
347 soap['a'] = [tmp]
348 tmp = self._TCTRL_soaP.GetValue().strip()
349 if tmp != '':
350 soap['p'] = [tmp]
351 return soap
352
353 soap = property(_get_soap, lambda x:x)
354
356 if self.__use_soap_fields:
357 for field in self.__soap_fields:
358 if field.GetValue().strip() != '':
359 return False
360 else:
361 if not self._STC_soap.empty:
362 return False
363
364
365 summary = self._TCTRL_episode_summary.GetValue().strip()
366 if self.problem is None:
367 if summary != '':
368 return False
369 elif self.problem['type'] == 'issue':
370 if summary != '':
371 return False
372 else:
373 if self.problem['summary'] is None:
374 if summary != '':
375 return False
376 else:
377 if summary != self.problem['summary'].strip():
378 return False
379
380
381 new_codes = self._PRW_episode_codes.GetData()
382 if self.problem is None:
383 if len(new_codes) > 0:
384 return False
385 elif self.problem['type'] == 'issue':
386 if len(new_codes) > 0:
387 return False
388 else:
389 old_code_pks = self.problem.generic_codes
390 if len(old_code_pks) != len(new_codes):
391 return False
392 for code in new_codes:
393 if code['data'] not in old_code_pks:
394 return False
395
396 return True
397
398 empty = property(_get_empty, lambda x:x)
399
400
401
402
403 if __name__ == '__main__':
404
405 if len(sys.argv) < 2:
406 sys.exit()
407
408 if sys.argv[1] != 'test':
409 sys.exit()
410
411
418
419
420 test_cProgressNotesEAPnl()
421