1
2 """GNUmed demographics object.
3
4 This is a patient object intended to let a useful client-side
5 API crystallize from actual use in true XP fashion.
6
7 license: GPL v2 or later
8 """
9
10 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>, I.Haywood <ihaywood@gnu.org>"
11
12
13 import sys
14 import os
15 import os.path
16 import logging
17 import urllib.parse
18
19
20
21 if __name__ == '__main__':
22 sys.path.insert(0, '../../')
23 from Gnumed.pycommon import gmDispatcher
24 from Gnumed.pycommon import gmBusinessDBObject
25 from Gnumed.pycommon import gmPG2
26 from Gnumed.pycommon import gmTools
27
28
29 _log = logging.getLogger('gm.business')
30
31
32
33
35 cmd = """
36 SELECT *
37 FROM dem.v_person_jobs
38 WHERE pk_identity = %(pk)s
39 ORDER BY l10n_occupation
40 """
41 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_identity}}])
42 return rows
43
44
45
46 _SQL_get_tag_image = "SELECT * FROM ref.v_tag_images_no_data WHERE %s"
47
48 -class cTagImage(gmBusinessDBObject.cBusinessDBObject):
49
50 _cmd_fetch_payload = _SQL_get_tag_image % "pk_tag_image = %s"
51 _cmds_store_payload = [
52 """
53 UPDATE ref.tag_image SET
54 description = gm.nullify_empty_string(%(description)s),
55 filename = gm.nullify_empty_string(%(filename)s)
56 WHERE
57 pk = %(pk_tag_image)s
58 AND
59 xmin = %(xmin_tag_image)s
60 RETURNING
61 pk as pk_tag_image,
62 xmin as xmin_tag_image
63 """
64 ]
65 _updatable_fields = ['description', 'filename']
66
68
69 if self._payload[self._idx['size']] == 0:
70 return None
71
72 if filename is None:
73 suffix = None
74
75 if self._payload[self._idx['filename']] is not None:
76 name, suffix = os.path.splitext(self._payload[self._idx['filename']])
77 suffix = suffix.strip()
78 if suffix == '':
79 suffix = None
80
81 filename = gmTools.get_unique_filename (
82 prefix = 'gm-tag_image-',
83 suffix = suffix
84 )
85
86 success = gmPG2.bytea2file (
87 data_query = {
88 'cmd': 'SELECT substring(image from %(start)s for %(size)s) FROM ref.tag_image WHERE pk = %(pk)s',
89 'args': {'pk': self.pk_obj}
90 },
91 filename = filename,
92 chunk_size = aChunkSize,
93 data_size = self._payload[self._idx['size']]
94 )
95
96 if success:
97 return filename
98
99 return None
100
102
103 if not (os.access(filename, os.R_OK) and os.path.isfile(filename)):
104 _log.error('[%s] is not a readable file' % filename)
105 return False
106
107 gmPG2.file2bytea (
108 query = "UPDATE ref.tag_image SET image = %(data)s::bytea WHERE pk = %(pk)s",
109 filename = filename,
110 args = {'pk': self.pk_obj}
111 )
112
113
114 self.refetch_payload()
115 return True
116
118 if order_by is None:
119 order_by = 'true'
120 else:
121 order_by = 'true ORDER BY %s' % order_by
122 cmd = _SQL_get_tag_image % order_by
123 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
124 if return_pks:
125 return [ r['pk_tag_image'] for r in rows ]
126 return [ cTagImage(row = {'data': r, 'idx': idx, 'pk_field': 'pk_tag_image'}) for r in rows ]
127
128
130
131 args = {'desc': description, 'img': ''}
132 cmd = """
133 INSERT INTO ref.tag_image (
134 description,
135 image
136 ) VALUES (
137 %(desc)s,
138 %(img)s::bytea
139 )
140 RETURNING pk
141 """
142 rows, idx = gmPG2.run_rw_queries (
143 link_obj = link_obj,
144 queries = [{'cmd': cmd, 'args': args}],
145 end_tx = True,
146 return_data = True,
147 get_col_idx = False
148 )
149
150 return cTagImage(aPK_obj = rows[0]['pk'])
151
153 args = {'pk': tag_image}
154 cmd = """
155 DELETE FROM ref.tag_image
156 WHERE
157 pk = %(pk)s
158 AND
159 NOT EXISTS (
160 SELECT 1
161 FROM dem.identity_tag
162 WHERE fk_tag = %(pk)s
163 LIMIT 1
164 )
165 RETURNING 1
166 """
167 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True)
168 if len(rows) == 0:
169 return False
170 return True
171
172
173 _SQL_get_person_tags = """SELECT * FROM dem.v_identity_tags WHERE %s"""
174
175 -class cPersonTag(gmBusinessDBObject.cBusinessDBObject):
176
177 _cmd_fetch_payload = _SQL_get_person_tags % "pk_identity_tag = %s"
178 _cmds_store_payload = [
179 """
180 UPDATE dem.identity_tag SET
181 fk_tag = %(pk_tag_image)s,
182 comment = gm.nullify_empty_string(%(comment)s)
183 WHERE
184 pk = %(pk_identity_tag)s
185 AND
186 xmin = %(xmin_identity_tag)s
187 RETURNING
188 pk as pk_identity_tag,
189 xmin as xmin_identity_tag
190 """
191 ]
192 _updatable_fields = ['fk_tag', 'comment']
193
195
196 if self._payload[self._idx['image_size']] == 0:
197 return None
198
199 if filename is None:
200 suffix = None
201
202 if self._payload[self._idx['filename']] is not None:
203 name, suffix = os.path.splitext(self._payload[self._idx['filename']])
204 suffix = suffix.strip()
205 if suffix == '':
206 suffix = None
207
208 filename = gmTools.get_unique_filename (
209 prefix = 'gm-person_tag-',
210 suffix = suffix
211 )
212
213 exported = gmPG2.bytea2file (
214 data_query = {
215 'cmd': 'SELECT substring(image from %(start)s for %(size)s) FROM ref.tag_image WHERE pk = %(pk)s',
216 'args': {'pk': self._payload[self._idx['pk_tag_image']]}
217 },
218 filename = filename,
219 chunk_size = aChunkSize,
220 data_size = self._payload[self._idx['image_size']]
221 )
222 if exported:
223 return filename
224
225 return None
226
227
228
229
231 cmd = """
232 SELECT
233 _(name) AS l10n_country, name, code, deprecated
234 FROM dem.country
235 ORDER BY l10n_country"""
236 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
237 return rows
238
239
241 cmd = """
242 SELECT code_country, l10n_country FROM dem.v_region WHERE lower(l10n_region) = lower(%(region)s)
243 union
244 SELECT code_country, l10n_country FROM dem.v_region WHERE lower(region) = lower(%(region)s)
245 """
246 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'region': region}}])
247 return rows
248
249
251 cmd = """
252 SELECT code FROM dem.country WHERE lower(_(name)) = lower(%(country)s)
253 UNION
254 SELECT code FROM dem.country WHERE lower(name) = lower(%(country)s)
255 """
256 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': {'country': country}}], get_col_idx = False)
257 if len(rows) == 0:
258 return None
259 return rows[0][0]
260
261
263
264 args = {'urb': urb, 'zip': zip, 'region': region}
265 cmd = """(
266 -- find by using all known details
267 SELECT
268 1 AS rank,
269 country,
270 l10n_country,
271 code_country
272 FROM dem.v_urb WHERE
273 postcode_urb = %(zip)s
274 AND
275 lower(urb) = lower(%(urb)s)
276 AND
277 (
278 (lower(region) = lower(coalesce(%(region)s, 'state/territory/province/region not available')))
279 OR
280 (lower(l10n_region) = lower(coalesce(%(region)s, _('state/territory/province/region not available'))))
281 )
282
283 ) UNION (
284
285 -- find by using zip/urb
286 SELECT
287 2 AS rank,
288 country,
289 l10n_country,
290 code_country
291 FROM dem.v_urb WHERE
292 postcode_urb = %(zip)s
293 AND
294 lower(urb) = lower(%(urb)s)
295
296 ) UNION (
297
298 -- find by using zip/region
299 SELECT
300 2 AS rank,
301 country,
302 l10n_country,
303 code_country
304 FROM dem.v_urb WHERE
305 postcode_urb = %(zip)s
306 AND
307 (
308 (lower(region) = lower(%(region)s))
309 OR
310 (lower(l10n_region) = lower(%(region)s))
311 )
312
313 ) UNION (
314
315 -- find by using urb/region
316 SELECT
317 2 AS rank,
318 country,
319 l10n_country,
320 code_country
321 FROM dem.v_urb WHERE
322 lower(urb) = lower(%(urb)s)
323 AND
324 ((lower(region) = lower(%(region)s))
325 OR
326 (lower(l10n_region) = lower(%(region)s)))
327
328 ) UNION (
329
330 -- find by region
331 SELECT
332 2 AS rank,
333 country,
334 l10n_country,
335 code_country
336 FROM dem.v_region WHERE
337 lower(region) = lower(%(region)s)
338 OR
339 lower(l10n_region) = lower(%(region)s)
340
341 ) ORDER BY rank"""
342
343 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
344 if len(rows) == 0:
345 _log.debug('zip [%s] / urb [%s] / region [%s] => ??', zip, urb, region)
346 return None
347 if len(rows) > 2:
348 _log.debug('zip [%s] / urb [%s] / region [%s] => [%s]', zip, urb, region, rows)
349 return None
350 country = rows[0]
351 _log.debug('zip [%s] / urb [%s] / region [%s] => [%s]', zip, urb, region, country)
352 return country
353
354
356
357 args = {'urb': urb, 'zip': zip, 'country': country, 'country_code': country_code}
358 cmd = """(
359 -- find by using all known details
360 SELECT
361 1 AS rank,
362 region,
363 l10n_region,
364 code_region
365 FROM dem.v_urb WHERE
366 postcode_urb = %(zip)s
367 AND
368 lower(urb) = lower(%(urb)s)
369 AND
370 (
371 (lower(country) = lower(%(country)s))
372 OR
373 (lower(l10n_country) = lower(%(country)s))
374 OR
375 (code_country = %(country_code)s)
376 )
377
378 ) UNION (
379
380 -- find by zip / urb
381 SELECT
382 2 AS rank,
383 region,
384 l10n_region,
385 code_region
386 FROM dem.v_urb WHERE
387 postcode_urb = %(zip)s
388 AND
389 lower(urb) = lower(%(urb)s)
390
391 ) UNION (
392
393 -- find by zip / country
394 SELECT
395 2 AS rank,
396 region,
397 l10n_region,
398 code_region
399 FROM dem.v_urb WHERE
400 postcode_urb = %(zip)s
401 AND
402 (
403 (lower(country) = lower(%(country)s))
404 OR
405 (lower(l10n_country) = lower(%(country)s))
406 OR
407 (code_country = %(country_code)s)
408 )
409
410 ) UNION (
411
412 -- find by urb / country
413 SELECT
414 2 AS rank,
415 region,
416 l10n_region,
417 code_region
418 FROM dem.v_urb WHERE
419 lower(urb) = lower(%(urb)s)
420 AND
421 (
422 (lower(country) = lower(%(country)s))
423 OR
424 (lower(l10n_country) = lower(%(country)s))
425 OR
426 (code_country = %(country_code)s)
427 )
428
429 ) ORDER BY rank"""
430
431 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
432
433 if len(rows) == 0:
434 cmd = """
435 -- find by country (some countries will only have one region)
436 SELECT
437 1 AS rank, -- dummy to conform with function result structure at Python level
438 region,
439 l10n_region,
440 code_region
441 FROM dem.v_region WHERE
442 (lower(country) = lower(%(country)s))
443 OR
444 (lower(l10n_country) = lower(%(country)s))
445 OR
446 (code_country = %(country_code)s)
447 """
448 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
449 if len(rows) == 1:
450 region = rows[0]
451 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [%s]', zip, urb, country, country_code, region)
452 return region
453 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [??]', zip, urb, country, country_code)
454 return None
455
456 if len(rows) > 2:
457 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [%s]', zip, urb, country, country_code, rows)
458 return None
459
460 region = rows[0]
461 _log.debug('zip [%s] / urb [%s] / country [%s] (%s) => [%s]', zip, urb, country, country_code, region)
462 return region
463
464
466 if country_code is None:
467 cmd = """
468 SELECT code FROM dem.region WHERE lower(_(name)) = lower(%(region)s)
469 UNION
470 SELECT code FROM dem.region WHERE lower(name) = lower(%(region)s)
471 """
472 else:
473 cmd = """
474 SELECT code FROM dem.region WHERE lower(_(name)) = lower(%(region)s) AND lower(country) = lower(%(country_code)s)
475 UNION
476 SELECT code FROM dem.region WHERE lower(name) = %(region)s AND lower(country) = lower(%(country_code)s)
477 """
478 args = {
479 'country_code': country_code,
480 'region': region
481 }
482 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
483 if len(rows) == 0:
484 return None
485 return rows[0][0]
486
487
489
490 args = {'region': region}
491
492 queries = []
493 if delete_urbs:
494 queries.append ({
495 'cmd': """
496 delete from dem.urb du
497 where
498 du.fk_region = %(region)s
499 and
500 not exists (select 1 from dem.street ds where ds.id_urb = du.id)""",
501 'args': args
502 })
503
504 queries.append ({
505 'cmd': """
506 DELETE FROM dem.region d_r
507 WHERE
508 d_r.pk = %(region)s
509 AND
510 NOT EXISTS (SELECT 1 FROM dem.urb du WHERE du.fk_region = d_r.pk)""",
511 'args': args
512 })
513
514 gmPG2.run_rw_queries(queries = queries)
515
516 return True
517
518
520
521 args = {'code': code, 'country': country, 'name': name}
522
523 cmd = """SELECT EXISTS (SELECT 1 FROM dem.region WHERE name = %(name)s)"""
524 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
525
526 if rows[0][0]:
527 return
528
529 cmd = """
530 INSERT INTO dem.region (
531 code, country, name
532 ) VALUES (
533 %(code)s, %(country)s, %(name)s
534 )"""
535 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
536
538 cmd = """
539 select
540 l10n_region, l10n_country, region, code_region, code_country, pk_region, country_deprecated
541 from dem.v_region
542 order by l10n_country, l10n_region"""
543 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}])
544 return rows
545
546
547
548
549 -class cAddress(gmBusinessDBObject.cBusinessDBObject):
550 """A class representing an address as an entity in itself.
551
552 We consider addresses to be self-complete "labels" for locations.
553 It does not depend on any people actually living there. Thus
554 an address can get attached to as many people as we want to
555 signify that that is their place of residence/work/...
556
557 This class acts on the address as an entity. Therefore it can
558 modify the address fields. Think carefully about *modifying*
559 addresses attached to people, though. Most times when you think
560 person.modify_address() what you *really* want is as sequence of
561 person.unlink_address(old) and person.link_address(new).
562
563 Modifying an address may or may not be the proper thing to do as
564 it will transparently modify the address for *all* the people to
565 whom it is attached. In many cases you will want to create a *new*
566 address and link it to a person instead of the old address.
567 """
568 _cmd_fetch_payload = "SELECT * FROM dem.v_address WHERE pk_address = %s"
569 _cmds_store_payload = [
570 """UPDATE dem.address SET
571 aux_street = %(notes_street)s,
572 subunit = %(subunit)s,
573 addendum = %(notes_subunit)s,
574 lat_lon = %(lat_lon_street)s
575 WHERE
576 id = %(pk_address)s
577 AND
578 xmin = %(xmin_address)s
579 RETURNING
580 xmin AS xmin_address"""
581 ]
582 _updatable_fields = [
583 'notes_street',
584 'subunit',
585 'notes_subunit',
586 'lat_lon_address'
587 ]
588
593
594
596 url = 'http://nominatim.openstreetmap.org/search/%s/%s/%s/%s?limit=3' % (
597 urllib.parse.quote(self['country'].encode('utf8')),
598 urllib.parse.quote(self['urb'].encode('utf8')),
599 urllib.parse.quote(self['street'].encode('utf8')),
600 urllib.parse.quote(self['number'].encode('utf8'))
601 )
602 return url
603
604 as_map_url = property(_get_as_map_url, lambda x:x)
605
606
607 -def address_exists(country_code=None, region_code=None, urb=None, postcode=None, street=None, number=None, subunit=None):
608
609 cmd = """SELECT dem.address_exists(%(country_code)s, %(region_code)s, %(urb)s, %(postcode)s, %(street)s, %(number)s, %(subunit)s)"""
610 args = {
611 'country_code': country_code,
612 'region_code': region_code,
613 'urb': urb,
614 'postcode': postcode,
615 'street': street,
616 'number': number,
617 'subunit': subunit
618 }
619
620 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}])
621 if rows[0][0] is None:
622 _log.debug('address does not exist')
623 for key, val in args.items():
624 _log.debug('%s: %s', key, val)
625 return None
626
627 return rows[0][0]
628
629
630 -def create_address(country_code=None, region_code=None, urb=None, suburb=None, postcode=None, street=None, number=None, subunit=None):
631
632 if suburb is not None:
633 suburb = gmTools.none_if(suburb.strip(), '')
634
635 pk_address = address_exists (
636 country_code = country_code,
637 region_code = region_code,
638 urb = urb,
639
640 postcode = postcode,
641 street = street,
642 number = number,
643 subunit = subunit
644 )
645 if pk_address is not None:
646 return cAddress(aPK_obj = pk_address)
647
648 cmd = """
649 SELECT dem.create_address (
650 %(number)s,
651 %(street)s,
652 %(postcode)s,
653 %(urb)s,
654 %(region_code)s,
655 %(country_code)s,
656 %(subunit)s
657 )"""
658 args = {
659 'number': number,
660 'street': street,
661 'postcode': postcode,
662 'urb': urb,
663 'region_code': region_code,
664 'country_code': country_code,
665 'subunit': subunit
666 }
667 queries = [{'cmd': cmd, 'args': args}]
668
669 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True)
670 adr = cAddress(aPK_obj = rows[0][0])
671
672 if suburb is not None:
673 queries = [{
674
675 'cmd': "UPDATE dem.street SET suburb = %(suburb)s WHERE id = %(pk_street)s AND suburb IS NULL",
676 'args': {'suburb': suburb, 'pk_street': adr['pk_street']}
677 }]
678 rows, idx = gmPG2.run_rw_queries(queries = queries)
679
680 return adr
681
683 cmd = """
684 DELETE FROM dem.address
685 WHERE
686 id = %(pk)s
687 AND
688 NOT EXISTS ((
689 SELECT 1 FROM dem.org_unit WHERE fk_address = %(pk)s LIMIT 1
690 ) UNION (
691 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_address = %(pk)s LIMIT 1
692 ) UNION (
693 SELECT 1 FROM dem.lnk_person_org_address WHERE id_address = %(pk)s LIMIT 1
694 ))
695 """
696 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_address}}])
697 return True
698
699
731
732
770
771
773 args = {'typ': address_type}
774 cmd = 'INSERT INTO dem.address_type (name) SELECT %(typ)s WHERE NOT EXISTS (SELECT 1 FROM dem.address_type WHERE name = %(typ)s OR _(name) = %(typ)s)'
775 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
776 cmd = 'SELECT id FROM dem.address_type WHERE name = %(typ)s OR _(name) = %(typ)s'
777 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False)
778 return rows[0][0]
779
780
782 cmd = 'select id as pk, name, _(name) as l10n_name from dem.address_type'
783 rows, idx = gmPG2.run_rw_queries(queries=[{'cmd': cmd}])
784 return rows
785
786
788
789 if order_by is None:
790 order_by = ''
791 else:
792 order_by = 'ORDER BY %s' % order_by
793
794 cmd = "SELECT * FROM dem.v_address %s" % order_by
795 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
796 if return_pks:
797 return [ r['pk_address'] for r in rows ]
798 return [ cAddress(row = {'data': r, 'idx': idx, 'pk_field': 'pk_address'}) for r in rows ]
799
800
802 cmd = """
803 SELECT * FROM dem.v_address WHERE
804 pk_address = (
805 SELECT id_address
806 FROM dem.lnk_person_org_address
807 WHERE id = %(pk_pat_adr)s
808 )
809 """
810 args = {'pk_pat_adr': pk_patient_address}
811 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
812 if len(rows) == 0:
813 return None
814
815 return cAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
816
817
819 cmd = 'SELECT pk_address, pk_identity FROM dem.v_pat_addresses WHERE pk_lnk_person_org_address = %(pk)s'
820 args = {'pk': pk_patient_address}
821 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
822 if not rows:
823 return None
824
825 if return_pks:
826 return [ r['pk_address'] for r in rows ]
827
828 pk_data = {
829 'pk_adr': rows[0]['pk_address'],
830 'pk_pat': rows[0]['pk_identity']
831 }
832 return cPatientAddress(aPK_obj = pk_data)
833
834
836 cmd = 'SELECT pk_address, pk_identity FROM dem.v_pat_addresses WHERE pk_identity = %(pat)s AND (address_type = %(typ)s OR l10n_address_type = %(typ)s)'
837 args = {'pat': pk_patient, 'typ': adr_type}
838 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
839 if len(rows) == 0:
840 return None
841
842 pk_data = {
843 'pk_adr': rows[0]['pk_address'],
844 'pk_pat': rows[0]['pk_identity']
845 }
846 return cPatientAddress(aPK_obj = pk_data)
847
848
850
851 _cmd_fetch_payload = 'SELECT * FROM dem.v_pat_addresses WHERE pk_address = %(pk_adr)s AND pk_identity = %(pk_pat)s'
852 _cmds_store_payload = [
853 """UPDATE dem.lnk_person_org_address SET
854 id_type = %(pk_address_type)s
855 WHERE
856 id = %(pk_lnk_person_org_address)s
857 AND
858 xmin = %(xmin_lnk_person_org_address)s
859 RETURNING
860 xmin AS xmin_lnk_person_org_address
861 """
862 ]
863 _updatable_fields = ['pk_address_type']
864
865
868
869
875
876
878 return cAddress(aPK_obj = self._payload[self._idx['pk_address']])
879
880 address = property(_get_address, lambda x:x)
881
882
885
886 as_map_url = property(_get_as_map_url, lambda x:x)
887
888
889
890
892
893 _cmd_fetch_payload = "SELECT * FROM dem.v_person_comms WHERE pk_lnk_identity2comm = %s"
894 _cmds_store_payload = [
895 """UPDATE dem.lnk_identity2comm SET
896 --fk_address = %(pk_address)s,
897 fk_type = dem.create_comm_type(%(comm_type)s),
898 url = %(url)s,
899 is_confidential = %(is_confidential)s,
900 comment = gm.nullify_empty_string(%(comment)s)
901 WHERE
902 pk = %(pk_lnk_identity2comm)s
903 AND
904 xmin = %(xmin_lnk_identity2comm)s
905 RETURNING
906 xmin AS xmin_lnk_identity2comm
907 """
908 ]
909 _updatable_fields = [
910 'url',
911 'comm_type',
912 'is_confidential',
913 'comment'
914 ]
915
916
918
919 _cmd_fetch_payload = "SELECT * FROM dem.v_org_unit_comms WHERE pk_lnk_org_unit2comm = %s"
920 _cmds_store_payload = [
921 """UPDATE dem.lnk_org_unit2comm SET
922 fk_type = dem.create_comm_type(%(comm_type)s),
923 url = %(url)s,
924 is_confidential = %(is_confidential)s,
925 comment = gm.nullify_empty_string(%(comment)s)
926 WHERE
927 pk = %(pk_lnk_org_unit2comm)s
928 AND
929 xmin = %(xmin_lnk_org_unit2comm)s
930 RETURNING
931 xmin AS xmin_lnk_org_unit2comm
932 """
933 ]
934 _updatable_fields = [
935 'url',
936 'comm_type',
937 'is_confidential',
938 'comment'
939 ]
940
941
942 -def create_comm_channel(comm_medium=None, url=None, is_confidential=False, pk_channel_type=None, pk_identity=None, pk_org_unit=None):
943 """Create a communications channel for a patient."""
944
945 if url is None:
946 return None
947
948 args = {
949 'url': url,
950 'secret': is_confidential,
951 'pk_type': pk_channel_type,
952 'type': comm_medium
953 }
954
955 if pk_identity is not None:
956 args['pk_owner'] = pk_identity
957 tbl = 'dem.lnk_identity2comm'
958 col = 'fk_identity'
959 view = 'dem.v_person_comms'
960 view_pk = 'pk_lnk_identity2comm'
961 channel_class = cCommChannel
962 if pk_org_unit is not None:
963 args['pk_owner'] = pk_org_unit
964 tbl = 'dem.lnk_org_unit2comm'
965 col = 'fk_org_unit'
966 view = 'dem.v_org_unit_comms'
967 view_pk = 'pk_lnk_org_unit2comm'
968 channel_class = cOrgCommChannel
969
970 if pk_channel_type is None:
971 cmd = """INSERT INTO %s (
972 %s,
973 url,
974 fk_type,
975 is_confidential
976 ) VALUES (
977 %%(pk_owner)s,
978 %%(url)s,
979 dem.create_comm_type(%%(type)s),
980 %%(secret)s
981 )""" % (tbl, col)
982 else:
983 cmd = """INSERT INTO %s (
984 %s,
985 url,
986 fk_type,
987 is_confidential
988 ) VALUES (
989 %%(pk_owner)s,
990 %%(url)s,
991 %%(pk_type)s,
992 %%(secret)s
993 )""" % (tbl, col)
994
995 queries = [{'cmd': cmd, 'args': args}]
996 cmd = "SELECT * FROM %s WHERE %s = currval(pg_get_serial_sequence('%s', 'pk'))" % (view, view_pk, tbl)
997 queries.append({'cmd': cmd})
998
999 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = True)
1000
1001 if pk_identity is not None:
1002 return cCommChannel(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx})
1003
1004 return channel_class(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx})
1005
1007 if pk_patient is not None:
1008 query = {
1009 'cmd': "DELETE FROM dem.lnk_identity2comm WHERE pk = %(pk)s AND fk_identity = %(pat)s",
1010 'args': {'pk': pk, 'pat': pk_patient}
1011 }
1012 if pk_org_unit is not None:
1013 query = {
1014 'cmd': "DELETE FROM dem.lnk_org_unit2comm WHERE pk = %(pk)s AND fk_org_unit = %(unit)s",
1015 'args': {'pk': pk, 'unit': pk_org_unit}
1016 }
1017 gmPG2.run_rw_queries(queries = [query])
1018
1020 cmd = "SELECT pk, _(description) AS l10n_description, description FROM dem.enum_comm_types"
1021 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
1022 return rows
1023
1025 cmd = """
1026 DELETE FROM dem.enum_comm_types
1027 WHERE
1028 pk = %(pk)s
1029 AND NOT EXISTS (
1030 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_type = %(pk)s
1031 )
1032 AND NOT EXISTS (
1033 SELECT 1 FROM dem.lnk_org_unit2comm WHERE fk_type = %(pk)s
1034 )
1035 """
1036 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_channel_type}}])
1037 return True
1038
1039
1040
1041
1043 """
1044 wrap mx.DateTime brokenness
1045 Returns 9-tuple for use with pyhon time functions
1046 """
1047 return [ int(x) for x in str(mx).split(' ')[0].split('-') ] + [0,0,0, 0,0,0]
1048
1050 """Gets a dict matching address types to their ID"""
1051 row_list = gmPG.run_ro_query('personalia', "select name, id from dem.address_type")
1052 if row_list is None:
1053 return {}
1054 if len(row_list) == 0:
1055 return {}
1056 return dict (row_list)
1057
1059 """Gets a dictionary matching marital status types to their internal ID"""
1060 row_list = gmPG.run_ro_query('personalia', "select name, pk from dem.marital_status")
1061 if row_list is None:
1062 return {}
1063 if len(row_list) == 0:
1064 return {}
1065 return dict(row_list)
1066
1068 """Gets a dictionary of relationship types to internal id"""
1069 row_list = gmPG.run_ro_query('personalia', "select description, id from dem.relation_types")
1070 if row_list is None:
1071 return None
1072 if len (row_list) == 0:
1073 return None
1074 return dict(row_list)
1075
1076
1078 cmd = """
1079 select
1080 dem.region.name,
1081 dem.urb.postcode
1082 from
1083 dem.urb,
1084 dem.region
1085 where
1086 dem.urb.id = %s and
1087 dem.urb.fk_region = dem.region.pk"""
1088 row_list = gmPG.run_ro_query('personalia', cmd, None, id_urb)
1089 if not row_list:
1090 return None
1091 else:
1092 return (row_list[0][0], row_list[0][1])
1093
1095 cmd = """
1096 select
1097 dem.region.name,
1098 coalesce (dem.street.postcode, dem.urb.postcode),
1099 dem.urb.name
1100 from
1101 dem.urb,
1102 dem.region,
1103 dem.street
1104 where
1105 dem.street.id = %s and
1106 dem.street.id_urb = dem.urb.id and
1107 dem.urb.fk_region = dem.region.pk
1108 """
1109 row_list = gmPG.run_ro_query('personalia', cmd, None, id_street)
1110 if not row_list:
1111 return None
1112 else:
1113 return (row_list[0][0], row_list[0][1], row_list[0][2])
1114
1116 row_list = gmPG.run_ro_query('personalia', "select name from dem.country where code = %s", None, country_code)
1117 if not row_list:
1118 return None
1119 else:
1120 return row_list[0][0]
1121
1123 row_list = gmPG.run_ro_query ('personalia', """
1124 select
1125 dem.urb.postcode,
1126 dem.region.code,
1127 dem.region.name,
1128 dem.country.code,
1129 dem.country.name
1130 from
1131 dem.urb,
1132 dem.region,
1133 dem.country
1134 where
1135 dem.urb.name = %s and
1136 dem.urb.fk_region = dem.region.pk and
1137 dem.region.country = dem.country.code""", None, town)
1138 if not row_list:
1139 return (None, None, None, None, None)
1140 else:
1141 return tuple (row_list[0])
1142
1143
1144
1146 print("received post_patient_selection notification")
1147 print(kwargs['kwds'])
1148
1149
1150
1151
1152
1153 if __name__ == "__main__":
1154
1155 if len(sys.argv) < 2:
1156 sys.exit()
1157
1158 if sys.argv[1] != 'test':
1159 sys.exit()
1160
1161 import random
1162
1163 from Gnumed.pycommon import gmConnectionPool
1164
1166
1167 addresses = [
1168 {
1169 'country_code': 'Germany',
1170 'region_code': 'Sachsen',
1171 'urb': 'Hannover',
1172 'postcode': '06672',
1173 'street': 'Rommelsberger Strasse',
1174 'number': '11'
1175 },
1176 {
1177 'country_code': 'DE',
1178 'region_code': 'SN',
1179 'urb': 'Hannover',
1180 'postcode': '06671',
1181 'street': 'Tonnenstraße',
1182 'number': '65',
1183 'subunit': 'Parterre'
1184 },
1185 {
1186 'country_code': 'DE',
1187 'region_code': 'SN',
1188 'urb': 'Hannover',
1189 'postcode': '06671',
1190 'street': 'Tonnenstraße',
1191 'number': '65',
1192 'subunit': '1. Stock'
1193 },
1194 {
1195 'country_code': 'DE',
1196 'region_code': 'SN',
1197 'urb': 'Hannover',
1198 'postcode': '06671',
1199 'street': 'Tonnenstraße',
1200 'number': '65',
1201 'subunit': '1. Stock'
1202 },
1203 {
1204
1205
1206 'urb': 'Hannover',
1207 'postcode': '06671',
1208 'street': 'Tonnenstraße',
1209 'number': '65',
1210 'subunit': '1. Stock'
1211 },
1212 ]
1213
1214 for adr in addresses:
1215 print(adr)
1216 exists = address_exists(**adr)
1217 if exists is None:
1218 print("address does not exist")
1219 else:
1220 print("address exists, primary key:", exists)
1221
1222
1224 address = create_address (
1225 country_code = 'DE',
1226 region_code = 'SN',
1227 urb ='Hannover',
1228 suburb ='Grabenthal',
1229 postcode ='06672',
1230 street = 'Rommelsberger Strasse',
1231 number = '11'
1232
1233 )
1234 print("created existing address")
1235 print(address.format())
1236
1237 su = str(random.random())
1238
1239 address = create_address (
1240 country_code = 'DE',
1241 region_code = 'SN',
1242 urb ='Hannover',
1243 suburb ='Grabenthal',
1244 postcode ='06672',
1245 street = 'Rommelsberger Strasse',
1246 number = '11',
1247
1248 subunit = su
1249 )
1250 print("created new address with subunit", su)
1251 print(address)
1252 print(address.format())
1253 print(address.as_map_url)
1254 print("deleted address:", delete_address(pk_address = address['pk_address']))
1255
1259
1261 region = input("Please enter a region: ")
1262 print("country for region [%s] is: %s" % (region, get_country_for_region(region = region)))
1263
1265 if delete_tag_image(tag_image = 9999):
1266 print("deleted tag 9999")
1267 else:
1268 print("did not delete tag 9999")
1269 if delete_tag_image(tag_image = 1):
1270 print("deleted tag 1")
1271 else:
1272 print("did not delete tag 1")
1273
1275 tag = cTagImage(aPK_obj = 1)
1276 print(tag)
1277
1278
1281
1287
1289 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Germany', country_code = 'DE'))
1290 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Germany', country_code = None))
1291 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Deutschland', country_code = 'DE'))
1292 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Deutschland', country_code = None))
1293 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = None, country_code = 'DE'))
1294 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = None, country_code = None))
1295
1296
1297
1298
1299
1300
1301
1302
1303 l, creds = gmPG2.request_login_params()
1304 gmConnectionPool.gmConnectionPool().credentials = creds
1305
1306 test_address_exists()
1307
1308
1309
1310
1311
1312 test_get_billing_address()
1313
1314
1315