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