| Home | Trees | Indices | Help |
|
|---|
|
|
1 # -*- coding: utf-8 -*-
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 # new problem ?
129 if self.problem is None:
130 return
131
132 # issue-level problem ?
133 if self.problem['type'] == 'issue':
134 return
135
136 # episode-level problem
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 #--------------------------------------------------------
154 if self.problem is None:
155 self._PNL_visual_soap.refresh(document_folder = None)
156 return
157
158 if self.problem['type'] == 'issue':
159 self._PNL_visual_soap.refresh(document_folder = None)
160 return
161
162 if self.problem['type'] == 'episode':
163 pat = gmPerson.gmCurrentPatient()
164 doc_folder = pat.get_document_folder()
165 emr = pat.emr
166 self._PNL_visual_soap.refresh (
167 document_folder = doc_folder,
168 episodes = [self.problem['pk_episode']],
169 encounter = emr.active_encounter['pk_encounter']
170 )
171 return
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 #--------------------------------------------------------
188 fname, discard_unmodified = gmVisualProgressNoteWidgets.select_visual_progress_note_template(parent = self)
189 if fname is None:
190 return False
191
192 if self.problem is None:
193 issue = None
194 episode = None
195 elif self.problem['type'] == 'issue':
196 issue = self.problem['pk_health_issue']
197 episode = None
198 else:
199 issue = self.problem['pk_health_issue']
200 episode = gmEMRStructItems.problem2episode(self.problem)
201
202 wx.CallAfter (
203 gmVisualProgressNoteWidgets.edit_visual_progress_note,
204 filename = fname,
205 episode = episode,
206 discard_unmodified = discard_unmodified,
207 health_issue = issue
208 )
209
210 #--------------------------------------------------------
212
213 if self.empty:
214 return True
215
216 # new episode (standalone=unassociated or new-in-issue)
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 # user cancelled
220 if episode is None:
221 return False
222 # existing episode
223 else:
224 episode = emr.problem2episode(self.problem)
225
226 if encounter is None:
227 encounter = emr.current_encounter['pk_encounter']
228
229 # set summary but only if not already set above for a
230 # newly created episode (either standalone or within
231 # a health issue)
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 # codes for episode
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 # internal helpers
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 # create episode
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 # this ensures we get a new episode even if a same-name one already exists
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 # event handling
323 #--------------------------------------------------------
325 if self.__use_soap_fields:
326 for field in self.__soap_fields:
327 self.bind_expando_layout_event(field)
328 self.bind_expando_layout_event(self._TCTRL_episode_summary)
329 gmDispatcher.connect(signal = 'blobs.doc_obj_mod_db', receiver = self.refresh_visual_soap)
330
331 #--------------------------------------------------------
332 # properties
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 # summary
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 # codes
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 # main
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 #----------------------------------------
413 pat = gmPersonSearch.ask_for_patient()
414 application = wx.PyWidgetTester(size=(800,500))
415 soap_input = cProgressNotesEAPnl(application.frame, -1)
416 application.frame.Show(True)
417 application.MainLoop()
418 #----------------------------------------
419
420 test_cProgressNotesEAPnl()
421
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Feb 29 02:55:27 2020 | http://epydoc.sourceforge.net |