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.gmDemographicsWidgets import _validate_dob_field, _validate_tob_field
33
34
35 _log = logging.getLogger('gm.patient')
36
37
39
40 dbcfg = gmCfg.cCfgSQL()
41
42 def_region = dbcfg.get2 (
43 option = u'person.create.default_region',
44 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
45 bias = u'user'
46 )
47 def_country = None
48
49 if def_region is None:
50 def_country = dbcfg.get2 (
51 option = u'person.create.default_country',
52 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace,
53 bias = u'user'
54 )
55 else:
56 countries = gmDemographicRecord.get_country_for_region(region = def_region)
57 if len(countries) == 1:
58 def_country = countries[0]['code_country']
59
60 if parent is None:
61 parent = wx.GetApp().GetTopWindow()
62
63 ea = cNewPatientEAPnl(parent = parent, id = -1, country = def_country, region = def_region)
64 dlg = gmEditArea.cGenericEditAreaDlg2(parent = parent, id = -1, edit_area = ea, single_entry = True)
65 dlg.SetTitle(_('Adding new person'))
66 ea._PRW_lastname.SetFocus()
67 result = dlg.ShowModal()
68 pat = ea.data
69 dlg.Destroy()
70
71 if result != wx.ID_OK:
72 return False
73
74 _log.debug('created new person [%s]', pat.ID)
75
76 if activate:
77 from Gnumed.wxpython import gmPatSearchWidgets
78 gmPatSearchWidgets.set_active_patient(patient = pat)
79
80 gmDispatcher.send(signal = 'display_widget', name = 'gmNotebookedPatientEditionPlugin')
81
82 return True
83
84
85 from Gnumed.wxGladeWidgets import wxgNewPatientEAPnl
86
87 -class cNewPatientEAPnl(wxgNewPatientEAPnl.wxgNewPatientEAPnl, gmEditArea.cGenericEditAreaMixin):
88
90
91 try:
92 self.default_region = kwargs['region']
93 del kwargs['region']
94 except KeyError:
95 self.default_region = None
96
97 try:
98 self.default_country = kwargs['country']
99 del kwargs['country']
100 except KeyError:
101 self.default_country = None
102
103 wxgNewPatientEAPnl.wxgNewPatientEAPnl.__init__(self, *args, **kwargs)
104 gmEditArea.cGenericEditAreaMixin.__init__(self)
105
106 self.mode = 'new'
107 self.data = None
108 self._address = None
109
110 self.__init_ui()
111 self.__register_interests()
112
113
114
116 self._PRW_lastname.final_regex = '.+'
117 self._PRW_firstnames.final_regex = '.+'
118 self._PRW_address_searcher.selection_only = False
119
120
121
122
123 if self.default_country is not None:
124 match = self._PRW_country._data2match(data = self.default_country)
125 if match is not None:
126 self._PRW_country.SetText(value = match['field_label'], data = match['data'])
127
128 if self.default_region is not None:
129 self._PRW_region.SetText(value = self.default_region)
130
131 self._PRW_type.SetText(value = u'home')
132
133
134 self._PRW_primary_provider.SetData(data = gmStaff.gmCurrentProvider()['pk_staff'])
135
136 self._PRW_lastname.SetFocus()
137
139 id_type = self._PRW_external_id_type.GetData()
140 if id_type is None:
141 self._LBL_id_exists.SetLabel(u'')
142 return
143 val = self._TCTRL_external_id_value.GetValue().strip()
144 if val == u'':
145 self._LBL_id_exists.SetLabel(u'')
146 return
147 if gmPerson.external_id_exists(pk_issuer = id_type, value = val) > 0:
148 self._LBL_id_exists.SetLabel(_('ID exists !'))
149 else:
150 self._LBL_id_exists.SetLabel(u'')
151
153 lname = self._PRW_lastname.GetValue().strip()
154 if lname == u'':
155 self._LBL_person_exists.SetLabel(u'')
156 return
157
158 dob = self._PRW_dob.GetData()
159 if dob is None:
160 self._LBL_person_exists.SetLabel(u'')
161 return
162
163 fname = gmTools.none_if(self._PRW_firstnames.GetValue().strip()[:1], u'')
164
165 no_of_dupes = gmPerson.person_exists(lastnames = lname, firstnames = fname, dob = dob)
166 if no_of_dupes == 0:
167 lbl = u''
168 elif no_of_dupes == 1:
169 lbl = _('One "%s, %s (%s)" already exists !') % (
170 lname,
171 gmTools.coalesce(fname, u'?', u'%s %%s. %s' % (gmTools.u_ellipsis, gmTools.u_ellipsis)),
172 gmDateTime.pydt_strftime(dob, '%Y %b %d', 'utf8')
173 )
174 else:
175 lbl = _('%s "%s, %s (%s)" already exist !') % (
176 no_of_dupes,
177 lname,
178 gmTools.coalesce(fname, u'?', u'%s %%s. %s' % (gmTools.u_ellipsis, gmTools.u_ellipsis)),
179 gmDateTime.pydt_strftime(dob, '%Y %b %d', 'utf8')
180 )
181
182 self._LBL_person_exists.SetLabel(lbl)
183
185
186 adr = self._PRW_address_searcher.address
187 if adr is None:
188 return True
189
190 if ctrl.GetValue().strip() != adr[field]:
191 wx.CallAfter(self._PRW_address_searcher.SetText, value = u'', data = None)
192 return True
193
194 return False
195
197 adr = self._PRW_address_searcher.address
198 if adr is None:
199 return True
200
201 self._PRW_zip.SetText(value = adr['postcode'], data = adr['postcode'])
202
203 self._PRW_street.SetText(value = adr['street'], data = adr['street'])
204 self._PRW_street.set_context(context = u'zip', val = adr['postcode'])
205
206 self._PRW_urb.SetText(value = adr['urb'], data = adr['urb'])
207 self._PRW_urb.set_context(context = u'zip', val = adr['postcode'])
208
209 self._PRW_region.SetText(value = adr['l10n_state'], data = adr['code_state'])
210 self._PRW_region.set_context(context = u'zip', val = adr['postcode'])
211
212 self._PRW_country.SetText(value = adr['l10n_country'], data = adr['code_country'])
213 self._PRW_country.set_context(context = u'zip', val = adr['postcode'])
214
216 error = False
217
218
219 if self._PRW_lastname.GetValue().strip() == u'':
220 error = True
221 gmDispatcher.send(signal = 'statustext', msg = _('Must enter lastname.'))
222 self._PRW_lastname.display_as_valid(False)
223 else:
224 self._PRW_lastname.display_as_valid(True)
225
226 if self._PRW_firstnames.GetValue().strip() == '':
227 error = True
228 gmDispatcher.send(signal = 'statustext', msg = _('Must enter first name.'))
229 self._PRW_firstnames.display_as_valid(False)
230 else:
231 self._PRW_firstnames.display_as_valid(True)
232
233
234 if self._PRW_gender.GetData() is None:
235 error = True
236 gmDispatcher.send(signal = 'statustext', msg = _('Must select gender.'))
237 self._PRW_gender.display_as_valid(False)
238 else:
239 self._PRW_gender.display_as_valid(True)
240
241
242 if not _validate_dob_field(self._PRW_dob):
243 error = True
244
245
246 if _validate_tob_field(self._TCTRL_tob):
247 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = True)
248 else:
249 error = True
250 self.display_ctrl_as_valid(ctrl = self._TCTRL_tob, valid = False)
251
252 return (not error)
253
255
256
257 if self._PRW_address_searcher.GetData() is not None:
258 wx.CallAfter(self.__set_fields_from_address_searcher)
259 return True
260
261
262 fields_to_fill = (
263 self._TCTRL_number,
264 self._PRW_zip,
265 self._PRW_street,
266 self._PRW_urb,
267 self._PRW_type
268 )
269 no_of_filled_fields = 0
270
271 for field in fields_to_fill:
272 if field.GetValue().strip() != u'':
273 no_of_filled_fields += 1
274 field.display_as_valid(True)
275
276
277 if no_of_filled_fields == 0:
278 if empty_address_is_valid:
279 return True
280 else:
281 return None
282
283
284 if no_of_filled_fields != len(fields_to_fill):
285 for field in fields_to_fill:
286 if field.GetValue().strip() == u'':
287 field.display_as_valid(False)
288 field.SetFocus()
289 msg = _('To properly create an address, all the related fields must be filled in.')
290 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
291 return False
292
293
294
295
296 strict_fields = (
297 self._PRW_type,
298 self._PRW_region,
299 self._PRW_country
300 )
301 error = False
302 for field in strict_fields:
303 if field.GetData() is None:
304 error = True
305 field.display_as_valid(False)
306 field.SetFocus()
307 else:
308 field.display_as_valid(True)
309
310 if error:
311 msg = _('This field must contain an item selected from the dropdown list.')
312 gmGuiHelpers.gm_show_error(msg, _('Required fields'))
313 return False
314
315 return True
316
339
340
341
342
344 wx.CallAfter(self._refresh_ext_id_warning)
345
347 wx.CallAfter(self._refresh_ext_id_warning)
348
350 wx.CallAfter(self._refresh_dupe_warning)
351
353 """Set the gender according to entered firstname.
354
355 Matches are fetched from existing records in backend.
356 """
357 wx.CallAfter(self._refresh_dupe_warning)
358
359
360
361 if self._PRW_gender.GetData() is not None:
362 return True
363
364 firstname = self._PRW_firstnames.GetValue().strip()
365 if firstname == u'':
366 return True
367
368 gender = gmPerson.map_firstnames2gender(firstnames = firstname)
369 if gender is None:
370 return True
371
372 wx.CallAfter(self._PRW_gender.SetData, gender)
373
374 return True
375
377 wx.CallAfter(self._refresh_dupe_warning)
378
380 self.__perhaps_invalidate_address_searcher(self._PRW_zip, 'postcode')
381
382 zip_code = gmTools.none_if(self._PRW_zip.GetValue().strip(), u'')
383 self._PRW_street.set_context(context = u'zip', val = zip_code)
384 self._PRW_urb.set_context(context = u'zip', val = zip_code)
385 self._PRW_region.set_context(context = u'zip', val = zip_code)
386 self._PRW_country.set_context(context = u'zip', val = zip_code)
387
388 return True
389
391 self.__perhaps_invalidate_address_searcher(self._PRW_country, 'l10n_country')
392
393 country = gmTools.none_if(self._PRW_country.GetValue().strip(), u'')
394 self._PRW_region.set_context(context = u'country', val = country)
395
396 return True
397
399 if self._TCTRL_number.GetValue().strip() == u'':
400 adr = self._PRW_address_searcher.address
401 if adr is None:
402 return True
403 self._TCTRL_number.SetValue(adr['number'])
404 return True
405
406 self.__perhaps_invalidate_address_searcher(self._TCTRL_number, 'number')
407 return True
408
410 if self._TCTRL_unit.GetValue().strip() == u'':
411 adr = self._PRW_address_searcher.address
412 if adr is None:
413 return True
414 self._TCTRL_unit.SetValue(gmTools.coalesce(adr['subunit'], u''))
415 return True
416
417 self.__perhaps_invalidate_address_searcher(self._TCTRL_unit, 'subunit')
418 return True
419
421 mapping = [
422 (self._PRW_street, 'street'),
423 (self._PRW_urb, 'urb'),
424 (self._PRW_region, 'l10n_state')
425 ]
426
427 for ctrl, field in mapping:
428 if self.__perhaps_invalidate_address_searcher(ctrl, field):
429 return True
430
431 return True
432
434 if self._PRW_address_searcher.address is None:
435 return True
436
437 wx.CallAfter(self.__set_fields_from_address_searcher)
438 return True
439
440
441
443 if self._PRW_primary_provider.GetValue().strip() == u'':
444 self._PRW_primary_provider.display_as_valid(True)
445 else:
446 if self._PRW_primary_provider.GetData() is None:
447 self._PRW_primary_provider.display_as_valid(False)
448 else:
449 self._PRW_primary_provider.display_as_valid(True)
450 return (self.__identity_valid_for_save() and self.__address_valid_for_save(empty_address_is_valid = True))
451
453
454 if self._PRW_dob.GetValue().strip() == u'':
455 if not _empty_dob_allowed():
456 self._PRW_dob.display_as_valid(False)
457 self._PRW_dob.SetFocus()
458 return False
459
460
461 new_identity = gmPerson.create_identity (
462 gender = self._PRW_gender.GetData(),
463 dob = self._PRW_dob.GetData(),
464 lastnames = self._PRW_lastname.GetValue().strip(),
465 firstnames = self._PRW_firstnames.GetValue().strip()
466 )
467 _log.debug('identity created: %s' % new_identity)
468
469 new_identity['dob_is_estimated'] = self._CHBOX_estimated_dob.GetValue()
470 val = self._TCTRL_tob.GetValue().strip()
471 if val != u'':
472 new_identity['tob'] = pydt.time(int(val[:2]), int(val[3:5]))
473 new_identity['title'] = gmTools.none_if(self._PRW_title.GetValue().strip())
474 new_identity.set_nickname(nickname = gmTools.none_if(self._PRW_nickname.GetValue().strip(), u''))
475
476 prov = self._PRW_primary_provider.GetData()
477 if prov is not None:
478 new_identity['pk_primary_provider'] = prov
479 new_identity['comment'] = gmTools.none_if(self._TCTRL_comment.GetValue().strip(), u'')
480 new_identity.save()
481
482
483
484 is_valid = self.__address_valid_for_save(empty_address_is_valid = False)
485 if is_valid is True:
486
487
488 try:
489 new_identity.link_address (
490 number = self._TCTRL_number.GetValue().strip(),
491 street = self._PRW_street.GetValue().strip(),
492 postcode = self._PRW_zip.GetValue().strip(),
493 urb = self._PRW_urb.GetValue().strip(),
494 state = self._PRW_region.GetData(),
495 country = self._PRW_country.GetData(),
496 subunit = gmTools.none_if(self._TCTRL_unit.GetValue().strip(), u''),
497 id_type = self._PRW_type.GetData()
498 )
499 except gmPG2.dbapi.InternalError:
500 _log.debug('number: >>%s<<', self._TCTRL_number.GetValue().strip())
501 _log.debug('(sub)unit: >>%s<<', self._TCTRL_unit.GetValue().strip())
502 _log.debug('street: >>%s<<', self._PRW_street.GetValue().strip())
503 _log.debug('postcode: >>%s<<', self._PRW_zip.GetValue().strip())
504 _log.debug('urb: >>%s<<', self._PRW_urb.GetValue().strip())
505 _log.debug('state: >>%s<<', self._PRW_region.GetData().strip())
506 _log.debug('country: >>%s<<', self._PRW_country.GetData().strip())
507 _log.exception('cannot link address')
508 gmGuiHelpers.gm_show_error (
509 aTitle = _('Saving address'),
510 aMessage = _(
511 'Cannot save this address.\n'
512 '\n'
513 'You will have to add it via the Demographics plugin.\n'
514 )
515 )
516 elif is_valid is False:
517 gmGuiHelpers.gm_show_error (
518 aTitle = _('Saving address'),
519 aMessage = _(
520 'Address not saved.\n'
521 '\n'
522 'You will have to add it via the Demographics plugin.\n'
523 )
524 )
525
526
527
528 channel_name = self._PRW_channel_type.GetValue().strip()
529 pk_channel_type = self._PRW_channel_type.GetData()
530 if pk_channel_type is None:
531 if channel_name == u'':
532 channel_name = u'homephone'
533 new_identity.link_comm_channel (
534 comm_medium = channel_name,
535 pk_channel_type = pk_channel_type,
536 url = gmTools.none_if(self._TCTRL_phone.GetValue().strip(), u''),
537 is_confidential = False
538 )
539
540
541 pk_type = self._PRW_external_id_type.GetData()
542 id_value = self._TCTRL_external_id_value.GetValue().strip()
543 if (pk_type is not None) and (id_value != u''):
544 new_identity.add_external_id(value = id_value, pk_type = pk_type)
545
546
547 new_identity.link_occupation (
548 occupation = gmTools.none_if(self._PRW_occupation.GetValue().strip(), u'')
549 )
550
551 self.data = new_identity
552 return True
553
555 raise NotImplementedError('[%s]: not expected to be used' % self.__class__.__name__)
556
560
563
565 raise NotImplementedError('[%s]: not expected to be used' % self.__class__.__name__)
566
567
568
569
570 if __name__ == "__main__":
571
572 if len(sys.argv) < 2:
573 sys.exit()
574
575 if sys.argv[1] != u'test':
576 sys.exit()
577
578
579
580
581
582
583
584
585