Package Gnumed :: Package business :: Module gmPraxis
[frames] | no frames]

Source Code for Module Gnumed.business.gmPraxis

  1  # -*- coding: utf8 -*- 
  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  #============================================================ 
30 -def delete_workplace(workplace=None, delete_config=False, conn=None):
31 32 args = {'wp': workplace} 33 34 # delete workplace itself (plugin load list, that is) 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 # delete other config items associated with this workplace 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 # short description 64 #------------------------------------------------------------ 65 _SQL_get_praxis_branches = "SELECT * FROM dem.v_praxis_branches WHERE %s" 66
67 -class cPraxisBranch(gmBusinessDBObject.cBusinessDBObject):
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 #--------------------------------------------------------
86 - def format(self):
87 txt = _('Praxis branch #%s\n') % self._payload[self._idx['pk_praxis_branch']] 88 txt += ' ' 89 txt += '\n '.join(self.org_unit.format(with_address = True, with_org = True, with_comms = True)) 90 return txt
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 #--------------------------------------------------------
101 - def get_comm_channels(self, comm_medium=None):
102 return self.org_unit.get_comm_channels(comm_medium = comm_medium)
103 104 #--------------------------------------------------------
105 - def get_external_ids(self, id_type=None, issuer=None):
106 return self.org_unit.get_external_ids(id_type = id_type, issuer = issuer)
107 108 #--------------------------------------------------------
109 - def get_distance2address_url(self, address):
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 # properties 127 #--------------------------------------------------------
128 - def _get_org_unit(self):
129 return gmOrganization.cOrgUnit(aPK_obj = self._payload[self._idx['pk_org_unit']])
130 131 org_unit = property(_get_org_unit, lambda x:x) 132 133 #--------------------------------------------------------
134 - def _get_org(self):
135 return gmOrganization.cOrg(aPK_obj = self._payload[self._idx['pk_org']])
136 137 organization = property(_get_org, lambda x:x) 138 139 #--------------------------------------------------------
140 - def _get_address(self):
141 return self.org_unit.address
142 143 address = property(_get_address, lambda x:x) 144 145 # def _set_address(self, address): 146 # self['pk_address'] = address['pk_address'] 147 # self.save() 148 # address = property(_get_address, _set_address) 149 150 #--------------------------------------------------------
151 - def _get_vcf(self):
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 #--------------------------------------------------------
182 - def export_as_mecard(self, filename=None):
183 if filename is None: 184 filename = gmTools.get_unique_filename ( 185 prefix = 'gm-praxis-', 186 suffix = '.mcf' 187 ) 188 with io.open(filename, mode = 'wt', encoding = 'utf8') as mecard_file: 189 mecard_file.write(self.MECARD) 190 return filename
191 192 #--------------------------------------------------------
193 - def _get_mecard(self):
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 #------------------------------------------------------------
220 -def lock_praxis_branch(pk_praxis_branch=None, exclusive=False):
221 return gmPG2.lock_row(table = 'dem.praxis_branch', pk = pk_praxis_branch, exclusive = exclusive)
222 223 #------------------------------------------------------------
224 -def unlock_praxis_branch(pk_praxis_branch=None, exclusive=False):
225 return gmPG2.unlock_row(table = 'dem.praxis_branch', pk = pk_praxis_branch, exclusive = exclusive)
226 227 #------------------------------------------------------------
228 -def get_praxis_branches(order_by=None):
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 #------------------------------------------------------------
239 -def get_praxis_branch_by_org_unit(pk_org_unit=None):
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 #------------------------------------------------------------
248 -def create_praxis_branch(pk_org_unit=None):
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 #------------------------------------------------------------
266 -def create_praxis_branches(pk_org_units=None):
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 #------------------------------------------------------------
285 -def delete_praxis_branch(pk_praxis_branch=None):
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 #------------------------------------------------------------
295 -def delete_praxis_branches(pk_praxis_branches=None, except_pk_praxis_branches=None):
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 #============================================================
335 -class gmCurrentPraxisBranch(gmBorg.cBorg):
336
337 - def __init__(self, branch=None):
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 # user wants copy of current branch 347 if branch is None: 348 return None 349 350 # must be cPraxisBranch instance, then 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 # __getattr__ handling 366 #--------------------------------------------------------
367 - def __getattr__(self, attribute):
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 # __get/setitem__ handling 376 #--------------------------------------------------------
377 - def __getitem__(self, attribute = None):
378 """Return any attribute if known how to retrieve it by proxy.""" 379 return self.branch[attribute]
380 381 #--------------------------------------------------------
382 - def __setitem__(self, attribute, value):
383 self.branch[attribute] = value
384 385 #-------------------------------------------------------- 386 # waiting list handling 387 #--------------------------------------------------------
388 - def remove_from_waiting_list(self, pk=None):
389 cmd = 'DELETE FROM clin.waiting_list WHERE pk = %(pk)s' 390 args = {'pk': pk} 391 gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}]) 392 gmHooks.run_hook_script(hook = 'after_waiting_list_modified')
393 394 #--------------------------------------------------------
395 - def update_in_waiting_list(self, pk = None, urgency = 0, comment = None, zone = None):
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 #--------------------------------------------------------
415 - def raise_in_waiting_list(self, current_position=None):
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 #--------------------------------------------------------
425 - def lower_in_waiting_list(self, current_position=None):
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 # properties 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 #--------------------------------------------------------
449 - def _set_helpdesk(self, helpdesk):
450 return
451
452 - def _get_helpdesk(self):
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 #--------------------------------------------------------
477 - def _get_db_logon_banner(self):
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
483 - def _set_db_logon_banner(self, banner):
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 #--------------------------------------------------------
497 - def _set_workplace(self, workplace):
498 # maybe later allow switching workplaces on the fly 499 return True
500
501 - def _get_workplace(self):
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 #--------------------------------------------------------
529 - def _set_workplaces(self, val):
530 pass
531
532 - def _get_workplaces(self):
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 #--------------------------------------------------------
539 - def _get_user_email(self):
540 # FIXME: get this from the current users staff record in the database 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
553 - def _set_user_email(self, val):
554 prefs_file = _cfg.get(option = 'user_preferences_file') 555 gmCfg2.set_option_in_INI_file ( 556 filename = prefs_file, 557 group = 'preferences', 558 option = 'user email', 559 value = val 560 ) 561 _cfg.reload_file_source(file = prefs_file)
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
577 - def run_tests():
578 prac = gmCurrentPraxisBranch() 579 # print "help desk:", prac.helpdesk 580 # print "active workplace:", prac.active_workplace 581 582 old_banner = prac.db_logon_banner 583 test_banner = 'a test banner' 584 prac.db_logon_banner = test_banner 585 if prac.db_logon_banner != test_banner: 586 print(('Cannot set logon banner to', test_banner)) 587 return False 588 prac.db_logon_banner = '' 589 if prac.db_logon_banner != '': 590 print('Cannot set logon banner to ""') 591 return False 592 prac.db_logon_banner = old_banner 593 594 return True
595 596 # if not run_tests(): 597 # print "regression tests failed" 598 # print "regression tests succeeded" 599 600 for b in get_praxis_branches(): 601 print((b.format())) 602 603 #============================================================ 604