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 return cAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
815
816
818 cmd = 'SELECT * FROM dem.v_pat_addresses WHERE pk_lnk_person_org_address = %(pk)s'
819 args = {'pk': pk_patient_address}
820 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
821 if len(rows) == 0:
822 return None
823 if return_pks:
824 return [ r['pk_address'] for r in rows ]
825 return cPatientAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
826
827
829 cmd = 'SELECT * FROM dem.v_pat_addresses WHERE pk_identity = %(pat)s AND (address_type = %(typ)s OR l10n_address_type = %(typ)s)'
830 args = {'pat': pk_patient, 'typ': adr_type}
831 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
832 if len(rows) == 0:
833 return None
834 return cPatientAddress(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_address'})
835
836
838
839 _cmd_fetch_payload = "SELECT * FROM dem.v_pat_addresses WHERE pk_address = %s"
840 _cmds_store_payload = [
841 """UPDATE dem.lnk_person_org_address SET
842 id_type = %(pk_address_type)s
843 WHERE
844 id = %(pk_lnk_person_org_address)s
845 AND
846 xmin = %(xmin_lnk_person_org_address)s
847 RETURNING
848 xmin AS xmin_lnk_person_org_address
849 """
850 ]
851 _updatable_fields = ['pk_address_type']
852
855
861
863 return cAddress(aPK_obj = self._payload[self._idx['pk_address']])
864
865 address = property(_get_address, lambda x:x)
866
867
870
871 as_map_url = property(_get_as_map_url, lambda x:x)
872
873
874
875
877
878 _cmd_fetch_payload = "SELECT * FROM dem.v_person_comms WHERE pk_lnk_identity2comm = %s"
879 _cmds_store_payload = [
880 """UPDATE dem.lnk_identity2comm SET
881 --fk_address = %(pk_address)s,
882 fk_type = dem.create_comm_type(%(comm_type)s),
883 url = %(url)s,
884 is_confidential = %(is_confidential)s,
885 comment = gm.nullify_empty_string(%(comment)s)
886 WHERE
887 pk = %(pk_lnk_identity2comm)s
888 AND
889 xmin = %(xmin_lnk_identity2comm)s
890 RETURNING
891 xmin AS xmin_lnk_identity2comm
892 """
893 ]
894 _updatable_fields = [
895 'url',
896 'comm_type',
897 'is_confidential',
898 'comment'
899 ]
900
901
903
904 _cmd_fetch_payload = "SELECT * FROM dem.v_org_unit_comms WHERE pk_lnk_org_unit2comm = %s"
905 _cmds_store_payload = [
906 """UPDATE dem.lnk_org_unit2comm SET
907 fk_type = dem.create_comm_type(%(comm_type)s),
908 url = %(url)s,
909 is_confidential = %(is_confidential)s,
910 comment = gm.nullify_empty_string(%(comment)s)
911 WHERE
912 pk = %(pk_lnk_org_unit2comm)s
913 AND
914 xmin = %(xmin_lnk_org_unit2comm)s
915 RETURNING
916 xmin AS xmin_lnk_org_unit2comm
917 """
918 ]
919 _updatable_fields = [
920 'url',
921 'comm_type',
922 'is_confidential',
923 'comment'
924 ]
925
926
927 -def create_comm_channel(comm_medium=None, url=None, is_confidential=False, pk_channel_type=None, pk_identity=None, pk_org_unit=None):
928 """Create a communications channel for a patient."""
929
930 if url is None:
931 return None
932
933 args = {
934 'url': url,
935 'secret': is_confidential,
936 'pk_type': pk_channel_type,
937 'type': comm_medium
938 }
939
940 if pk_identity is not None:
941 args['pk_owner'] = pk_identity
942 tbl = 'dem.lnk_identity2comm'
943 col = 'fk_identity'
944 view = 'dem.v_person_comms'
945 view_pk = 'pk_lnk_identity2comm'
946 channel_class = cCommChannel
947 if pk_org_unit is not None:
948 args['pk_owner'] = pk_org_unit
949 tbl = 'dem.lnk_org_unit2comm'
950 col = 'fk_org_unit'
951 view = 'dem.v_org_unit_comms'
952 view_pk = 'pk_lnk_org_unit2comm'
953 channel_class = cOrgCommChannel
954
955 if pk_channel_type is None:
956 cmd = """INSERT INTO %s (
957 %s,
958 url,
959 fk_type,
960 is_confidential
961 ) VALUES (
962 %%(pk_owner)s,
963 %%(url)s,
964 dem.create_comm_type(%%(type)s),
965 %%(secret)s
966 )""" % (tbl, col)
967 else:
968 cmd = """INSERT INTO %s (
969 %s,
970 url,
971 fk_type,
972 is_confidential
973 ) VALUES (
974 %%(pk_owner)s,
975 %%(url)s,
976 %%(pk_type)s,
977 %%(secret)s
978 )""" % (tbl, col)
979
980 queries = [{'cmd': cmd, 'args': args}]
981 cmd = "SELECT * FROM %s WHERE %s = currval(pg_get_serial_sequence('%s', 'pk'))" % (view, view_pk, tbl)
982 queries.append({'cmd': cmd})
983
984 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = True)
985
986 if pk_identity is not None:
987 return cCommChannel(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx})
988
989 return channel_class(row = {'pk_field': view_pk, 'data': rows[0], 'idx': idx})
990
992 if pk_patient is not None:
993 query = {
994 'cmd': "DELETE FROM dem.lnk_identity2comm WHERE pk = %(pk)s AND fk_identity = %(pat)s",
995 'args': {'pk': pk, 'pat': pk_patient}
996 }
997 if pk_org_unit is not None:
998 query = {
999 'cmd': "DELETE FROM dem.lnk_org_unit2comm WHERE pk = %(pk)s AND fk_org_unit = %(unit)s",
1000 'args': {'pk': pk, 'unit': pk_org_unit}
1001 }
1002 gmPG2.run_rw_queries(queries = [query])
1003
1005 cmd = "SELECT pk, _(description) AS l10n_description, description FROM dem.enum_comm_types"
1006 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
1007 return rows
1008
1010 cmd = """
1011 DELETE FROM dem.enum_comm_types
1012 WHERE
1013 pk = %(pk)s
1014 AND NOT EXISTS (
1015 SELECT 1 FROM dem.lnk_identity2comm WHERE fk_type = %(pk)s
1016 )
1017 AND NOT EXISTS (
1018 SELECT 1 FROM dem.lnk_org_unit2comm WHERE fk_type = %(pk)s
1019 )
1020 """
1021 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': {'pk': pk_channel_type}}])
1022 return True
1023
1024
1025
1026
1028 """
1029 wrap mx.DateTime brokenness
1030 Returns 9-tuple for use with pyhon time functions
1031 """
1032 return [ int(x) for x in str(mx).split(' ')[0].split('-') ] + [0,0,0, 0,0,0]
1033
1035 """Gets a dict matching address types to their ID"""
1036 row_list = gmPG.run_ro_query('personalia', "select name, id from dem.address_type")
1037 if row_list is None:
1038 return {}
1039 if len(row_list) == 0:
1040 return {}
1041 return dict (row_list)
1042
1044 """Gets a dictionary matching marital status types to their internal ID"""
1045 row_list = gmPG.run_ro_query('personalia', "select name, pk from dem.marital_status")
1046 if row_list is None:
1047 return {}
1048 if len(row_list) == 0:
1049 return {}
1050 return dict(row_list)
1051
1053 """Gets a dictionary of relationship types to internal id"""
1054 row_list = gmPG.run_ro_query('personalia', "select description, id from dem.relation_types")
1055 if row_list is None:
1056 return None
1057 if len (row_list) == 0:
1058 return None
1059 return dict(row_list)
1060
1061
1063 cmd = """
1064 select
1065 dem.region.name,
1066 dem.urb.postcode
1067 from
1068 dem.urb,
1069 dem.region
1070 where
1071 dem.urb.id = %s and
1072 dem.urb.fk_region = dem.region.pk"""
1073 row_list = gmPG.run_ro_query('personalia', cmd, None, id_urb)
1074 if not row_list:
1075 return None
1076 else:
1077 return (row_list[0][0], row_list[0][1])
1078
1080 cmd = """
1081 select
1082 dem.region.name,
1083 coalesce (dem.street.postcode, dem.urb.postcode),
1084 dem.urb.name
1085 from
1086 dem.urb,
1087 dem.region,
1088 dem.street
1089 where
1090 dem.street.id = %s and
1091 dem.street.id_urb = dem.urb.id and
1092 dem.urb.fk_region = dem.region.pk
1093 """
1094 row_list = gmPG.run_ro_query('personalia', cmd, None, id_street)
1095 if not row_list:
1096 return None
1097 else:
1098 return (row_list[0][0], row_list[0][1], row_list[0][2])
1099
1101 row_list = gmPG.run_ro_query('personalia', "select name from dem.country where code = %s", None, country_code)
1102 if not row_list:
1103 return None
1104 else:
1105 return row_list[0][0]
1106
1108 row_list = gmPG.run_ro_query ('personalia', """
1109 select
1110 dem.urb.postcode,
1111 dem.region.code,
1112 dem.region.name,
1113 dem.country.code,
1114 dem.country.name
1115 from
1116 dem.urb,
1117 dem.region,
1118 dem.country
1119 where
1120 dem.urb.name = %s and
1121 dem.urb.fk_region = dem.region.pk and
1122 dem.region.country = dem.country.code""", None, town)
1123 if not row_list:
1124 return (None, None, None, None, None)
1125 else:
1126 return tuple (row_list[0])
1127
1128
1129
1131 print("received post_patient_selection notification")
1132 print(kwargs['kwds'])
1133
1134
1135
1136
1137
1138 if __name__ == "__main__":
1139
1140 if len(sys.argv) < 2:
1141 sys.exit()
1142
1143 if sys.argv[1] != 'test':
1144 sys.exit()
1145
1146 import random
1147
1149
1150 addresses = [
1151 {
1152 'country': 'Germany',
1153 'region_code': 'Sachsen',
1154 'urb': 'Hannover',
1155 'postcode': '06672',
1156 'street': 'Rommelsberger Strasse',
1157 'number': '11'
1158 },
1159 {
1160 'country': 'DE',
1161 'region_code': 'SN',
1162 'urb': 'Hannover',
1163 'postcode': '06671',
1164 'street': 'Tonnenstraße',
1165 'number': '65',
1166 'subunit': 'Parterre'
1167 },
1168 {
1169 'country': 'DE',
1170 'region_code': 'SN',
1171 'urb': 'Hannover',
1172 'postcode': '06671',
1173 'street': 'Tonnenstraße',
1174 'number': '65',
1175 'subunit': '1. Stock'
1176 },
1177 {
1178 'country': 'DE',
1179 'region_code': 'SN',
1180 'urb': 'Hannover',
1181 'postcode': '06671',
1182 'street': 'Tonnenstraße',
1183 'number': '65',
1184 'subunit': '1. Stock'
1185 },
1186 {
1187
1188
1189 'urb': 'Hannover',
1190 'postcode': '06671',
1191 'street': 'Tonnenstraße',
1192 'number': '65',
1193 'subunit': '1. Stock'
1194 },
1195 ]
1196
1197 for adr in addresses:
1198 print(adr)
1199 exists = address_exists(**adr)
1200 if exists is None:
1201 print("address does not exist")
1202 else:
1203 print("address exists, primary key:", exists)
1204
1205
1207 address = create_address (
1208 country_code = 'DE',
1209 region_code = 'SN',
1210 urb ='Hannover',
1211 suburb ='Grabenthal',
1212 postcode ='06672',
1213 street = 'Rommelsberger Strasse',
1214 number = '11'
1215
1216 )
1217 print("created existing address")
1218 print(address.format())
1219
1220 su = str(random.random())
1221
1222 address = create_address (
1223 country_code = 'DE',
1224 region_code = 'SN',
1225 urb ='Hannover',
1226 suburb ='Grabenthal',
1227 postcode ='06672',
1228 street = 'Rommelsberger Strasse',
1229 number = '11',
1230
1231 subunit = su
1232 )
1233 print("created new address with subunit", su)
1234 print(address)
1235 print(address.format())
1236 print(address.as_map_url)
1237 print("deleted address:", delete_address(pk_address = address['pk_address']))
1238
1242
1244 region = input("Please enter a region: ")
1245 print("country for region [%s] is: %s" % (region, get_country_for_region(region = region)))
1246
1248 if delete_tag_image(tag_image = 9999):
1249 print("deleted tag 9999")
1250 else:
1251 print("did not delete tag 9999")
1252 if delete_tag_image(tag_image = 1):
1253 print("deleted tag 1")
1254 else:
1255 print("did not delete tag 1")
1256
1258 tag = cTagImage(aPK_obj = 1)
1259 print(tag)
1260
1261
1264
1270
1272 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Germany', country_code = 'DE'))
1273 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Germany', country_code = None))
1274 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Deutschland', country_code = 'DE'))
1275 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = 'Deutschland', country_code = None))
1276 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = None, country_code = 'DE'))
1277 print(map_urb_zip_country2region(urb = 'Kassel', zip = '34119', country = None, country_code = None))
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288 test_create_address()
1289
1290
1291
1292
1293
1294
1295
1296