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