1
2 """GNUmed Praxis related middleware."""
3
4 __license__ = "GPL"
5 __author__ = "K.Hilbert <Karsten.Hilbert@gmx.net>"
6
7
8 import sys
9 import logging
10 import io
11 import urllib.parse
12
13
14 if __name__ == '__main__':
15 sys.path.insert(0, '../../')
16 from Gnumed.pycommon import gmPG2
17 from Gnumed.pycommon import gmTools
18 from Gnumed.pycommon import gmBorg
19 from Gnumed.pycommon import gmCfg2
20 from Gnumed.pycommon import gmHooks
21 from Gnumed.pycommon import gmBusinessDBObject
22
23 from Gnumed.business import gmOrganization
24
25
26 _log = logging.getLogger('gm.praxis')
27 _cfg = gmCfg2.gmCfgData()
28
29
31
32 args = {'wp': workplace}
33
34
35 queries = [
36 {'cmd': """
37 delete from cfg.cfg_item
38 where
39 fk_template = (
40 select pk
41 from cfg.cfg_template
42 where name = 'horstspace.notebook.plugin_load_order'
43 )
44 and
45 workplace = %(wp)s""",
46 'args': args
47 }
48 ]
49
50
51 if delete_config:
52 queries.append ({
53 'cmd': """
54 delete from cfg.cfg_item
55 where
56 workplace = %(wp)s""",
57 'args': args
58 })
59
60 gmPG2.run_rw_queries(link_obj = conn, queries = queries, end_tx = True)
61
62
63
64
65 _SQL_get_praxis_branches = "SELECT * FROM dem.v_praxis_branches WHERE %s"
66
68 """Represents a praxis branch"""
69
70 _cmd_fetch_payload = _SQL_get_praxis_branches % "pk_praxis_branch = %s"
71 _cmds_store_payload = [
72 """UPDATE dem.praxis_branch SET
73 fk_org_unit = %(pk_org_unit)s
74 WHERE
75 pk = %(pk_praxis_branch)s
76 AND
77 xmin = %(xmin_praxis_branch)s
78 RETURNING
79 xmin as xmin_praxis_branch
80 """
81 ]
82 _updatable_fields = [
83 'pk_org_unit'
84 ]
85
91
92
93 - def lock(self, exclusive=False):
94 return lock_praxis_branch(pk_praxis_branch = self._payload[self._idx['pk_praxis_branch']], exclusive = exclusive)
95
96
97 - def unlock(self, exclusive=False):
98 return unlock_praxis_branch(pk_praxis_branch = self._payload[self._idx['pk_praxis_branch']], exclusive = exclusive)
99
100
103
104
107
108
110 self_adr = self.address
111 url = 'https://www.luftlinie.org/%s-%s-%s-%s-%s/%s-%s-%s-%s-%s' % (
112 urllib.parse.quote(self_adr['street'].encode('utf8')),
113 urllib.parse.quote(self_adr['number'].encode('utf8')),
114 urllib.parse.quote(self_adr['urb'].encode('utf8')),
115 urllib.parse.quote(self_adr['postcode'].encode('utf8')),
116 urllib.parse.quote(self_adr['country'].encode('utf8')),
117 urllib.parse.quote(address['street'].encode('utf8')),
118 urllib.parse.quote(address['number'].encode('utf8')),
119 urllib.parse.quote(address['urb'].encode('utf8')),
120 urllib.parse.quote(address['postcode'].encode('utf8')),
121 urllib.parse.quote(address['country'].encode('utf8'))
122 )
123 return url
124
125
126
127
130
131 org_unit = property(_get_org_unit, lambda x:x)
132
133
136
137 organization = property(_get_org, lambda x:x)
138
139
142
143 address = property(_get_address, lambda x:x)
144
145
146
147
148
149
150
152 vcf_fields = [
153 'BEGIN:VCARD',
154 'VERSION:4.0',
155 'KIND:org',
156 _('FN:%(l10n_unit_category)s %(branch)s of %(l10n_organization_category)s %(praxis)s') % self,
157 'N:%(praxis)s;%(branch)s' % self
158 ]
159 adr = self.address
160 if adr is not None:
161 vcf_fields.append('ADR:;%(subunit)s;%(street)s %(number)s;%(urb)s;%(l10n_region)s;%(postcode)s;%(l10n_country)s' % adr)
162 comms = self.get_comm_channels(comm_medium = 'workphone')
163 if len(comms) > 0:
164 vcf_fields.append('TEL;VALUE=uri;TYPE=work:tel:%(url)s' % comms[0])
165 comms = self.get_comm_channels(comm_medium = 'email')
166 if len(comms) > 0:
167 vcf_fields.append('EMAIL:%(url)s' % comms[0])
168 vcf_fields.append('END:VCARD')
169 vcf_fname = gmTools.get_unique_filename (
170 prefix = 'gm-praxis-',
171 suffix = '.vcf'
172 )
173 vcf_file = io.open(vcf_fname, mode = 'wt', encoding = 'utf8')
174 vcf_file.write('\n'.join(vcf_fields))
175 vcf_file.write('\n')
176 vcf_file.close()
177 return vcf_fname
178
179 vcf = property(_get_vcf, lambda x:x)
180
181
191
192
194 """
195 http://blog.thenetimpact.com/2011/07/decoding-qr-codes-how-to-format-data-for-qr-code-generators/
196 https://www.nttdocomo.co.jp/english/service/developer/make/content/barcode/function/application/addressbook/index.html
197
198 MECARD:N:NAME;ADR:pobox,subunit,unit,street,ort,region,zip,country;TEL:111111111;FAX:22222222;EMAIL:mail@praxis.org;
199
200 MECARD:N:$<praxis::%(praxis)s, %(branch)s::>$;ADR:$<praxis_address::,%(subunit)s,%(number)s,%(street)s,%(urb)s,,%(postcode)s,%(l10n_country)s::>$;TEL:$<praxis_comm::workphone::>$;FAX:$<praxis_comm::fax::>$;EMAIL:$<praxis_comm::email::60>$;
201 """
202 MECARD = 'MECARD:N:%(praxis)s,%(branch)s;' % self
203 adr = self.address
204 if adr is not None:
205 MECARD += 'ADR:,%(subunit)s,%(number)s,%(street)s,%(urb)s,,%(postcode)s,%(l10n_country)s;' % adr
206 comms = self.get_comm_channels(comm_medium = 'workphone')
207 if len(comms) > 0:
208 MECARD += 'TEL:%(url)s;' % comms[0]
209 comms = self.get_comm_channels(comm_medium = 'fax')
210 if len(comms) > 0:
211 MECARD += 'FAX:%(url)s;' % comms[0]
212 comms = self.get_comm_channels(comm_medium = 'email')
213 if len(comms) > 0:
214 MECARD += 'EMAIL:%(url)s;' % comms[0]
215 return MECARD
216
217 MECARD = property(_get_mecard)
218
219
221 return gmPG2.lock_row(table = 'dem.praxis_branch', pk = pk_praxis_branch, exclusive = exclusive)
222
223
225 return gmPG2.unlock_row(table = 'dem.praxis_branch', pk = pk_praxis_branch, exclusive = exclusive)
226
227
229 if order_by is None:
230 order_by = 'true'
231 else:
232 order_by = 'true ORDER BY %s' % order_by
233
234 cmd = _SQL_get_praxis_branches % order_by
235 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = True)
236 return [ cPraxisBranch(row = {'data': r, 'idx': idx, 'pk_field': 'pk_praxis_branch'}) for r in rows ]
237
238
240 cmd = _SQL_get_praxis_branches % 'pk_org_unit = %(pk_ou)s'
241 args = {'pk_ou': pk_org_unit}
242 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = True)
243 if len(rows) == 0:
244 return None
245 return cPraxisBranch(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_praxis_branch'})
246
247
249
250 args = {'fk_unit': pk_org_unit}
251 cmd1 = """
252 INSERT INTO dem.praxis_branch (fk_org_unit)
253 SELECT %(fk_unit)s WHERE NOT EXISTS (
254 SELECT 1 FROM dem.praxis_branch WHERE fk_org_unit = %(fk_unit)s
255 )
256 """
257 cmd2 = """SELECT * from dem.v_praxis_branches WHERE pk_org_unit = %(fk_unit)s"""
258 queries = [
259 {'cmd': cmd1, 'args': args},
260 {'cmd': cmd2, 'args': args}
261 ]
262 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = True)
263 return cPraxisBranch(row = {'data': rows[0], 'idx': idx, 'pk_field': 'pk_praxis_branch'})
264
265
267 queries = []
268 for pk in pk_org_units:
269 args = {'fk_unit': pk}
270 cmd = """
271 INSERT INTO dem.praxis_branch (fk_org_unit)
272 SELECT %(fk_unit)s WHERE NOT EXISTS (
273 SELECT 1 FROM dem.praxis_branch WHERE fk_org_unit = %(fk_unit)s
274 )
275 """
276 queries.append({'cmd': cmd, 'args': args})
277
278 args = {'fk_units': tuple(pk_org_units)}
279 cmd = """SELECT * from dem.v_praxis_branches WHERE pk_org_unit IN %(fk_units)s"""
280 queries.append({'cmd': cmd, 'args': args})
281 rows, idx = gmPG2.run_rw_queries(queries = queries, return_data = True, get_col_idx = True)
282 return [ cPraxisBranch(row = {'data': r, 'idx': idx, 'pk_field': 'pk_praxis_branch'}) for r in rows ]
283
284
286 if not lock_praxis_branch(pk_praxis_branch = pk_praxis_branch, exclusive = True):
287 return False
288 args = {'pk': pk_praxis_branch}
289 cmd = "DELETE FROM dem.praxis_branch WHERE pk = %(pk)s"
290 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
291 unlock_praxis_branch(pk_praxis_branch = pk_praxis_branch, exclusive = True)
292 return True
293
294
296
297 if pk_praxis_branches is None:
298 cmd = 'SELECT pk from dem.praxis_branch'
299 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd}], get_col_idx = False)
300 pks_to_lock = [ r[0] for r in rows ]
301 else:
302 pks_to_lock = pk_praxis_branches[:]
303
304 if except_pk_praxis_branches is not None:
305 for pk in except_pk_praxis_branches:
306 try: pks_to_lock.remove(pk)
307 except ValueError: pass
308
309 for pk in pks_to_lock:
310 if not lock_praxis_branch(pk_praxis_branch = pk, exclusive = True):
311 return False
312
313 args = {}
314 where_parts = []
315
316 if pk_praxis_branches is not None:
317 args['pks'] = tuple(pk_praxis_branches)
318 where_parts.append('pk IN %(pks)s')
319
320 if except_pk_praxis_branches is not None:
321 args['except'] = tuple(except_pk_praxis_branches)
322 where_parts.append('pk NOT IN %(except)s')
323
324 if len(where_parts) == 0:
325 cmd = "DELETE FROM dem.praxis_branch"
326 else:
327 cmd = "DELETE FROM dem.praxis_branch WHERE %s" % ' AND '.join(where_parts)
328
329 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
330 for pk in pks_to_lock:
331 unlock_praxis_branch(pk_praxis_branch = pk, exclusive = True)
332 return True
333
334
336
338 try:
339 self.has_been_initialized
340 except AttributeError:
341 self.branch = None
342 self.has_been_initialized = True
343 self.__helpdesk = None
344 self.__active_workplace = None
345
346
347 if branch is None:
348 return None
349
350
351 if not isinstance(branch, cPraxisBranch):
352 _log.error('cannot set current praxis branch to [%s], must be a cPraxisBranch instance' % str(branch))
353 raise TypeError('gmPraxis.gmCurrentPraxisBranch.__init__(): <branch> must be a cPraxisBranch instance but is: %s' % str(branch))
354
355 if self.branch is not None:
356 self.branch.unlock()
357
358 branch.lock()
359 self.branch = branch
360 _log.debug('current praxis branch now: %s', self.branch)
361
362 return None
363
364
365
366
368 if attribute == 'has_been_initialized':
369 raise AttributeError
370 if attribute in ['branch', 'waiting_list_patients', 'help_desk', 'db_logon_banner', 'active_workplace', 'workplaces', 'user_email']:
371 return getattr(self, attribute)
372 return getattr(self.branch, attribute)
373
374
375
376
378 """Return any attribute if known how to retrieve it by proxy."""
379 return self.branch[attribute]
380
381
383 self.branch[attribute] = value
384
385
386
387
393
394
396 cmd = """
397 update clin.waiting_list
398 set
399 urgency = %(urg)s,
400 comment = %(cmt)s,
401 area = %(zone)s
402 where
403 pk = %(pk)s"""
404 args = {
405 'pk': pk,
406 'urg': urgency,
407 'cmt': gmTools.none_if(comment, ''),
408 'zone': gmTools.none_if(zone, '')
409 }
410
411 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
412 gmHooks.run_hook_script(hook = 'after_waiting_list_modified')
413
414
416 if current_position == 1:
417 return
418
419 cmd = 'select clin.move_waiting_list_entry(%(pos)s, (%(pos)s - 1))'
420 args = {'pos': current_position}
421
422 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
423
424
426 cmd = 'select clin.move_waiting_list_entry(%(pos)s, (%(pos)s+1))'
427 args = {'pos': current_position}
428
429 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}])
430
431
432
433
435 cmd = """
436 SELECT * FROM clin.v_waiting_list
437 ORDER BY
438 list_position
439 """
440 rows, idx = gmPG2.run_ro_queries (
441 queries = [{'cmd': cmd}],
442 get_col_idx = False
443 )
444 return rows
445
446 waiting_list_patients = property (_get_waiting_list_patients, lambda x:x)
447
448
451
453
454 if self.__helpdesk is not None:
455 return self.__helpdesk
456
457 self.__helpdesk = gmTools.coalesce (
458 _cfg.get (
459 group = 'workplace',
460 option = 'help desk',
461 source_order = [
462 ('explicit', 'return'),
463 ('workbase', 'return'),
464 ('local', 'return'),
465 ('user', 'return'),
466 ('system', 'return')
467 ]
468 ),
469 'http://wiki.gnumed.de'
470 )
471
472 return self.__helpdesk
473
474 helpdesk = property(_get_helpdesk, _set_helpdesk)
475
476
478 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': 'select _(message) from cfg.db_logon_banner'}])
479 if len(rows) == 0:
480 return ''
481 return gmTools.coalesce(rows[0][0], '').strip()
482
484 queries = [
485 {'cmd': 'delete from cfg.db_logon_banner'}
486 ]
487 if banner.strip() != '':
488 queries.append ({
489 'cmd': 'insert into cfg.db_logon_banner (message) values (%(msg)s)',
490 'args': {'msg': banner.strip()}
491 })
492 rows, idx = gmPG2.run_rw_queries(queries = queries, end_tx = True)
493
494 db_logon_banner = property(_get_db_logon_banner, _set_db_logon_banner)
495
496
500
502 """Return the current workplace (client profile) definition.
503
504 The first occurrence counts.
505 """
506 if self.__active_workplace is not None:
507 return self.__active_workplace
508
509 self.__active_workplace = gmTools.coalesce (
510 _cfg.get (
511 group = 'workplace',
512 option = 'name',
513 source_order = [
514 ('explicit', 'return'),
515 ('workbase', 'return'),
516 ('local', 'return'),
517 ('user', 'return'),
518 ('system', 'return'),
519 ]
520 ),
521 'Local Default'
522 )
523
524 return self.__active_workplace
525
526 active_workplace = property(_get_workplace, _set_workplace)
527
528
531
533 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': 'SELECT DISTINCT workplace FROM cfg.cfg_item ORDER BY workplace'}])
534 return [ r[0] for r in rows ]
535
536 workplaces = property(_get_workplaces, _set_workplaces)
537
538
540
541 return _cfg.get (
542 group = 'preferences',
543 option = 'user email',
544 source_order = [
545 ('explicit', 'return'),
546 ('user', 'return'),
547 ('local', 'return'),
548 ('workbase', 'return'),
549 ('system', 'return')
550 ]
551 )
552
562
563 user_email = property(_get_user_email, _set_user_email)
564
565
566 if __name__ == '__main__':
567
568 if len(sys.argv) < 2:
569 sys.exit()
570
571 if sys.argv[1] != 'test':
572 sys.exit()
573
574 from Gnumed.pycommon import gmI18N
575 gmI18N.install_domain()
576
595
596
597
598
599
600 for b in get_praxis_branches():
601 print((b.format()))
602
603
604