[domino] finish family update workflow

- when creating or updating a family, store the family.code_interne value into
  the user object for later retrieval,
- add web service API to retrieve person to contact for children
This commit is contained in:
Benjamin Dauvergne 2012-09-24 11:19:29 +02:00 committed by Frédéric Péters
parent 20ebbe3a02
commit 84fd22a049
5 changed files with 350 additions and 141 deletions

View File

@ -21,24 +21,32 @@ def synchronize_domino(publisher):
client.clear_cache()
users = User.values()
users_by_mail = dict(((user.email, user) for user in users))
users_by_code_interne = {}
for user in users:
if hasattr(user, 'abelium_domino_code_famille'):
users_by_code_interne[user.abelium_domino_code_famille] = user
try:
invoices = client.get_invoices(state='TOUTES')
invoices = client.invoices
except abelium_domino_ws.DominoException, e:
logger.error('failure to retrieve invoice list from domino '
logger.debug('domino cron: failure to retrieve invoice list from domino '
'for synchronization [error:%s]', e)
return
# import new invoices
for invoice in invoices:
logger.debug('domino cron: retrieved %i invoices', len(invoices))
for invoice_id, invoice in invoices.iteritems():
user = None
for email in (invoice.family.email_pere, invoice.family.email_mere,
invoice.family.adresse_internet):
user = users_by_mail.get(email)
if user:
break
else:
continue
if invoice.family.code_interne in users_by_code_interne:
user = users_by_code_interne[invoice.family.code_interne]
if user is None:
for email in (invoice.family.email_pere, invoice.family.email_mere,
invoice.family.adresse_internet):
user = users_by_mail.get(email)
if user:
break
else:
continue
external_id = '%s%s' % (DOMINO_ID_PREFIX, invoice.id)
payment_invoice = Invoice.get_on_index(external_id, 'external_id',)
payment_invoice = Invoice.get_on_index(external_id, 'external_id', ignore_errors=True)
if payment_invoice:
continue
payment_invoice = Invoice()
@ -51,13 +59,13 @@ def synchronize_domino(publisher):
payment_invoice.date = invoice.creation
payment_invoice.domino_synchro_date = datetime.now()
payment_invoice.store()
logger.info('remote invoice %s for family %s added to user %s invoices with id %s',
logger.info('domino cron: remote invoice %s for family %s added to user %s invoices with id %s',
invoice.id, invoice.family.id, user.id, payment_invoice.id)
# update invoices
invoices_ids = dict(((invoice.id, invoice) for invoice in invoices))
invoices_ids = dict(invoices.iteritems())
for payment_invoice in Invoice.values():
if not payment_invoice.external_id.starswith(DOMINO_ID_PREFIX):
if payment_invoice.external_id is None or not payment_invoice.external_id.startswith(DOMINO_ID_PREFIX):
continue # not a payment related to domino we skip
i = payment_invoice.external_id[len(DOMINO_ID_PREFIX):]
i = int(i)
@ -67,12 +75,12 @@ def synchronize_domino(publisher):
# invoice has been paid (locally or not) but remote invoice has
# been deleted do, we do nothing.
continue
if getattr(payment_invoice, 'domino_knows_its_paid'):
if getattr(payment_invoice, 'domino_knows_its_paid', None) or getattr(payment_invoice, 'paid_by_domino', None):
# synchronization of payment already done, skip
continue
transactions = Transaction.get_with_indexed_value('invoice_ids', payment_invoice.id)
if not transactions:
logger.warning("invoice %s is marked paid but does "
logger.warning("domino cron: invoice %s is marked paid but does "
"not have any linked transaction.", payment_invoice.id)
details = '' # no details about the payment, problem
else:
@ -83,18 +91,18 @@ def synchronize_domino(publisher):
client.pay_invoice([invoice], invoice.montant, details,
payment_invoice.paid_date)
except abelium_domino_ws.DominoException, e:
logger.error('invoice %s has been paid, but the remote system '
logger.error('domino cron: invoice %s has been paid, but the remote system '
'is unreachable, notification will be done again '
'later [error: %s]', invoice.id, e)
else:
# memorize the date of synchronization
payment_invoice.domino_knows_its_paid = datetime.now()
payment_invoice.store()
logger.info('invoice %s has been paid; remote system has been '
logger.info('domino cron: domino: invoice %s has been paid; remote system has been '
'notified', payment_invoice.id)
else: # unpaid
if not invoice:
logger.info('remote invoice %s disapearred, so its '
logger.info('domino cron: remote invoice %s disapearred, so its '
'still-unpaid local counterpart invoice %s was deleted.',
i, payment_invoice.id)
payment_invoice.remove_self()
@ -104,11 +112,11 @@ def synchronize_domino(publisher):
payment_invoice.paid_date = datetime.now()
payment_invoice.paid_by_domino = True
payment_invoice.store()
logging.info('remote invoice %s has beend paid, '
logger.info('domino cron: remote invoice %s has beend paid, '
'local invoice %s of user %s is now marked as paid.',
invoice.id, payment_invoice.id, payment_invoice.user_id)
else: # not invoice.paid()
pass # still waiting for the payment
get_publisher_class().register_cronjob(CronJob(function=synchronize_domino,
hours=range(24), minutes=range(0,60,10)))
hours=range(0, 24), minutes=range(0, 60)))

View File

@ -1,4 +1,4 @@
from quixote import get_publisher, redirect
from quixote import get_publisher, redirect, get_request
from quixote.directory import Directory, AccessControlled
from qommon import get_cfg
@ -7,6 +7,7 @@ from qommon.admin.menu import html_top
from payments import Regie
# constants
ABELIUM_DOMINO = 'abelium_domino'
ACTIVATED = 'activated'
@ -32,20 +33,29 @@ def is_activated(publisher=None):
cfg = get_abelium_cfg(publisher)
return cfg.get(ACTIVATED, False) and abelium_domino_ws is not None
_WS_CACHE = None
def get_client(publisher=None):
global _WS_CACHE
publisher = publisher or get_publisher()
cfg = get_abelium_cfg(publisher)
if _WS_CACHE is None:
_WS_CACHE = abelium_domino_ws.DominoWs(
url=cfg.get(WSDL_URL, ''),
domain=cfg.get(DOMAIN,''),
login=cfg.get(LOGIN, ''),
password=cfg.get(PASSWORD, ''),
location=cfg.get(SERVICE_URL))
return _WS_CACHE
publisher._ws_cache = abelium_domino_ws.DominoWs(
url=cfg.get(WSDL_URL, ''),
domain=cfg.get(DOMAIN,''),
login=cfg.get(LOGIN, ''),
password=cfg.get(PASSWORD, ''),
location=cfg.get(SERVICE_URL))
return publisher._ws_cache
def get_family(user, publisher=None):
family = None
if user is None:
return None
client = get_client(publisher)
if hasattr(user, 'abelium_domino_code_famille'):
family = client.get_family_by_code_interne(
user.abelium_domino_code_famille)
if family is None and user.email:
family = client.get_family_by_mail(user.email)
return family
def get_invoice_regie(publisher=None):
cfg = get_abelium_cfg(publisher)
@ -59,16 +69,18 @@ class AbeliumDominoDirectory(Directory):
label = N_('Domino')
def debug [html] (self):
from abelium_domino_vars import SESSION_CACHE
html_top(ABELIUM_DOMINO)
'<p>code interne: %s</p>' % getattr(get_request().user, str('abelium_domino_code_famille'), None)
'<dl>'
context = get_publisher().substitutions.get_context_variables()
for var in sorted(context.keys()):
value = context[var]
if value:
'<dt>%s</dt>' % var
'<dd>%s</dt>' % unicode(value).encode(get_publisher().site_charset)
'<dd>%s</dt>' % value
'</dl>'
delattr(get_request().session, SESSION_CACHE)
def _q_index [html] (self):
publisher = get_publisher()
@ -98,6 +110,14 @@ class AbeliumDominoDirectory(Directory):
'activated because of this error when '
'loading it: %r') % import_error
'<p class="errornotice">%s</p>' % message
'<dl>'
context = get_publisher().substitutions.get_context_variables()
for var in sorted(context.keys()):
value = context[var]
if value:
'<dt>%s</dt>' % var
'<dd>%s</dt>' % unicode(value).encode(get_publisher().site_charset)
'</dl>'
form_desc = (
# name, required, title, kind
@ -129,4 +149,3 @@ class AbeliumDominoDirectory(Directory):
form.add_submit('cancel', _('Cancel'))
return form

View File

@ -1,10 +1,12 @@
from decimal import Decimal
import logging
from quixote.publish import get_publisher
from qommon.substitution import Substitutions
from publisher import WcsPublisher
from abelium_domino_ui import (is_activated, abelium_domino_ws, get_client)
from abelium_domino_ui import (is_activated, abelium_domino_ws, get_client, get_family)
SESSION_CACHE = 'abelium_domino_variable_cache'
@ -31,8 +33,8 @@ class DominoVariables(object):
return cache
# call the web service
try:
client = get_client()
family = client.get_family_by_mail(self.request.user.email)
charset = get_publisher().site_charset
family = get_family(self.request.user)
if family:
family.complete()
for i, child in enumerate(family.children):
@ -40,10 +42,17 @@ class DominoVariables(object):
v = getattr(child, name, None)
if v is None:
continue
if hasattr(v, 'encode'):
v = v.encode(charset)
vars[self.CHILD_VARIABLE_TEMPLATE % (name, i+1)] = v
vars[self.VARIABLE_TEMPLATE % 'nombre_enfants'] = len(family.children)
for remote_name, name, converted, desc in self.FAMILY_COLUMNS:
if hasattr(family, name):
v = getattr(family, name)
if v is None:
continue
if hasattr(v, 'encode'):
v = v.encode(charset)
vars[self.VARIABLE_TEMPLATE % name] = v
amount = Decimal(0)
for invoice in family.invoices:
@ -52,17 +61,17 @@ class DominoVariables(object):
vars['user_famille_reste_du'] = str(amount)
except abelium_domino_ws.DominoException:
logging.exception('unable to call the domino ws for user %s', self.request.user.id)
setattr(self.request.session, SESSION_CACHE, vars)
self.request.session.store()
setattr(self.request.session, SESSION_CACHE, vars)
self.request.session.store()
return vars
def get_substitution_variables_list(cls):
if not is_activated():
return ()
vars = []
for remote_name, name, converted, desc in self.FAMILY_COLUMNS:
for remote_name, name, converted, desc in cls.FAMILY_COLUMNS:
vars.append((_('Domino'), cls.VARIABLE_TEMPLATE % name, desc))
for remote_name, name, converted, desc in self.CHILD_COLUMNS:
for remote_name, name, converted, desc in cls.CHILD_COLUMNS:
vars.append((_('Domino'), cls.CHILD_VARIABLE_TEMPLATE % (name, '{0,1,2,..}'), desc))
return vars
get_substitution_variables_list = classmethod(get_substitution_variables_list)

View File

@ -1,36 +1,144 @@
from quixote import get_request
import re
import time
from quixote import get_request, get_publisher, get_session
from quixote.directory import Directory
from qommon.substitution import Substitutions
from qommon.form import Form, StringWidget
import qommon.misc
from qommon import get_logger
from publisher import WcsPublisher
from wcs.workflows import Workflow, WorkflowStatusItem, register_item_class, \
from wcs.workflows import Workflow, WorkflowStatusJumpItem, register_item_class, \
render_list_of_roles, get_role_translation
from wcs.forms.common import FormStatusPage
from abelium_domino_ui import (is_activated, abelium_domino_ws, get_client, get_family)
import abelium_domino_ws
class AbeliumDominoRegisterFamilyWorkflowStatusItem(WorkflowStatusItem):
class AbeliumDominoRegisterFamilyWorkflowStatusItem(WorkflowStatusJumpItem):
status = None
description = N_('Abelium Domino: Register a Family')
key = 'abelium-domino-register-family'
endpoint = False
label = None
def render_as_line(self):
return _('Register a Family into Abelium Domino')
def get_parameters(self):
return ()
def get_family(self, formdata):
try:
user = formdata.get_user()
if user:
family = get_family(user)
if family:
family.complete()
return family
except abelium_domino_ws.DominoException:
pass
return None
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
pass
def fill_form(self, form, formdata, user):
family = self.get_family(formdata)
if 'family_id' not in form._names:
form.add(StringWidget, 'family_id', title=_('Family internal code'),
value=family and family.code_interne.encode('utf8'))
if not family:
form.add_submit('create_button%s' % self.id, _('Create the family'))
form.add_submit('update_button%s' % self.id, _('Update the family'))
def perform(self, formdata):
family_data = {}
for k, v in formdata.get_as_dict().items():
if k.startswith('var_'):
family_data['domino_'+k] = v
# XXX: store family data locally, this should be changed to send it
# over to the abelium domino web service.
get_request().user.family_data = family_data
get_request().user.store()
def update(self, form, formdata, user, evo):
fid_widget = form.get_widget('family_id')
code_interne = fid_widget.parse()
try:
code_interne = int(code_interne)
except ValueError:
raise ValueError('Le code interne est invalide')
code_interne = '%05d' % code_interne
family = get_client().get_family_by_code_interne(code_interne)
if not family:
raise ValueError('Le code interne est invalide')
family.complete()
self.extract_family(form, formdata, user, evo, family)
family.save()
return family
def create(self, form, formdata, user, evo):
family = abelium_domino_ws.Family(client=get_client())
self.extract_family(form, formdata, user, evo, family)
return family
def extract_family(self, form, formdata, user, evo, family):
formdef = formdata.formdef
children = [abelium_domino_ws.Child() for i in range(5)]
max_i = 0
for field in formdef.fields:
value = formdata.data.get(field.id)
if value in (None, ''):
continue
if hasattr(field, 'date_in_the_past'):
value = time.strftime('%Y%m%d', value)
value = unicode(value, 'utf8')
if field.prefill and \
field.prefill.get('type') == 'formula':
v = field.prefill.get('value', '').strip()
i = None
name = None
m = re.search('domino_var_([^ ]*)_enfant([0-9]*)', v)
m2 = re.search('domino_var_([^ ]*)', v)
if m:
name, i = m.groups()
try:
i = int(i)
except ValueError:
continue
max_i = max(i, max_i)
print 'enfant', name, i-1, value
setattr(children[i-1], name, value)
elif m2:
name = m2.group(1)
print 'family', name, value
setattr(family, name, value)
for child1, child2 in zip(family.children, children):
child1.__dict__.update(child2.__dict__)
family.save()
if max_i > len(family.children): # add new children
for child in children[len(family.children):max_i]:
family.add_child(child)
def submit_form(self, form, formdata, user, evo):
logger = get_logger()
try:
if form.get_submit() == 'update_button%s' % self.id:
family = self.update(form, formdata, user, evo)
msg = _('Sucessfully updated the family %s')
log_msg = _('Sucessfully updated the family %s of %s')
elif form.get_submit() == 'create_button%s' % self.id:
family = self.create(form, formdata, user, evo)
msg = _('Sucessfully created the family %s')
log_msg = _('Sucessfully created the family %s of %s')
else:
raise NotImplemented
code_interne = family.code_interne.encode('utf8')
msg = msg % code_interne
logger.info(_('Sucessfully created the family %s of %s'),
code_interne, formdata.get_user())
form_user = formdata.get_user()
form_user.abelium_domino_code_famille = code_interne
form_user.store()
except Exception, e:
raise
if form.get_submit() == 'update_button%s' % self.id:
msg = _('Unable to update family: %s') % str(e)
elif form.get_submit() == 'create_button%s' % self.id:
msg = _('Unable to create family: %s') % str(e)
evo.comment = msg
logger.exception(msg % formdata.get_user())
else:
evo.comment = msg
wf_status = self.get_status()
if wf_status:
evo.status = 'wf-%s' % wf_status.id
return False
register_item_class(AbeliumDominoRegisterFamilyWorkflowStatusItem)

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
import time
import datetime
from xml.etree import ElementTree as etree
import logging
@ -20,7 +21,16 @@ def unicode_and_strip(x):
return unicode(x).strip()
def strip_and_int(x):
return int(x.strip())
try:
return int(x.strip())
except ValueError:
return None
def strip_and_date(x):
try:
return datetime.datetime.strptime(x.strip(), '%Y%m%d').date()
except ValueError:
return None
def parse_date(date_string):
if date_string:
@ -38,8 +48,11 @@ def object_cached(function):
def decorated_function(self, *args, **kwargs):
cache_name = '__%s_cache' % function.__name__
if not hasattr(self, cache_name):
setattr(self, cache_name, {})
d = getattr(self, cache_name)
setattr(self, cache_name, (time.time(), {}))
t, d = getattr(self, cache_name)
if time.time() - t > 30:
setattr(self, cache_name, (time.time(), {}))
t, d = getattr(self, cache_name)
k = tuple(*args) + tuple(sorted(kwargs.items()))
if not k in d:
d[k] = function(self, *args, **kwargs)
@ -73,58 +86,79 @@ class SimpleObject(object):
v = getattr(self, local_name, None)
if v is None:
continue
v = unicode(v).encode('utf-8')
l.append('{0}: "{1}"'.format(remote_name, v))
return ','.join(l)
l.append(u'{0}: "{1}"'.format(remote_name, v))
return u','.join(l)
def debug(self):
'''Output a debugging view of this object'''
res = ''
for remote_name, name, converter, desc in self.MORE_COLUMNS or self.COLUMNS:
if hasattr(self, name):
print name, ':', getattr(self, name)
res += name + ':' + repr(getattr(self, name)) + '\n'
return res
def __int__(self):
'''Return the object id'''
return self.id
class UrgentContact(SimpleObject):
COLUMNS = (
('IDENFANTS', 'id_enfant', strip_and_int, 'IDENFANTS'),
('IDCONTACT_AUTORISE', 'id', strip_and_int, 'IDCONTACT_AUTORISE'),
('LIENFAMILLE_CH', 'lien_de_famille', unicode_and_strip, 'LIENFAMILLE_CH'),
('PERE_MERE_CH', 'lien_pere_ou_pere', unicode_and_strip, 'PERE_MERE_CH'),
('IDFAMILLES', 'id_famille', unicode_and_strip, 'IDFAMILLES'),
('TYPE_CH', 'type', unicode_and_strip, 'TYPE_CH'),
('NOM_CH', 'nom', unicode_and_strip, 'NOM_CH'),
('PRENOM_CH', 'prenom', unicode_and_strip, 'PRENOM_CH'),
('RUE_CH', 'rue', unicode_and_strip, 'RUE_CH'),
('RUE2_CH', 'rue2', unicode_and_strip, 'RUE2_CH'),
('RUE3_CH', 'rue3', unicode_and_strip, 'RUE3_CH'),
('CODEPOSTAL_CH', 'code_postal', unicode_and_strip, 'CODEPOSTAL_CH'),
('VILLE_CH', 'ville', unicode_and_strip, 'VILLE_CH'),
('TELEPHONE_CH', 'telephone', unicode_and_strip, 'TELEPHONE_CH'),
('TELEPHONE2_CH', 'telephone2', unicode_and_strip, 'TELEPHONE2_CH'),
('ADRESSEINT_CH', 'adresse_internet', unicode_and_strip, 'ADRESSEINT_CH'),
)
class Child(SimpleObject):
COLUMNS = (
('IDENFANTS', 'id', strip_and_int, 'Identifiant de ENFANTS'),
('NOM_CH', 'nom',unicode_and_strip, 'Nom'),
('PRENOM_CH', 'prenom',unicode_and_strip, 'Prénom'),
('NAISSANCE_DA', 'naissance',unicode_and_strip, 'Date de Naissance'),
('COMMENTAIRE_ME', 'commentaire',unicode_and_strip, 'Commentaires / Notes'),
('IDFAMILLES', 'id_famille',unicode_and_strip, 'IDFAMILLES'),
('CODEPOSTAL_CH', 'code_postal',unicode_and_strip, 'Code Postal'),
('VILLE_CH', 'ville',unicode_and_strip, 'Ville'),
('CODEINTERNE_CH', 'code_interne',unicode_and_strip, 'Code Interne'),
('LIEUNAISSANCE_CH', 'lieu_naissance',unicode_and_strip, 'Lieu de Naissance'),
('DEPNAISSANCE_CH', 'departement_naissance',unicode_and_strip, 'Département Naissance'),
('NUMSECU_CH', 'num_securite_sociale',unicode_and_strip, 'N° de SECU'),
('NATIONALITE_CH', 'nationalite',unicode_and_strip, 'Nationalité'),
('PRENOM2_CH', 'prenom2',unicode_and_strip, 'Prénom 2'),
('SEXE_CH', 'sexe',unicode_and_strip, 'Sexe'),
('IDTABLELIBRE1', 'IDTABLELIBRE1',unicode_and_strip, 'IDTABLELIBRE1'),
('IDTABLELIBRE2', 'IDTABLELIBRE2',unicode_and_strip, 'IDTABLELIBRE2'),
('IDTABLELIBRE3', 'IDTABLELIBRE3',unicode_and_strip, 'IDTABLELIBRE3'),
('IDTABLELIBRE4', 'IDTABLELIBRE4',unicode_and_strip, 'IDTABLELIBRE4'),
('CHAMPLIBRE1_CH', 'CHAMPLIBRE1_CH',unicode_and_strip, 'Valeur Champ Libre 1'),
('CHAMPLIBRE2_CH', 'CHAMPLIBRE2_CH',unicode_and_strip, 'Valeur Champ Libre 2'),
('CHAMPCALCULE1_CH', 'CHAMPCALCULE1_CH',unicode_and_strip, 'Valeur Champ Calculé 1'),
('CHAMPCALCULE2_CH', 'CHAMPCALCULE2_CH',unicode_and_strip, 'Valeur Champ Calculé 2'),
('SOMMEIL_ME', 'sommeil',unicode_and_strip, 'Sommeil'),
('ACTIVITE_ME', 'activite',unicode_and_strip, 'Activités'),
('HABITUDE_ME', 'habitude',unicode_and_strip, 'Habitudes'),
('PHOTO_CH', 'photographie',unicode_and_strip, 'Photographie'),
('NUMCOMPTE_CH', 'numcompte',unicode_and_strip, 'N° Compte Comptable'),
('TELEPHONE_CH', 'telephone',unicode_and_strip, 'Téléphone'),
('IDFAMILLES2', 'id_famille2',unicode_and_strip, 'Identifiant famille 2'),
('PERE_CH', 'pere',unicode_and_strip, 'Nom du père'),
('MERE_CH', 'mere',unicode_and_strip, 'Nom de la mère'),
('AUTOPARENTALEMERE_IN', 'autorisation_parentale_mere',unicode_and_strip, 'Autorisation Parentale Mère'),
('AUTOPARENTALEPERE_IN', 'autorisation_parentale_pere',unicode_and_strip, 'Autorisation Parentale de Père'),
('IDPORTAIL_ENFANTS', 'id_portail_enfants',unicode_and_strip, 'Identifiant de PORTAIL_ENFANTS'),
('ADRESSEINT_CH', 'adresse_internet',unicode_and_strip, 'Adresse Internet'),
('NOM_CH', 'nom', unicode_and_strip, 'Nom'),
('PRENOM_CH', 'prenom', unicode_and_strip, 'Prénom'),
('NAISSANCE_DA', 'date_naissance', strip_and_date, 'Date de Naissance'),
('COMMENTAIRE_ME', 'commentaire', unicode_and_strip, 'Commentaires / Notes'),
('IDFAMILLES', 'id_famille', unicode_and_strip, 'IDFAMILLES'),
('CODEPOSTAL_CH', 'code_postal', unicode_and_strip, 'Code Postal'),
('VILLE_CH', 'ville', unicode_and_strip, 'Ville'),
('CODEINTERNE_CH', 'code_interne', unicode_and_strip, 'Code Interne'),
('LIEUNAISSANCE_CH', 'lieu_naissance', unicode_and_strip, 'Lieu de Naissance'),
('DEPNAISSANCE_CH', 'departement_naissance', unicode_and_strip, 'Département Naissance'),
('NUMSECU_CH', 'num_securite_sociale', unicode_and_strip, 'N° de SECU'),
('NATIONALITE_CH', 'nationalite', unicode_and_strip, 'Nationalité'),
('PRENOM2_CH', 'prenom2', unicode_and_strip, 'Prénom 2'),
('SEXE_CH', 'sexe', unicode_and_strip, 'Sexe'),
('IDTABLELIBRE1', 'IDTABLELIBRE1', unicode_and_strip, 'IDTABLELIBRE1'),
('IDTABLELIBRE2', 'IDTABLELIBRE2', unicode_and_strip, 'IDTABLELIBRE2'),
('IDTABLELIBRE3', 'IDTABLELIBRE3', unicode_and_strip, 'IDTABLELIBRE3'),
('IDTABLELIBRE4', 'IDTABLELIBRE4', unicode_and_strip, 'IDTABLELIBRE4'),
('CHAMPLIBRE1_CH', 'CHAMPLIBRE1_CH', unicode_and_strip, 'Valeur Champ Libre 1'),
('CHAMPLIBRE2_CH', 'CHAMPLIBRE2_CH', unicode_and_strip, 'Valeur Champ Libre 2'),
('CHAMPCALCULE1_CH', 'CHAMPCALCULE1_CH', unicode_and_strip, 'Valeur Champ Calculé 1'),
('CHAMPCALCULE2_CH', 'CHAMPCALCULE2_CH', unicode_and_strip, 'Valeur Champ Calculé 2'),
('SOMMEIL_ME', 'sommeil', unicode_and_strip, 'Sommeil'),
('ACTIVITE_ME', 'activite', unicode_and_strip, 'Activités'),
('HABITUDE_ME', 'habitude', unicode_and_strip, 'Habitudes'),
('PHOTO_CH', 'photographie', unicode_and_strip, 'Photographie'),
('NUMCOMPTE_CH', 'numcompte', unicode_and_strip, 'N° Compte Comptable'),
('TELEPHONE_CH', 'telephone', unicode_and_strip, 'Téléphone'),
('IDFAMILLES2', 'id_famille2', unicode_and_strip, 'Identifiant famille 2'),
('PERE_CH', 'pere', unicode_and_strip, 'Nom du père'),
('MERE_CH', 'mere', unicode_and_strip, 'Nom de la mère'),
('AUTOPARENTALEMERE_IN', 'autorisation_parentale_mere', unicode_and_strip, 'Autorisation Parentale Mère'),
('AUTOPARENTALEPERE_IN', 'autorisation_parentale_pere', unicode_and_strip, 'Autorisation Parentale de Père'),
('IDPORTAIL_ENFANTS', 'id_portail_enfants', unicode_and_strip, 'Identifiant de PORTAIL_ENFANTS'),
('ADRESSEINT_CH', 'adresse_internet', unicode_and_strip, 'Adresse Internet'),
)
def save(self):
@ -132,6 +166,7 @@ class Child(SimpleObject):
self.client.update_child(self)
else:
self.id = self.client.add_child(self)
self.client.clear_cache()
class Family(SimpleObject):
COLUMNS = (
@ -140,6 +175,7 @@ class Family(SimpleObject):
('EMAILPERE_CH', 'email_pere', unicode_and_strip, 'email du père'),
('EMAILMERE_CH', 'email_mere', unicode_and_strip, 'email de la mère'),
('ADRESSEINT_CH', 'adresse_internet', unicode_and_strip, 'adresse internet'),
('CODEINTERNE_CH', 'code_interne', unicode_and_strip, 'code interne'),
)
MORE_COLUMNS = (
@ -158,15 +194,15 @@ class Family(SimpleObject):
('TELECOPIE2_CH', 'telecopie2', unicode_and_strip, 'télécopie 2'),
('ADRESSEINT_CH', 'adresse_internet', unicode_and_strip, 'adresse internet'),
('SITUATION_CH', 'situation', unicode_and_strip, 'situation familiale'),
('REVENUMENSUEL_MO', 'revenu_mensuel_mo', unicode_and_strip, 'revenu mensuel de la famille'),
('REVENUANNUEL_MO', 'revenu_annuel_mo', unicode_and_strip, 'revenu annuel de la famille'),
('QUOTIENTFAMILIAL_MO', 'quotient_familial_mo', unicode_and_strip, 'quotient familial'),
('NBTOTALENFANTS_EN', 'nb_total_enfants_en', unicode_and_strip, 'nombre total d\'enfants'),
('NBENFANTSACHARGE_EN', 'nb_enfants_a_charge_en', unicode_and_strip, 'nombre d\'enfants à charge'),
('REVENUMENSUEL_MO', 'revenu_mensuel', unicode_and_strip, 'revenu mensuel de la famille'),
('REVENUANNUEL_MO', 'revenu_annuel', unicode_and_strip, 'revenu annuel de la famille'),
('QUOTIENTFAMILIAL_MO', 'quotient_familial', unicode_and_strip, 'quotient familial'),
('NBTOTALENFANTS_EN', 'nb_total_enfants', unicode_and_strip, 'nombre total d\'enfants'),
('NBENFANTSACHARGE_EN', 'nb_enfants_a_charge', unicode_and_strip, 'nombre d\'enfants à charge'),
('NOMPERE_CH', 'nom_pere', unicode_and_strip, 'monsieur'),
('PRENOMPERE_CH', 'prenom_pere', unicode_and_strip, 'prénom monsieur'),
('AUTOPARENTALEPERE_IN', 'autoparentale_pere_in', unicode_and_strip, 'autorisation parentale de père'),
('DATENAISPERE_DA', 'date_naissance_pere', unicode_and_strip, 'date de naisance du père'),
('AUTOPARENTALEPERE_IN', 'autoparentale_pere', unicode_and_strip, 'autorisation parentale de père'),
('DATENAISPERE_DA', 'date_naissance_pere', strip_and_date, 'date de naisance du père'),
('DEPNAISPERE_EN', 'departement_naissance_pere', unicode_and_strip, 'département de naissance du père'),
('LIEUNAISPERE_CH', 'lieu_naissance_pere', unicode_and_strip, 'lieu de naissance du père'),
('RUEPERE_CH', 'rue_pere', unicode_and_strip, 'rue père'),
@ -176,29 +212,29 @@ class Family(SimpleObject):
('VILLEPERE_CH', 'ville_pere', unicode_and_strip, 'ville père'),
('TELEPHONEPERE_CH', 'telephone_pere', unicode_and_strip, 'téléphone père'),
('TELEPHONE2PERE_CH', 'telephone2_pere', unicode_and_strip, 'téléphone 2 père'),
('TELPERE_LR_IN', 'tel_pere_liste_rouge_in', unicode_and_strip, 'téléphone liste rouge père'),
('TEL2PERE_LR_IN', 'tel2_pere_liste_rouge_in', unicode_and_strip, 'téléphone 2 liste rouge père'),
('TEL_LR_IN', 'tel_liste_rourge_in', unicode_and_strip, 'téléphone liste rouge'),
('TEL2_LR_IN', 'tel2_liste_rouge_in', unicode_and_strip, 'téléphone 2 liste rouge'),
('TELPERE_LR_IN', 'tel_pere_liste_rouge', unicode_and_strip, 'téléphone liste rouge père'),
('TEL2PERE_LR_IN', 'tel2_pere_liste_rouge', unicode_and_strip, 'téléphone 2 liste rouge père'),
('TEL_LR_IN', 'tel_liste_rourge', unicode_and_strip, 'téléphone liste rouge'),
('TEL2_LR_IN', 'tel2_liste_rouge', unicode_and_strip, 'téléphone 2 liste rouge'),
('NOMMERE_CH', 'nom_mere', unicode_and_strip, 'madame'),
('PRENOMMERE_CH', 'prenom_mere', unicode_and_strip, 'prénom madame'),
('AUTOPARENTALEMERE_IN', 'autoparentale_mere_in', unicode_and_strip, 'autorisation parentale mère'),
('DATENAISMERE_DA', 'date_naissance_mere_da', unicode_and_strip, 'date de naissance de la mère'),
('DEPNAISMERE_EN', 'departement_naissance_mere_en', unicode_and_strip, 'département de naissance de la mère'),
('AUTOPARENTALEMERE_IN', 'autoparentale_mere', unicode_and_strip, 'autorisation parentale mère'),
('DATENAISMERE_DA', 'date_naissance_mere', strip_and_date, 'date de naissance de la mère'),
('DEPNAISMERE_EN', 'departement_naissance_mere', unicode_and_strip, 'département de naissance de la mère'),
('LIEUNAISMERE_CH', 'lieu_naissance_mere', unicode_and_strip, 'lieu de naissance de la mère'),
('RUEMERE_CH', 'rue_mere', unicode_and_strip, 'rue mère'),
('REVMENSUELPERE_MO', 'revenu_mensuel_pere_mo', unicode_and_strip, 'revenu mensuel du père'),
('REVMENSUELPERE_MO', 'revenu_mensuel_pere', unicode_and_strip, 'revenu mensuel du père'),
('RUE2MERE_CH', 'rue2_mere', unicode_and_strip, 'rue 2 mère'),
('RUE3MERE_CH', 'rue3_mere', unicode_and_strip, 'rue 3 mère'),
('CODEPOSTALMERE_CH', 'code_postal_mere', unicode_and_strip, 'code postal de la mère'),
('VILLEMERE_CH', 'ville_mere', unicode_and_strip, 'ville de la mère'),
('REVMENSUELMERE_MO', 'revenu_mensuel_mere_mo', unicode_and_strip, 'revenu mensuel mère'),
('REVANNUELPERE_MO', 'revenu_annuel_pere_mo', unicode_and_strip, 'revenu annuel père'),
('REVANNUELMERE_MO', 'revenu_annuel_mere_mo', unicode_and_strip, 'revenu annuel mère'),
('REVMENSUELMERE_MO', 'revenu_mensuel_mere', unicode_and_strip, 'revenu mensuel mère'),
('REVANNUELPERE_MO', 'revenu_annuel_pere', unicode_and_strip, 'revenu annuel père'),
('REVANNUELMERE_MO', 'revenu_annuel_mere', unicode_and_strip, 'revenu annuel mère'),
('TELEPHONEMERE_CH', 'telephone_mere', unicode_and_strip, 'téléphone mère'),
('TELEPHONE2MERE_CH', 'telephone2_mere', unicode_and_strip, 'téléphone 2 mère'),
('TELMERE_LR_IN', 'telephone_mere_liste_rouge_in', unicode_and_strip, 'téléphone liste rouge mère'),
('TEL2MERE_LR_IN', 'telephone2_mere_liste_rouge_in', unicode_and_strip, 'téléphone 2 liste rouge mère'),
('TELMERE_LR_IN', 'telephone_mere_liste_rouge', unicode_and_strip, 'téléphone liste rouge mère'),
('TEL2MERE_LR_IN', 'telephone2_mere_liste_rouge', unicode_and_strip, 'téléphone 2 liste rouge mère'),
('TELECOPIEPERE_CH', 'telecopie_pere', unicode_and_strip, 'télécopie du père'),
('TELECOPIE2PERE_CH', 'telecopie2_pere', unicode_and_strip, 'télécopie 2 du père'),
('TELECOPIEMERE_CH', 'telecopie_mere', unicode_and_strip, 'télécopie de la mère'),
@ -223,18 +259,18 @@ class Family(SimpleObject):
('TELPROFMERE_CH', 'telephone_travail_mere', unicode_and_strip, 'téléphone travail mère'),
('TEL2PROFMERE_CH', 'telephone2_travail_mere', unicode_and_strip, 'téléphone 2 travail mère'),
('TELMOBILMERE_CH', 'telephone_mobile_mere', unicode_and_strip, 'téléphone mobile mère'),
('TOTALDU_MO', 'total_du_mo', unicode_and_strip, 'total dû'),
('TOTALREGLE_MO', 'total_regle_mo', unicode_and_strip, 'total réglé'),
('TOTALDU_MO', 'total_du', unicode_and_strip, 'total dû'),
('TOTALREGLE_MO', 'total_regle', unicode_and_strip, 'total réglé'),
('NUMCENTRESS_CH', 'num_centre_securite_sociale', unicode_and_strip, 'n° centre sécurité sociale'),
('NOMCENTRESS_CH', 'nom_centre_securite_sociale', unicode_and_strip, 'nom centre sécurité sociale'),
('NUMASSURANCE_CH', 'num_assurance', unicode_and_strip, 'n° assurance'),
('NOMASSURANCE_CH', 'nom_assurance', unicode_and_strip, 'nom assurance'),
('RIVOLI_EN', 'code_rivoli_en', unicode_and_strip, 'identifiant code rivoli'),
('RIVOLI_EN', 'code_rivoli', unicode_and_strip, 'identifiant code rivoli'),
('NUMCOMPTE_CH', 'numero_compte_comptable', unicode_and_strip, 'n° compte comptable'),
('EMAILPERE_CH', 'email_pere', unicode_and_strip, 'email du père'),
('EMAILMERE_CH', 'email_mere', unicode_and_strip, 'email de la mère'),
('NUMALLOCATAIRE_CH', 'numero_allocataire', unicode_and_strip, 'n° allocataire'),
('COMMENTAIRE_ME', 'commentaire_me', unicode_and_strip, 'commentaires / notes'),
('COMMENTAIRE_ME', 'commentaire', unicode_and_strip, 'commentaires / notes'),
('IDCSPPERE', 'identifiant_csp_pere', unicode_and_strip, 'référence identifiant csp'),
('IDCSPMERE', 'identifiant_csp_mere', unicode_and_strip, 'référence identifiant csp'),
('IDSECTEURS', 'identifiant_secteurs', unicode_and_strip, 'référence identifiant secteurs'),
@ -268,19 +304,19 @@ class Family(SimpleObject):
('NUMRUEPERE_CH', 'numero_rue_pere', unicode_and_strip, 'numéro de rue père'),
('NUMRUEMERE_CH', 'numero_rue_mere', unicode_and_strip, 'numéro de rue mère'),
('IDPORTAIL_FAMILLES', 'identifiant_portail_familles', unicode_and_strip, 'identifiant de portail_familles'),
('ECHEANCEASSURANCE_DA', 'echeance_assurance_da', unicode_and_strip, 'date echéance assurance'),
('RM_MIKADO_MO', 'rm_mikado_mo', unicode_and_strip, 'revenus mensuels mikado'),
('RA_MIKADO_MO', 'ra_mikado_mo', unicode_and_strip, 'revenus annuels mikado'),
('QF_MIKADO_MO', 'qf_mikado_mo', unicode_and_strip, 'quotient familial mikado'),
('RM_DIABOLO_MO', 'rm_diabolo_mo', unicode_and_strip, 'revenus mensuels diabolo'),
('RA_DIABOLO_MO', 'ra_diabolo_mo', unicode_and_strip, 'revenus annuels diabolo'),
('QF_DIABOLO_MO', 'qf_diabolo_mo', unicode_and_strip, 'quotient familial diabolo'),
('RM_OLIGO_MO', 'rm_oligo_mo', unicode_and_strip, 'revenus mensuels oligo'),
('RA_OLIGO_MO', 'ra_oligo_mo', unicode_and_strip, 'revenus annuels oligo'),
('QF_OLIGO_MO', 'qf_oligo_mo', unicode_and_strip, 'quotient familial oligo'),
('APPLICATION_REV_MIKADO_DA', 'application_rev_mikado_da', unicode_and_strip, 'date d\'application des revenus de mikado'),
('APPLICATION_REV_DIABOLO_DA', 'application_rev_diabolo_da', unicode_and_strip, 'date d\'application des revenus de diabolo'),
('APPLICATION_REV_OLIGO_DA', 'application_rev_oligo_da', unicode_and_strip, 'date d\'application des revenus de oligo'),
('ECHEANCEASSURANCE_DA', 'echeance_assurance', unicode_and_strip, 'date echéance assurance'),
('RM_MIKADO_MO', 'rm_mikado', unicode_and_strip, 'revenus mensuels mikado'),
('RA_MIKADO_MO', 'ra_mikado', unicode_and_strip, 'revenus annuels mikado'),
('QF_MIKADO_MO', 'qf_mikado', unicode_and_strip, 'quotient familial mikado'),
('RM_DIABOLO_MO', 'rm_diabolo', unicode_and_strip, 'revenus mensuels diabolo'),
('RA_DIABOLO_MO', 'ra_diabolo', unicode_and_strip, 'revenus annuels diabolo'),
('QF_DIABOLO_MO', 'qf_diabolo', unicode_and_strip, 'quotient familial diabolo'),
('RM_OLIGO_MO', 'rm_oligo', unicode_and_strip, 'revenus mensuels oligo'),
('RA_OLIGO_MO', 'ra_oligo', unicode_and_strip, 'revenus annuels oligo'),
('QF_OLIGO_MO', 'qf_oligo', unicode_and_strip, 'quotient familial oligo'),
('APPLICATION_REV_MIKADO_DA', 'application_rev_mikado', unicode_and_strip, 'date d\'application des revenus de mikado'),
('APPLICATION_REV_DIABOLO_DA', 'application_rev_diabolo', unicode_and_strip, 'date d\'application des revenus de diabolo'),
('APPLICATION_REV_OLIGO_DA', 'application_rev_oligo', unicode_and_strip, 'date d\'application des revenus de oligo'),
)
def __init__(self, *args, **kwargs):
@ -302,16 +338,19 @@ class Family(SimpleObject):
def add_child(self, child):
if hasattr(self, 'id'):
child.id_famille = self.id
child.client = self.client
self.children.append(child)
def save(self):
if hasattr(self, 'id'):
self.client.update_family(self)
else:
self.code_interne = self.client.new_code_interne()
self.id = self.client.add_family(self)
for child in self.children:
child.id_famille = self.id
child.save()
self.client.clear_cache()
class Invoice(SimpleObject):
COLUMNS = (
@ -359,7 +398,7 @@ class DominoWs(object):
self.domain = domain
self.login = login
self.password = password
self.client = Client(url, location=location, timeout=5)
self.client = Client(url, location=location, timeout=60)
self.client.options.cache.setduration(seconds=60)
def clear_cache(self):
@ -373,6 +412,7 @@ class DominoWs(object):
'''Call SOAP method named function_name passing args list as parameters.
Any error is converted into the DominoException class.'''
print 'call', function_name, args
try:
logger.debug('soap call to %s%r', function_name, args)
@ -381,6 +421,8 @@ class DominoWs(object):
self.data = data
except IOError, e:
raise DominoException('Erreur IO', e)
if data is None:
data = ''
if data.startswith('ERREUR'):
raise DominoException(data[9:].encode('utf8'))
return data
@ -488,6 +530,13 @@ class DominoWs(object):
args=(id_famille, (','.join([x[0] for x in columns]))))
return dict([(int(x), x) for x in children])
def get_urgent_contacts(self, id_enfant):
columns = UrgentContact.COLUMNS
urgent_contacts = self('LISTER_PERSONNES_URGENCE',
UrgentContact,
args=((id_enfant, ','.join([x[0] for x in columns]))))
return dict([(int(x), x) for x in urgent_contacts])
@property
@object_cached
@ -502,6 +551,15 @@ class DominoWs(object):
invoice.famille = self.families[invoice.id_famille]
return invoices
def new_code_interne(self):
max_ci = 0
for family in self.families.values():
try:
max_ci = max(max_ci, int(family.code_interne))
except:
pass
return '%05d' % (max_ci+1)
def get_invoices(self, id_famille=0, state='TOUTES'):
'''Get invoices informations.
@ -551,6 +609,13 @@ class DominoWs(object):
return famille
return None
def get_family_by_code_interne(self, code_interne):
'''Return the first whose one email attribute matches the given email'''
for famille in self.families.values():
if getattr(famille, 'code_interne', None) == code_interne:
return famille
return None
def pay_invoice(self, id_invoices, amount, other_information, date=None):
'''Notify Domino of the payment of some invoices.