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 parent = self,
276 message = msg,
277 caption = _('Creating problem (episode) to save notelet under ...'),
278 defaultValue = epi_name,
279 style = wx.OK | wx.CANCEL | wx.CENTRE
280 )
281 decision = dlg.ShowModal()
282 if decision != wx.ID_OK:
283 return None
284
285 epi_name = dlg.GetValue().strip()
286 if epi_name == '':
287 gmGuiHelpers.gm_show_error(_('Cannot save a new problem without a name.'), _('saving progress note'))
288 return None
289
290
291 new_episode = emr.add_episode (
292 episode_name = epi_name[:45],
293 pk_health_issue = None,
294 is_open = True,
295 allow_dupes = True
296 )
297 new_episode['summary'] = self._TCTRL_episode_summary.GetValue().strip()
298 new_episode.save()
299
300 if self.problem is not None:
301 issue = emr.problem2issue(self.problem)
302 if not gmEMRStructWidgets.move_episode_to_issue(episode = new_episode, target_issue = issue, save_to_backend = True):
303 gmGuiHelpers.gm_show_warning (
304 _(
305 'The new episode:\n'
306 '\n'
307 ' "%s"\n'
308 '\n'
309 'will remain unassociated despite the editor\n'
310 'having been invoked from the health issue:\n'
311 '\n'
312 ' "%s"'
313 ) % (
314 new_episode['description'],
315 issue['description']
316 ),
317 _('saving progress note')
318 )
319
320 return new_episode
321
322
323
324
331
332
333
334
336 if not self.__use_soap_fields:
337 return self._STC_soap.soap
338
339 soap = {}
340 tmp = self._TCTRL_Soap.GetValue().strip()
341 if tmp != '':
342 soap['s'] = [tmp]
343 tmp = self._TCTRL_sOap.GetValue().strip()
344 if tmp != '':
345 soap['o'] = [tmp]
346 tmp = self._TCTRL_soAp.GetValue().strip()
347 if tmp != '':
348 soap['a'] = [tmp]
349 tmp = self._TCTRL_soaP.GetValue().strip()
350 if tmp != '':
351 soap['p'] = [tmp]
352 return soap
353
354 soap = property(_get_soap, lambda x:x)
355
357 if self.__use_soap_fields:
358 for field in self.__soap_fields:
359 if field.GetValue().strip() != '':
360 return False
361 else:
362 if not self._STC_soap.empty:
363 return False
364
365
366 summary = self._TCTRL_episode_summary.GetValue().strip()
367 if self.problem is None:
368 if summary != '':
369 return False
370 elif self.problem['type'] == 'issue':
371 if summary != '':
372 return False
373 else:
374 if self.problem['summary'] is None:
375 if summary != '':
376 return False
377 else:
378 if summary != self.problem['summary'].strip():
379 return False
380
381
382 new_codes = self._PRW_episode_codes.GetData()
383 if self.problem is None:
384 if len(new_codes) > 0:
385 return False
386 elif self.problem['type'] == 'issue':
387 if len(new_codes) > 0:
388 return False
389 else:
390 old_code_pks = self.problem.generic_codes
391 if len(old_code_pks) != len(new_codes):
392 return False
393 for code in new_codes:
394 if code['data'] not in old_code_pks:
395 return False
396
397 return True
398
399 empty = property(_get_empty, lambda x:x)
400
401
402
403
404 if __name__ == '__main__':
405
406 if len(sys.argv) < 2:
407 sys.exit()
408
409 if sys.argv[1] != 'test':
410 sys.exit()
411
412
419
420
421 test_cProgressNotesEAPnl()
422