| Home | Trees | Indices | Help |
|
|---|
|
|
1 """GNUmed patient creation widgets.
2
3 copyright: authors
4 """
5 #============================================================
6 __author__ = "K.Hilbert"
7 __license__ = "GPL v2 or later (details at http://www.gnu.org)"
8
9 import logging
10 import sys
11 import datetime as pydt
12
13
14 import wx
15
16
17 if __name__ == '__main__':
18 sys.path.insert(0, '../../')
19 from Gnumed.pycommon import gmCfg
20 from Gnumed.pycommon import gmPG2
21 from Gnumed.pycommon import gmTools
22 from Gnumed.pycommon import gmDateTime
23 from Gnumed.pycommon import gmDispatcher
24
25 from Gnumed.business import gmPraxis
26 from Gnumed.business import gmPerson
27 from Gnumed.business import gmStaff
28 from Gnumed.business import gmDemographicRecord
29
30 from Gnumed.wxpython import gmEditArea
31 from Gnumed.wxpython import gmGuiHelpers
32 from Gnumed.wxpython import gmEncounterWidgets
33 from Gnumed.wxpython.gmDemographicsWidgets import _validate_dob_field, _validate_tob_field, _empty_dob_allowed
34
35
36 _log = logging.getLogger('gm.patient')
37
38 #============================================================
40
41 if parent is None:
42 parent = wx.GetApp().GetTopWindow()
43
44 if activate: # meaning we will switch away from the current patient if any
45 msg = _(
46 'Before creating a new person review the encounter details\n'
47 'of the patient you just worked on:\n'
48 )
49 gmEncounterWidgets.sanity_check_encounter_of_active_patient(parent = parent, msg = msg)
50
51 msg = _('Edit the current encounter of the patient you are ABOUT TO LEAVE:')
52
53 dbcfg = gmCfg.cCfgSQL()
54
55 def_region = dbcfg.get2 (
56 option = 'person.create.default_region',
57 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
58 bias = 'user'
59 )
60 def_country = None
61
62 if def_region is None:
63 def_country = dbcfg.get2 (
64 option = 'person.create.default_country',
65 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
66 bias = 'user'
67 )
68 else:
69 countries = gmDemographicRecord.get_country_for_region(region = def_region)
70 if len(countries) == 1:
71 def_country = countries[0]['code_country']
72
73 ea = cNewPatientEAPnl(parent, -1, country = def_country, region = def_region)
74 dlg = gmEditArea.cGenericEditAreaDlg2(parent, -1, edit_area = ea, single_entry = True)
75 dlg.SetTitle(_('Adding new person'))
76 ea._PRW_lastname.SetFocus()
77 result = dlg.ShowModal()
78 pat = ea.data
79 dlg.DestroyLater()
80
81 if result != wx.ID_OK:
82 return False
83
84 _log.debug('created new person [%s]', pat.ID)
85
86 if activate:
87 from Gnumed.wxpython import gmPatSearchWidgets
88 gmPatSearchWidgets.set_active_patient(patient = pat)
89
90 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
91
92 return True
93
94 #============================================================
95 from Gnumed.wxGladeWidgets import wxgNewPatientEAPnl
96
97 -class cNewPatientEAPnl(wxgNewPatientEAPnl.wxgNewPatientEAPnl, gmEditArea.cGenericEditAreaMixin):
98
100
101 try:
102 self.default_region = kwargs['region']
103 del kwargs['region']
104 except KeyError:
105 self.default_region = None
106
107 try:
108 self.default_country = kwargs['country']
109 del kwargs['country']
110 except KeyError:
111 self.default_country = None
112
113 wxgNewPatientEAPnl.wxgNewPatientEAPnl.__init__(self, *args, **kwargs)
114 gmEditArea.cGenericEditAreaMixin.__init__(self)
115
116 self.mode = 'new'
117 self.data = None
118 self._address = None
119
120 self.__init_ui()
121 self.__register_interests()
122 #----------------------------------------------------------------
123 # internal helpers
124 #----------------------------------------------------------------
126 self._PRW_lastname.final_regex = '.+'
127 self._PRW_firstnames.final_regex = '.+'
128 self._PRW_address_searcher.selection_only = False
129
130 # only if we would support None on selection_only's:
131 # self._PRW_external_id_type.selection_only = True
132
133 if self.default_country is not None:
134 match = self._PRW_country._data2match(data = self.default_country)
135 if match is not None:
136 self._PRW_country.SetText(value = match['field_label'], data = match['data'])
137
138 if self.default_region is not None:
139 self._PRW_region.SetText(value = self.default_region)
140
141 self._PRW_type.SetText(value = 'home')
142 # FIXME: only use this if member of gm-doctors,
143 # FIXME: other than that check fallback_primary_provider
144 self._PRW_primary_provider.SetData(data = gmStaff.gmCurrentProvider()['pk_staff'])
145
146 self._PRW_lastname.SetFocus()
147 #----------------------------------------------------------------
149 id_type = self._PRW_external_id_type.GetData()
150 if id_type is None:
151 self._LBL_id_exists.SetLabel('')
152 return
153 val = self._TCTRL_external_id_value.GetValue().strip()
154 if val == '':
155 self._LBL_id_exists.SetLabel('')
156 return
157 if gmPerson.external_id_exists(pk_issuer = id_type, value = val) > 0:
158 self._LBL_id_exists.SetLabel(_('ID exists !'))
159 else:
160 self._LBL_id_exists.SetLabel('')
161 #----------------------------------------------------------------
163 lname = self._PRW_lastname.GetValue().strip()
164 if lname == '':
165 self._LBL_person_exists.SetLabel('')
166 return
167
168 dob = self._PRW_dob.GetData()
169 if dob is None:
170 self._LBL_person_exists.SetLabel('')
171 return
172
173 fname = gmTools.none_if(self._PRW_firstnames.GetValue().strip()[:1], '')
174
175 no_of_dupes = gmPerson.get_potential_person_dupes(lastnames = lname, firstnames = fname, dob = dob)
176 if no_of_dupes == 0:
177 lbl = ''
178 elif no_of_dupes == 1:
179 lbl = _('One "%s, %s (%s)" already exists !') % (
180 lname,
181 gmTools.coalesce(fname, '?', '%s %%s. %s' % (gmTools.u_ellipsis, gmTools.u_ellipsis)),
182 gmDateTime.pydt_strftime(dob, '%Y %b %d', 'utf8')
183 )
184 else:
185 lbl = _('%s "%s, %s (%s)" already exist !') % (
186 no_of_dupes,
187 lname,
188 gmTools.coalesce(fname, '?', '%s %%s. %s' % (gmTools.u_ellipsis, gmTools.u_ellipsis)),
189 gmDateTime.pydt_strftime(dob, '%Y %b %d', 'utf8')
190 )
191
192 self._LBL_person_exists.SetLabel(lbl)
193 #----------------------------------------------------------------
195
196 adr = self._PRW_address_searcher.address
197 if adr is None:
198 return True
199
200 if ctrl.GetValue().strip() != adr[field]:
201 wx.CallAfter(self._PRW_address_searcher.SetText, value = '', data = None)
202 return True
203
204 return False
205 #----------------------------------------------------------------
207 adr = self._PRW_address_searcher.address
208 if adr is None:
209 return True
210
211 self._PRW_zip.SetText(value = adr['postcode'], data = adr['postcode'])
212
213 self._PRW_street.SetText(value = adr['street'], data = adr['street'])
214 self._PRW_street.set_context(context = 'zip', val = adr['postcode'])
215
216 self._PRW_urb.SetText(value = adr['urb'], data = adr['urb'])
217 self._PRW_urb.set_context(context = 'zip', val = adr['postcode'])
218
219 self._PRW_region.SetText(value = adr['l10n_region'], data = adr['code_region'])
220 self._PRW_region.set_context(context = 'zip', val = adr['postcode'])
221
222 self._PRW_country.SetText(value = adr['l10n_country'], data = adr['code_country'])
223 self._PRW_country.set_context(context = 'zip', val = adr['postcode'])
224 #----------------------------------------------------------------
226 error = False
227
228 # name fields
229 if self._PRW_lastname.GetValue().strip() == '':
230 error = True
231 gmDispatcher.send(signal = 'statustext', msg = _('Must enter lastname.'))
232 self._PRW_lastname.display_as_valid(False)
233 else:
234 self._PRW_lastname.display_as_valid(True)
235
236 if self._PRW_firstnames.GetValue().strip() == '':
237 error = True
238 gmDispatcher.send(signal = 'statustext', msg = _('Must enter first name.'))
239 self._PRW_firstnames.display_as_valid(False)
240 else:
241 self._PRW_firstnames.display_as_valid(True)
242
243 # gender
244 if self._PRW_gender.GetData() is None:
245 error = True
246 gmDispatcher.send(signal = 'statustext', msg = _('Must select gender.'))
247 self._PRW_gender.display_as_valid(False)
248 else:
249 self._PRW_gender.display_as_valid(True)
250
251 # dob validation
252 if not _validate_dob_field(self._PRW_dob):
253 error = True
254
255 # TOB validation
256 if _validate_tob_field(self._TCTRL_tob):
257 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
258 else:
259 error = True
260 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
261
262 # uniqueness
263 if gmPerson.this_person_exists (
264 self._PRW_lastname.GetValue().strip(),
265 self._PRW_firstnames.GetValue().strip(),
266 self._PRW_dob.GetData(),
267 gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
268 ):
269 error = True
270 self.StatusText = _('Duplicate person. Modify name and/or DOB or use comment to make unique.')
271
272 return (not error)
273 #----------------------------------------------------------------
275
276 # existing address ? if so set other fields
277 if self._PRW_address_searcher.GetData() is not None:
278 wx.CallAfter(self.__set_fields_from_address_searcher)
279 return True
280
281 # must either all contain something or none of them
282 fields_to_fill = (
283 self._TCTRL_number,
284 self._PRW_zip,
285 self._PRW_street,
286 self._PRW_urb,
287 self._PRW_type
288 )
289 no_of_filled_fields = 0
290
291 for field in fields_to_fill:
292 if field.GetValue().strip() != '':
293 no_of_filled_fields += 1
294 field.display_as_valid(True)
295
296 # empty address ?
297 if no_of_filled_fields == 0:
298 if empty_address_is_valid:
299 return True
300 else:
301 return None
302
303 # incompletely filled address ?
304 if no_of_filled_fields != len(fields_to_fill):
305 for field in fields_to_fill:
306 if field.GetValue().strip() == '':
307 field.display_as_valid(False)
308 field.SetFocus()
309 msg = _('To properly create an address, all the related fields must be filled in.')
310 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
311 return False
312
313 # fields which must contain a selected item
314 # FIXME: they must also contain an *acceptable combination* which
315 # FIXME: can only be tested against the database itself ...
316 strict_fields = (
317 self._PRW_type,
318 self._PRW_region,
319 self._PRW_country
320 )
321 error = False
322 for field in strict_fields:
323 if field.GetData() is None:
324 error = True
325 field.display_as_valid(False)
326 field.SetFocus()
327 else:
328 field.display_as_valid(True)
329
330 if error:
331 msg = _('This field must contain an item selected from the dropdown list.')
332 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
333 return False
334
335 return True
336 #----------------------------------------------------------------
338
339 # identity
340 self._PRW_lastname.add_callback_on_lose_focus(self._on_leaving_lastname)
341 self._PRW_firstnames.add_callback_on_lose_focus(self._on_leaving_firstname)
342 self._PRW_dob.add_callback_on_lose_focus(self._on_leaving_dob)
343
344 # address
345 self._PRW_address_searcher.add_callback_on_lose_focus(self._on_leaving_adress_searcher)
346
347 # invalidate address searcher when any field edited
348 self._PRW_street.add_callback_on_lose_focus(self._invalidate_address_searcher)
349 self._TCTRL_number.Bind(wx.EVT_KILL_FOCUS, self._on_leaving_number)
350 self._TCTRL_unit.Bind(wx.EVT_KILL_FOCUS, self._on_leaving_unit)
351 self._PRW_urb.add_callback_on_lose_focus(self._invalidate_address_searcher)
352 self._PRW_region.add_callback_on_lose_focus(self._invalidate_address_searcher)
353
354 self._PRW_zip.add_callback_on_lose_focus(self._on_leaving_zip)
355 self._PRW_country.add_callback_on_lose_focus(self._on_leaving_country)
356
357 self._PRW_external_id_type.add_callback_on_lose_focus(callback = self._on_leaving_ext_id_type)
358 self._TCTRL_external_id_value.add_callback_on_lose_focus(callback = self._on_leaving_ext_id_val)
359
360 #----------------------------------------------------------------
361 # event handlers
362 #----------------------------------------------------------------
365 #----------------------------------------------------------------
368 #----------------------------------------------------------------
371 #----------------------------------------------------------------
373 """Set the gender according to entered firstname.
374
375 Matches are fetched from existing records in backend.
376 """
377 wx.CallAfter(self._refresh_dupe_warning)
378
379 # only set if not already set so as to not
380 # overwrite a change by the user
381 if self._PRW_gender.GetData() is not None:
382 return True
383
384 firstname = self._PRW_firstnames.GetValue().strip()
385 if firstname == '':
386 return True
387
388 gender = gmPerson.map_firstnames2gender(firstnames = firstname)
389 if gender is None:
390 return True
391
392 wx.CallAfter(self._PRW_gender.SetData, gender)
393
394 return True
395 #----------------------------------------------------------------
399 #----------------------------------------------------------------
401 self.__perhaps_invalidate_address_searcher(self._PRW_zip, 'postcode')
402
403 zip_code = gmTools.none_if(self._PRW_zip.GetValue().strip(), '')
404 self._PRW_street.set_context(context = 'zip', val = zip_code)
405 self._PRW_urb.set_context(context = 'zip', val = zip_code)
406 self._PRW_region.set_context(context = 'zip', val = zip_code)
407 self._PRW_country.set_context(context = 'zip', val = zip_code)
408
409 return True
410 #----------------------------------------------------------------
412 self.__perhaps_invalidate_address_searcher(self._PRW_country, 'l10n_country')
413
414 country = gmTools.none_if(self._PRW_country.GetValue().strip(), '')
415 self._PRW_region.set_context(context = 'country', val = country)
416
417 return True
418 #----------------------------------------------------------------
420 if self._TCTRL_number.GetValue().strip() == '':
421 adr = self._PRW_address_searcher.address
422 if adr is None:
423 return True
424 self._TCTRL_number.SetValue(adr['number'])
425 return True
426
427 self.__perhaps_invalidate_address_searcher(self._TCTRL_number, 'number')
428 return True
429 #----------------------------------------------------------------
431 if self._TCTRL_unit.GetValue().strip() == '':
432 adr = self._PRW_address_searcher.address
433 if adr is None:
434 return True
435 self._TCTRL_unit.SetValue(gmTools.coalesce(adr['subunit'], ''))
436 return True
437
438 self.__perhaps_invalidate_address_searcher(self._TCTRL_unit, 'subunit')
439 return True
440 #----------------------------------------------------------------
442 mapping = [
443 (self._PRW_street, 'street'),
444 (self._PRW_urb, 'urb'),
445 (self._PRW_region, 'l10n_region')
446 ]
447 # loop through fields and invalidate address searcher if different
448 for ctrl, field in mapping:
449 if self.__perhaps_invalidate_address_searcher(ctrl, field):
450 return True
451
452 return True
453 #----------------------------------------------------------------
455 if self._PRW_address_searcher.address is None:
456 return True
457
458 wx.CallAfter(self.__set_fields_from_address_searcher)
459 return True
460 #----------------------------------------------------------------
461 # generic Edit Area mixin API
462 #----------------------------------------------------------------
464 if self._PRW_primary_provider.GetValue().strip() == '':
465 self._PRW_primary_provider.display_as_valid(True)
466 else:
467 if self._PRW_primary_provider.GetData() is None:
468 self._PRW_primary_provider.display_as_valid(False)
469 else:
470 self._PRW_primary_provider.display_as_valid(True)
471 return (self.__identity_valid_for_save() and self.__address_valid_for_save(empty_address_is_valid = True))
472 #----------------------------------------------------------------
474
475 if self._PRW_dob.GetValue().strip() == '':
476 if not _empty_dob_allowed():
477 self._PRW_dob.display_as_valid(False)
478 self._PRW_dob.SetFocus()
479 return False
480
481 # identity
482 new_identity = gmPerson.create_identity (
483 gender = self._PRW_gender.GetData(),
484 dob = self._PRW_dob.GetData(),
485 lastnames = self._PRW_lastname.GetValue().strip(),
486 firstnames = self._PRW_firstnames.GetValue().strip(),
487 comment = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), '')
488 )
489 if new_identity is None:
490 gmGuiHelpers.gm_show_error (
491 title = _('Creating person.'),
492 error = _(
493 'Failed to create person. Does it already exist ?\n'
494 '\n'
495 'If so you need to add a unique comment.'
496 )
497 )
498 return False
499 _log.info('identity created: %s' % new_identity)
500
501 new_identity['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
502 val = self._TCTRL_tob.GetValue().strip()
503 if val != '':
504 new_identity['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
505 new_identity['title'] = gmTools.none_if(self._PRW_title.GetValue().strip())
506
507 prov = self._PRW_primary_provider.GetData()
508 if prov is not None:
509 new_identity['pk_primary_provider'] = prov
510 #new_identity['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), '')
511 new_identity.save()
512 _log.info('new identity updated: %s' % new_identity)
513
514 new_identity.set_nickname(nickname = gmTools.none_if(self._PRW_nickname.GetValue().strip(), ''))
515 _log.info('nickname set on new identity: %s' % new_identity)
516
517 # address
518 # if we reach this the address cannot be completely empty
519 is_valid = self.__address_valid_for_save(empty_address_is_valid = False)
520 if is_valid is True:
521 # because we currently only check for non-emptiness
522 # we must still deal with database errors
523 try:
524 new_identity.link_address (
525 number = self._TCTRL_number.GetValue().strip(),
526 street = self._PRW_street.GetValue().strip(),
527 postcode = self._PRW_zip.GetValue().strip(),
528 urb = self._PRW_urb.GetValue().strip(),
529 region_code = self._PRW_region.GetData(),
530 country_code = self._PRW_country.GetData(),
531 subunit = gmTools.none_if(self._TCTRL_unit.GetValue().strip(), ''),
532 id_type = self._PRW_type.GetData()
533 )
534 except gmPG2.dbapi.InternalError:
535 _log.debug('number: >>%s<<', self._TCTRL_number.GetValue().strip())
536 _log.debug('(sub)unit: >>%s<<', self._TCTRL_unit.GetValue().strip())
537 _log.debug('street: >>%s<<', self._PRW_street.GetValue().strip())
538 _log.debug('postcode: >>%s<<', self._PRW_zip.GetValue().strip())
539 _log.debug('urb: >>%s<<', self._PRW_urb.GetValue().strip())
540 _log.debug('region: >>%s<<', self._PRW_region.GetData().strip())
541 _log.debug('country: >>%s<<', self._PRW_country.GetData().strip())
542 _log.exception('cannot link address')
543 gmGuiHelpers.gm_show_error (
544 aTitle = _('Saving address'),
545 aMessage = _(
546 'Cannot save this address.\n'
547 '\n'
548 'You will have to add it via the Demographics plugin.\n'
549 )
550 )
551 elif is_valid is False:
552 gmGuiHelpers.gm_show_error (
553 aTitle = _('Saving address'),
554 aMessage = _(
555 'Address not saved.\n'
556 '\n'
557 'You will have to add it via the Demographics plugin.\n'
558 )
559 )
560 # else it is None which means empty address which we ignore
561
562 # phone
563 channel_name = self._PRW_channel_type.GetValue().strip()
564 pk_channel_type = self._PRW_channel_type.GetData()
565 if pk_channel_type is None:
566 if channel_name == '':
567 channel_name = 'homephone'
568 new_identity.link_comm_channel (
569 comm_medium = channel_name,
570 pk_channel_type = pk_channel_type,
571 url = gmTools.none_if(self._TCTRL_phone.GetValue().strip(), ''),
572 is_confidential = False
573 )
574
575 # external ID
576 pk_type = self._PRW_external_id_type.GetData()
577 id_value = self._TCTRL_external_id_value.GetValue().strip()
578 if (pk_type is not None) and (id_value != ''):
579 new_identity.add_external_id(value = id_value, pk_type = pk_type)
580
581 # occupation
582 new_identity.link_occupation (
583 occupation = gmTools.none_if(self._PRW_occupation.GetValue().strip(), '')
584 )
585
586 self.data = new_identity
587 return True
588 #----------------------------------------------------------------
591 #----------------------------------------------------------------
595 #----------------------------------------------------------------
598 #----------------------------------------------------------------
601
602 #============================================================
603 # main
604 #------------------------------------------------------------
605 if __name__ == "__main__":
606
607 if len(sys.argv) < 2:
608 sys.exit()
609
610 if sys.argv[1] != 'test':
611 sys.exit()
612
613 # from Gnumed.pycommon import gmPG2
614 # from Gnumed.pycommon import gmI18N
615 # gmI18N.activate_locale()
616 # gmI18N.install_domain()
617
618 #--------------------------------------------------------
619 #test_org_unit_prw()
620
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Sat Feb 29 02:55:27 2020 | http://epydoc.sourceforge.net |