From f1133a627aa8a832e8986d8f7aa1fce348588c77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20P=C3=A9ters?= <fpeters@entrouvert.com>
Date: Sat, 3 Oct 2020 20:04:57 +0200
Subject: [PATCH] remove obsolete abelium domino modules (#17244)

---
 auquotidien/auquotidien.py                    |   7 -
 auquotidien/modules/abelium_domino_synchro.py | 165 -----
 auquotidien/modules/abelium_domino_ui.py      | 170 -----
 auquotidien/modules/abelium_domino_vars.py    |  86 ---
 .../modules/abelium_domino_workflow.py        | 148 +---
 auquotidien/modules/abelium_domino_ws.py      | 647 ------------------
 auquotidien/modules/admin.py                  |   7 +-
 auquotidien/modules/connectors.py             |   1 -
 8 files changed, 3 insertions(+), 1228 deletions(-)
 delete mode 100644 auquotidien/modules/abelium_domino_synchro.py
 delete mode 100644 auquotidien/modules/abelium_domino_ui.py
 delete mode 100644 auquotidien/modules/abelium_domino_vars.py
 delete mode 100644 auquotidien/modules/abelium_domino_ws.py

diff --git a/auquotidien/auquotidien.py b/auquotidien/auquotidien.py
index b847803..9a5384f 100644
--- a/auquotidien/auquotidien.py
+++ b/auquotidien/auquotidien.py
@@ -13,9 +13,6 @@ from modules import template
 from modules import root
 from modules import payments
 from modules import connectors
-from modules import abelium_domino_ui
-from modules import abelium_domino_vars
-from modules import abelium_domino_synchro
 
 get_publisher_class().register_translation_domain('auquotidien')
 get_publisher_class().default_configuration_path = 'au-quotidien-wcs-settings.xml'
@@ -32,10 +29,6 @@ rdb.register_directory('settings', admin.SettingsDirectory())
 import wcs.admin.forms
 wcs.admin.forms.FormsDirectory.categories = categories_admin.CategoriesDirectory()
 
-import wcs.admin.settings
-wcs.admin.settings.SettingsDirectory.domino = abelium_domino_ui.AbeliumDominoDirectory()
-wcs.admin.settings.SettingsDirectory._q_exports.append('domino')
-
 import wcs.categories
 wcs.categories.Category.XML_NODES = [('name', 'str'), ('url_name', 'str'),
         ('description', 'str'), ('position', 'int'),
diff --git a/auquotidien/modules/abelium_domino_synchro.py b/auquotidien/modules/abelium_domino_synchro.py
deleted file mode 100644
index e7d7a89..0000000
--- a/auquotidien/modules/abelium_domino_synchro.py
+++ /dev/null
@@ -1,165 +0,0 @@
-import sys
-from datetime import datetime
-import collections
-from decimal import Decimal
-
-from wcs.qommon import _
-from wcs.qommon.cron import CronJob
-from wcs.qommon.publisher import get_publisher_class
-from wcs.qommon import get_logger
-
-from wcs.users import User
-
-from .abelium_domino_ui import (get_client, is_activated, get_invoice_regie,
-        abelium_domino_ws)
-from .payments import Invoice, Transaction
-
-DOMINO_ID_PREFIX = 'DOMINO-'
-
-def synchronize_domino(publisher):
-    regie = get_invoice_regie(publisher)
-    logger = get_logger()
-    if not is_activated(publisher) or not regie:
-        return
-    client = get_client(publisher)
-    if client is None:
-        logger.warning('Unable to create a DominoWS object')
-        return
-    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.invoices
-    except abelium_domino_ws.DominoException as e:
-        publisher.notify_of_exception(sys.exc_info(), context='[DOMINO]')
-        logger.error('domino cron: failure to retrieve invoice list from domino '
-                'for synchronization [error:%s]', e)
-        return
-    # import new invoices
-    logger.info('domino cron: retrieved %i invoices', len(invoices))
-    for invoice_id, invoice in invoices.items():
-        user = None
-        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', ignore_errors=True)
-        if payment_invoice:
-            continue
-        if invoice.reste_du == Decimal(0) or invoice.reste_du < Decimal(0):
-            continue
-        payment_invoice = Invoice()
-        payment_invoice.user_id = user.id
-        payment_invoice.external_id = external_id
-        payment_invoice.regie_id = regie.id
-        payment_invoice.formdef_id = None
-        payment_invoice.formdata_id = None
-        payment_invoice.amount = invoice.reste_du
-        payment_invoice.date = invoice.creation
-        payment_invoice.domino_synchro_date = datetime.now()
-        if 'etablissement' in invoice._detail:
-            etablissement = invoice._detail['etablissement'].encode('utf-8')
-            payment_invoice.subject = _('%s - Childcare services') % etablissement
-        else:
-            payment_invoice.subject = _('Childcare services')
-        if invoice._detail.get('lignes'):
-            details = []
-            details.append('<table class="invoice-details"><thead>')
-            tpl = '''<tr>
-    <td>%(designation)s</td>
-    <td>%(quantite)s</td>
-    <td>%(prix)s</td>
-    <td>%(montant)s</td>
-</tr>'''
-            captions = {
-                    'designation': _('Caption'),
-                    'quantite': _('Quantity'),
-                    'prix': _('Price'),
-                    'amount': _('Amount')
-            }
-            details.append(tpl % captions)
-            details.append('</thead>')
-            details.append('<tbody>')
-            for ligne in invoice._detail['lignes']:
-                def encode(x):
-                    a, b = x
-                    b = b.encode('utf-8')
-                    return (a,b)
-                ligne = map(encode, ligne)
-                ligne = dict(ligne)
-                base = collections.defaultdict(lambda:'')
-                base.update(ligne)
-                details.append(tpl % base)
-            details.append('</tbody></table>')
-            payment_invoice.details = '\n'.join(details)
-        payment_invoice.store()
-        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(invoices.items())
-    for payment_invoice in Invoice.values():
-        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)
-        invoice = invoices_ids.get(i)
-        if payment_invoice.paid:
-            if not invoice: 
-                # 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', None) or getattr(payment_invoice, 'paid_by_domino', None):
-                # synchronization of payment already done, skip
-                continue
-            transactions = list(Transaction.get_with_indexed_value('invoice_ids',
-                                                                   payment_invoice.id))
-            if not transactions:
-                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:
-                details = repr(transactions[0].__dict__)
-            if invoice.montant != payment_invoice.amount:
-                pass # add warning logs
-            try:
-                client.pay_invoice([invoice], invoice.montant, details,
-                        payment_invoice.paid_date)
-            except abelium_domino_ws.DominoException as e:
-                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('domino cron: domino: invoice %s has been paid; remote system has been '
-                        'notified', payment_invoice.id)
-        else: # unpaid
-            if not invoice:
-                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()
-            elif invoice.paid():
-                payment_invoice.paid_by_domino = True
-                payment_invoice.pay()
-                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(0, 24), minutes=range(0, 60, 30)))
diff --git a/auquotidien/modules/abelium_domino_ui.py b/auquotidien/modules/abelium_domino_ui.py
deleted file mode 100644
index c6c6531..0000000
--- a/auquotidien/modules/abelium_domino_ui.py
+++ /dev/null
@@ -1,170 +0,0 @@
-from quixote import get_publisher, redirect, get_request
-from quixote.directory import Directory, AccessControlled
-from quixote.html import TemplateIO, htmltext
-
-from wcs.qommon import _, N_
-from wcs.qommon import get_cfg, get_logger
-from wcs.qommon.form import Form, StringWidget, CheckboxWidget, SingleSelectWidget
-from wcs.qommon.backoffice.menu import html_top
-from quixote.html import htmltext
-
-from .payments import Regie
-
-
-# constants
-ABELIUM_DOMINO = 'abelium_domino'
-ACTIVATED = 'activated'
-WSDL_URL = 'wsdl_url'
-SERVICE_URL = 'service_url'
-DOMAIN = 'domain'
-LOGIN = 'login'
-PASSWORD = 'password'
-INVOICE_REGIE = 'invoice_regie'
-
-try:
-    import abelium_domino_ws
-except ImportError as e:
-    abelium_domino_ws = None
-    import_error = e
-
-def get_abelium_cfg(publisher):
-    if not publisher:
-        publisher = get_publisher()
-    return publisher.cfg.get(ABELIUM_DOMINO, {})
-
-def is_activated(publisher=None):
-    cfg = get_abelium_cfg(publisher)
-    return cfg.get(ACTIVATED, False) and abelium_domino_ws is not None
-
-def get_client(publisher=None):
-    publisher = publisher or get_publisher()
-
-    cfg = get_abelium_cfg(publisher)
-    try:
-        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),
-            logger=get_logger())
-    except IOError:
-        return None
-    return publisher._ws_cache
-
-def get_family(user, publisher=None):
-    family = None
-    if user is None:
-        return None
-    client = get_client(publisher)
-    if not client:
-        return None
-    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)
-    regie_id = cfg.get(INVOICE_REGIE)
-    if not regie_id:
-        return None
-    return Regie.get(regie_id, ignore_errors=True)
-
-class AbeliumDominoDirectory(Directory):
-    _q_exports = [ '' , 'debug' ]
-    label = N_('Domino')
-
-    def debug(self):
-        from abelium_domino_vars import SESSION_CACHE
-        html_top(ABELIUM_DOMINO)
-        r = TemplateIO(html=True)
-        r += htmltext('<form method="post"><button>Lancer le cron</button></form>')
-        if get_request().get_method() == 'POST':
-            try:
-                from abelium_domino_synchro import synchronize_domino
-                synchronize_domino(get_publisher())
-            except Exception as e:
-                r += htmltext('<pre>%s</pre>') % repr(e)
-        r += htmltext('<p>code interne: %s</p>') % getattr(get_request().user, str('abelium_domino_code_famille'), None)
-        r += htmltext('<dl>')
-        context = get_publisher().substitutions.get_context_variables()
-        for var in sorted(context.keys()):
-            value = context[var]
-            if value:
-                r += htmltext('<dt>%s</dt>') % var
-                r += htmltext('<dd>%s</dt>') % value
-        r += htmltext('</dl>')
-        delattr(get_request().session, SESSION_CACHE)
-
-    def _q_index(self):
-        publisher = get_publisher()
-        cfg = get_cfg(ABELIUM_DOMINO, {})
-        form = self.form(cfg)
-
-        title = _('Abelium Domino')
-        html_top(ABELIUM_DOMINO, title = title)
-        r = TemplateIO(html=True)
-        r += htmltext('<h2>%s</h2>') % title
-
-        if form.is_submitted() and not form.has_errors():
-            if form.get_widget('cancel').parse():
-                return redirect('..')
-            if form.get_widget('submit').parse():
-                for name in [f[0] for f in self.form_desc] + [INVOICE_REGIE]:
-                    widget = form.get_widget(name)
-                    if widget:
-                        cfg[name] = widget.parse()
-                publisher.cfg[ABELIUM_DOMINO] = cfg
-                publisher.write_cfg()
-                return redirect('.')
-
-        if abelium_domino_ws:
-            r += form.render()
-        else:
-            message = _('The Abelium Domino module is not '
-                    'activated because of this error when '
-                    'loading it: %r') % import_error
-            r += htmltext('<p class="errornotice">%s</p>') % message
-        r += htmltext('<dl style="display: none">')
-        context = get_publisher().substitutions.get_context_variables()
-        for var in sorted(context.keys()):
-            value = context[var]
-            if value:
-                r += htmltext('<dt>%s</dt>') % var
-                r += htmltext('<dd>%s</dt>') % value
-        r += htmltext('</dl>')
-        return r.getvalue()
-
-    form_desc = (
-            # name, required, title, kind
-            (ACTIVATED, False, _('Activated'), bool),
-            (WSDL_URL, True, _('WSDL URL'), str),
-            (SERVICE_URL, False, _('Service URL'), str),
-            (DOMAIN, True, _('Domain'), str),
-            (LOGIN, True, _('Login'), str),
-            (PASSWORD, True, _('Password'), str),
-    )
-
-
-    def form(self, initial_value={}):
-        form = Form(enctype='multipart/form-data')
-        kinds = { str: StringWidget, bool: CheckboxWidget }
-        for name, required, title, kind in self.form_desc:
-            widget = kinds[kind]
-            form.add(widget, name, required=required, title=title,
-                    value=initial_value.get(name, ''))
-        options = [(regie.id, regie.label) \
-                        for regie in Regie.values()]
-        options.insert(0, (None, _('None')))
-        form.add(SingleSelectWidget, INVOICE_REGIE,
-                title=_('Regie which will receive payments'),
-                value=initial_value.get(INVOICE_REGIE),
-                options=options)
-
-        form.add_submit('submit', _('Submit'))
-        form.add_submit('cancel', _('Cancel'))
-
-        return form
diff --git a/auquotidien/modules/abelium_domino_vars.py b/auquotidien/modules/abelium_domino_vars.py
deleted file mode 100644
index 7a5178c..0000000
--- a/auquotidien/modules/abelium_domino_vars.py
+++ /dev/null
@@ -1,86 +0,0 @@
-from decimal import Decimal
-import logging
-
-from quixote.publish import get_publisher
-
-from wcs.qommon import _
-from wcs.qommon.substitution import Substitutions
-from wcs.publisher import WcsPublisher
-
-from .abelium_domino_ui import (is_activated, abelium_domino_ws, get_client, get_family)
-
-SESSION_CACHE = 'abelium_domino_variable_cache'
-
-class DominoVariables(object):
-    VARIABLE_TEMPLATE = 'domino_var_%s'
-    CHILD_VARIABLE_TEMPLATE = 'domino_var_%s_enfant%s'
-
-    @classmethod
-    def CHILD_COLUMNS(cls):
-        return abelium_domino_ws.Child.COLUMNS
-
-    @classmethod
-    def FAMILY_COLUMNS(cls):
-        return abelium_domino_ws.Family.COLUMNS + abelium_domino_ws.Family.MORE_COLUMNS
-
-    def __init__(self, publisher=None, request=None):
-        self.publisher = publisher
-        self.request = request
-
-    def get_substitution_variables(self):
-        vars = {}
-        if not is_activated() or not self.request or not self.request.user \
-                or not getattr(self.request.user, 'email'):
-            return vars
-
-        # test cache
-        cache = getattr(self.request.session, SESSION_CACHE, None)
-        if cache is not None:
-            return cache
-        # call the web service
-        try:
-            charset = get_publisher().site_charset
-            family = get_family(self.request.user)
-            if family:
-                family.complete()
-                for i, child in enumerate(family.children):
-                    for remote_name, name, converter, desc in self.CHILD_COLUMNS():
-                        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:
-                    amount += invoice.reste_du
-                if amount:
-                    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()
-        return vars
-
-    def get_substitution_variables_list(cls):
-        if not is_activated():
-            return ()
-        vars = []
-        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 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)
-
-Substitutions.register_dynamic_source(DominoVariables)
-WcsPublisher.register_extra_source(DominoVariables)
diff --git a/auquotidien/modules/abelium_domino_workflow.py b/auquotidien/modules/abelium_domino_workflow.py
index 113459f..40737c7 100644
--- a/auquotidien/modules/abelium_domino_workflow.py
+++ b/auquotidien/modules/abelium_domino_workflow.py
@@ -1,148 +1,4 @@
-import re
-import time
+from wcs.workflows import WorkflowStatusItem
 
-from quixote import get_request, get_publisher, get_session
-from quixote.directory import Directory
-
-from wcs.qommon import _, N_
-from wcs.qommon.substitution import Substitutions
-from wcs.qommon.form import Form, ValidatedStringWidget
-from wcs.qommon import get_logger
-
-from wcs.workflows import Workflow, WorkflowStatusJumpItem, register_item_class
-from wcs.forms.common import FormStatusPage
-
-from .abelium_domino_ui import (is_activated, abelium_domino_ws, get_client, get_family)
-from . import abelium_domino_ws
-
-class InternalCodeStringWidget(ValidatedStringWidget):
-    regex = '\d*'
-
-class AbeliumDominoRegisterFamilyWorkflowStatusItem(WorkflowStatusJumpItem):
-    status = None
-    description = N_('Abelium Domino: Register a Family')
+class AbeliumDominoRegisterFamilyWorkflowStatusItem(WorkflowStatusItem):
     key = 'abelium-domino-register-family'
-    category = 'interaction'
-    label = None
-
-    def render_as_line(self):
-        return _('Register a Family into Abelium Domino')
-
-    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 fill_form(self, form, formdata, user):
-        family = self.get_family(formdata)
-        if 'family_id' not in form._names:
-            form.add(InternalCodeStringWidget, 'family_id',
-                     title=_('Family internal code'),
-                     value=family and family.code_interne.encode('utf8'),
-                     hint=_('If a family internal code is present, the '
-                            'family is updated, if not it is created'))
-            form.add_submit('create_update_button%s' % self.id,
-                    _('Create or update the family'))
-
-    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)
-                    setattr(children[i-1], name, value)
-                elif m2:
-                    name = m2.group(1)
-                    setattr(family, name, value)
-        for child1, child2 in zip(family.children, children[:max_i]):
-            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()
-        if form.get_submit() != 'create_update_button%s' % self.id:
-            return
-        try:
-            if form.get_widget('family_id').parse():
-                family = self.update(form, formdata, user, evo)
-                msg = _('Sucessfully updated the family %s')
-                log_msg = _('Sucessfully updated the family %(code)s of %(user)s')
-            else:
-                family = self.create(form, formdata, user, evo)
-                msg = _('Sucessfully created the family %s')
-                log_msg = _('Sucessfully created the family %(code)s of %(user)s')
-            code_interne = family.code_interne.encode('utf8')
-            msg = msg % code_interne
-            logger.info(log_msg, {'code': code_interne, 'user': formdata.get_user()})
-            form_user = formdata.get_user()
-            form_user.abelium_domino_code_famille = code_interne
-            form_user.store()
-        except Exception as e:
-            if form.get_widget('family_id').parse():
-                msg = _('Unable to update family: %s') % str(e)
-            else:
-                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_target_status()
-            if wf_status:
-                evo.status = 'wf-%s' % wf_status[0].id
-        return False
-
-    def is_available(self, workflow=None):
-        return get_publisher().has_site_option('domino')
-    is_available = classmethod(is_available)
-
-register_item_class(AbeliumDominoRegisterFamilyWorkflowStatusItem)
diff --git a/auquotidien/modules/abelium_domino_ws.py b/auquotidien/modules/abelium_domino_ws.py
deleted file mode 100644
index fc68b61..0000000
--- a/auquotidien/modules/abelium_domino_ws.py
+++ /dev/null
@@ -1,647 +0,0 @@
-# -*- coding: utf-8 -*-
-from decimal import Decimal
-import time
-import datetime
-from xml.etree import ElementTree as etree
-import logging
-
-try:
-    from suds.client import Client
-    from suds.bindings.binding import Binding
-    # Webdev is bugged and using an HTML generator to produce XML content, 
-    Binding.replyfilter = lambda self, x: x.replace('&nbsp;', '&#160;')
-except ImportError:
-    Client = None
-    Binding = None
-
-logger = logging.getLogger(__name__)
-
-# cleaning and parsing functions
-
-LINE_SEPARATOR = '\n'
-COLUMN_SEPARATOR = '\t'
-
-def unicode_and_strip(x):
-    return unicode(x).strip()
-
-def strip_and_int(x):
-    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:
-        return datetime.datetime.strptime(date_string, "%Y%m%d")
-    else:
-        None
-
-class DominoException(Exception):
-    pass
-
-def object_cached(function):
-    '''Decorate an object method so that its results is cached on the object
-       instance after the first call.
-    '''
-    def decorated_function(self, *args, **kwargs):
-        cache_name = '__%s_cache' % function.__name__
-        if not hasattr(self, cache_name):
-            setattr(self, cache_name, (time.time(), {}))
-        t, d = getattr(self, cache_name)
-        if time.time() - t > 80:
-            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)
-        return d[k]
-    return decorated_function
-
-# Data model
-class SimpleObject(object):
-    '''Base class for object returned by the web service'''
-
-    '''Describe basic columns'''
-    COLUMNS = ()
-    '''Describe extended object columns'''
-    MORE_COLUMNS = ()
-
-    def __init__(self, **kwargs):
-        self.__dict__.update(kwargs)
-
-    def __repr__(self):
-        c = {}
-        for remote_name, name, converter, desc in self.COLUMNS:
-            if hasattr(self, name):
-                c[name] = getattr(self, name)
-        return str(c)
-
-    def serialize(self):
-        l = []
-        for remote_name, local_name, converter, desc in self.COLUMNS + self.MORE_COLUMNS:
-            if local_name == 'id':
-                continue
-            v = getattr(self, local_name, None)
-            if v is None:
-                continue
-            if isinstance(v, (datetime.date, datetime.datetime)):
-                v = v.strftime('%Y%m%d')
-            if remote_name.endswith('_DA') and '-' in v:
-                v = v.replace('-', '')
-            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):
-                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', '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):
-        if hasattr(self, 'id'):
-            self.client.update_child(self)
-        else:
-            self.id = self.client.add_child(self)
-        self.client.clear_cache()
-
-class Family(SimpleObject):
-    COLUMNS = (
-            ('IDFAMILLES', 'id', strip_and_int, 'identifiant de famille'),
-            ('NOMFAMILLE_CH', 'famille_nom', unicode_and_strip, 'nom de famille'),
-            ('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 = (
-            ('IDFAMILLES', 'id', strip_and_int, 'identifiant de famille'),
-            ('CODEINTERNE_CH', 'code_interne', unicode_and_strip, 'code interne'),
-            ('CIVILITE_CH', 'civilite', unicode_and_strip, 'civilité'),
-            ('NOMFAMILLE_CH', 'famille_nom', unicode_and_strip, 'nom de famille'),
-            ('RUE_CH', 'rue', unicode_and_strip, 'rue'),
-            ('RUE2_CH', 'rue2', unicode_and_strip, 'rue 2'),
-            ('RUE3_CH', 'rue3', unicode_and_strip, 'rue 3'),
-            ('CODEPOSTAL_CH', 'code_postal', unicode_and_strip, 'code postal'),
-            ('VILLE_CH', 'ville', unicode_and_strip, 'ville'),
-            ('TELEPHONE_CH', 'telephone', unicode_and_strip, 'téléphone'),
-            ('TELEPHONE2_CH', 'telephone2', unicode_and_strip, 'téléphone 2'),
-            ('TELECOPIE_CH', 'telecopie', unicode_and_strip, 'télécopie'),
-            ('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', 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', 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'),
-            ('RUE2PERE_CH', 'rue2_pere', unicode_and_strip, 'rue 2 père'),
-            ('RUE3PERE_CH', 'rue3_pere', unicode_and_strip, 'rue 3 père'),
-            ('CODEPOSTALPERE_CH', 'code_postal_pere', unicode_and_strip, 'code postal père'),
-            ('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', 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', 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', 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', 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', 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'),
-            ('TELECOPIE2MERE_CH', 'telecopie2_mere', unicode_and_strip, 'télécopie 2 de la mère'),
-            ('PROFPERE_CH', 'profession_pere', unicode_and_strip, 'profession du père'),
-            ('PROFMERE_CH', 'profession_mere', unicode_and_strip, 'profession de la mère'),
-            ('LIEUTRAVPERE_CH', 'lieu_travail_pere', unicode_and_strip, 'lieu de travail du père'),
-            ('LIEUTRAVMERE_CH', 'lieu_travail_mere', unicode_and_strip, 'lieu de travail de la mère'),
-            ('RUETRAVPERE_CH', 'rue_travail_pere', unicode_and_strip, 'rue travail père'),
-            ('RUE2TRAVPERE_CH', 'rue2_travail_pere', unicode_and_strip, 'rue 2 travail père'),
-            ('RUE3TRAVPERE_CH', 'rue3_travail_pere', unicode_and_strip, 'rue 3 travail père'),
-            ('CPTRAVPERE_CH', 'code_postal_travail_pere', unicode_and_strip, 'code postal travail père'),
-            ('VILLETRAVPERE_CH', 'ville_travail_pere', unicode_and_strip, 'ville travail père'),
-            ('RUETRAVMERE_CH', 'rue_travail_mere', unicode_and_strip, 'rue travail mère'),
-            ('RUE2TRAVMERE_CH', 'rue2_travail_mere', unicode_and_strip, 'rue 2 travail mère'),
-            ('RUE3TRAVMERE_CH', 'rue3_travail_mere', unicode_and_strip, 'rue 3 travail mère'),
-            ('CPTRAVMERE_CH', 'code_postal_travail_mere', unicode_and_strip, 'code postal travail mère'),
-            ('VILLETRAVMERE_CH', 'ville_travail_mere', unicode_and_strip, 'ville travail mère'),
-            ('TELPROFPERE_CH', 'telephone_travail_pere', unicode_and_strip, 'téléphone professionnel père'),
-            ('TEL2PROFPERE_CH', 'telephone2_travail_pere', unicode_and_strip, 'téléphone 2 professionnel père'),
-            ('TELMOBILPERE_CH', 'telephone_mobile_pere', unicode_and_strip, 'téléphone mobile'),
-            ('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', 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', 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', 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'),
-            ('IDZONES', 'identifiant_zones', unicode_and_strip, 'référence identifiant zones'),
-            ('IDRUES', 'identifiant_rues', unicode_and_strip, 'référence identifiant rues'),
-            ('IDVILLES', 'identifiant_villes', unicode_and_strip, 'référence identifiant villes'),
-            ('IDREGIMES', 'identifiant_regimes', unicode_and_strip, 'référence identifiant regimes'),
-            ('IDSITUATIONFAMILLE', 'identifiant_situation_famille', unicode_and_strip, 'référence identifiant situationfamille'),
-            ('NUMSECUPERE_CH', 'num_securite_sociale_pere', unicode_and_strip, 'n° secu père'),
-            ('NUMSECUMERE_CH', 'num_securite_sociale_mere', unicode_and_strip, 'n° secu mère'),
-            ('NATIONPERE_CH', 'nation_pere', unicode_and_strip, 'nationalité père'),
-            ('NATIONMERE_CH', 'nation_mere', unicode_and_strip, 'nationalité mère'),
-            ('NOMJEUNEFILLE_CH', 'nom_jeune_fille', unicode_and_strip, 'nom jeune fille'),
-            ('IDCAFS', 'idcafs', unicode_and_strip, 'référence identifiant cafs'),
-            ('CHAMPLIBRE1_CH', 'champ_libre1', unicode_and_strip, 'valeur champ libre 1'),
-            ('CHAMPLIBRE2_CH', 'champ_libre2', unicode_and_strip, 'valeur champ libre 2'),
-            ('CHAMPCALCULE1_CH', 'champ_calcule1', unicode_and_strip, 'valeur champ calculé 1'),
-            ('CHAMPCALCULE2_CH', 'champ_calcule2', unicode_and_strip, 'valeur champ calculé 2'),
-            ('IDTABLELIBRE1', 'id_table_libre1', unicode_and_strip, 'idtablelibre1'),
-            ('IDTABLELIBRE3', 'id_table_libre3', unicode_and_strip, 'idtablelibre3'),
-            ('IDTABLELIBRE2', 'id_table_libre2', unicode_and_strip, 'idtablelibre2'),
-            ('IDTABLELIBRE4', 'id_table_libre4', unicode_and_strip, 'idtablelibre4'),
-            ('NOMURSSAF_CH', 'nom_urssaf', unicode_and_strip, 'nom urssaf'),
-            ('NUMURSSAF_CH', 'num_urssaf', unicode_and_strip, 'n° urssaf'),
-            ('IDPROFPERE', 'identifiant_profession_pere', unicode_and_strip, 'référence identifiant profession'),
-            ('IDPROFMERE', 'identifiant_profession_mere', unicode_and_strip, 'référence identifiant profession'),
-            ('ALLOCATAIRE_CH', 'allocataire', unicode_and_strip, 'allocataire père ou mère (p,m)'),
-#            ('PHOTOPERE_CH', 'photo_pere', unicode_and_strip, 'photographie père'),
-#            ('PHOTOMERE_CH', 'photo_mere', unicode_and_strip, 'photographie mère'),
-            ('NUMRUE_CH', 'numero_rue', unicode_and_strip, 'numéro de rue'),
-            ('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', 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):
-        self.children = []
-        super(Family, self).__init__(*args, **kwargs)
-
-    def complete(self):
-        k = [a for a,b,c,d in self.MORE_COLUMNS]
-        list(self.client('LISTER_FAMILLES', args=(','.join(k), self.id),
-                columns=self.MORE_COLUMNS, instances=(self,)))
-        l = self.client.get_children(self.id).values()
-        self.children = sorted(l, key=lambda c: c.id)
-        return self
-
-    @property
-    def invoices(self):
-        return [invoice for id, invoice in self.client.invoices.items() if invoice.id_famille == self.id]
-
-    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 = (
-        ('', 'id_famille', int, ''),
-        ('', 'id', int, ''),
-        ('', 'numero', str, ''),
-        ('', 'debut_periode', parse_date, ''),
-        ('', 'fin_periode', parse_date, ''),
-        ('', 'creation', parse_date, ''),
-        ('', 'echeance', parse_date, ''),
-        ('', 'montant', Decimal, ''),
-        ('', 'reste_du', Decimal, ''),
-    )
-    _detail = {}
-
-    def detail(self):
-        if not self._detail:
-            self.client.factures_detail([self])
-        return self._detail
-
-    @property
-    def family(self):
-        return self.client.families[self.id_famille]
-
-    def paid(self):
-        return self.reste_du == Decimal(0)
-
-class DominoWs(object):
-    '''Interface to the WebService exposed by Abelium Domino.
-
-       It allows to retrieve family and invoices.
-
-       Beware that it does a lot of caching to limit call to the webservice, so
-       if you need fresh data, call clear_cache()
-
-       All family are in the families dictionnary and all invoices in the
-       invoices dictionnary.
-    '''
-
-    def __init__(self, url, domain, login, password, location=None,
-            logger=logger):
-        if not Client:
-            raise ValueError('You need python suds')
-        self.logger = logger
-        self.logger.debug('creating DominoWs(%r, %r, %r, %r, location=%r)',
-                url, domain, login, password, location)
-        self.url = url
-        self.domain = domain
-        self.login = login
-        self.password = password
-        self.client = Client(url, location=location, timeout=60)
-        self.client.options.cache.setduration(seconds=60)
-
-    def clear_cache(self):
-        '''Remove cached attributes from the instance.'''
-
-        for key, value in self.__dict__.items():
-            if key.startswith('__') and key.endswith('_cache'):
-                del self.__dict__[key]
-
-    def call(self, function_name, *args):
-        '''Call SOAP method named function_name passing args list as parameters.
-
-           Any error is converted into the DominoException class.'''
-
-        try:
-            self.logger.debug(('soap call to %s(%s)' % (function_name, args)).encode('utf-8'))
-            data = getattr(self.client.service, function_name)(self.domain, self.login, self.password, *args)
-            self.logger.debug((u'result: %s' % data).encode('utf-8'))
-            self.data = data
-        except IOError as e:
-            raise DominoException('Erreur IO', e)
-        if data is None:
-           data = ''
-        if data.startswith('ERREUR'):
-            raise DominoException(data[9:].encode('utf8'))
-        return data
-
-    def parse_tabular_data(self, data):
-        '''Row are separated by carriage-return, ASCII #13, characters and columns by tabs.
-           Empty lines (ignoring spaces) are ignored.
-        '''
-
-        rows = data.split(LINE_SEPARATOR)
-        rows = [[cell.strip() for cell in row.split(COLUMN_SEPARATOR)] for row in rows if row.strip() != '']
-        return rows
-
-    def __call__(self, function_name, cls=None, args=[], instances=None, columns=None):
-        '''Call SOAP method named function_name, splitlines, map tab separated
-        values to _map keys in a dictionnary, and use this dictionnary to
-        initialize an object of class cls.
-
-        - If instances is present, the given instances are updated with the
-          returned content, in order, row by row.
-        - If cls is not None and instances is None, a new instance of the class
-          cls is instancied for every row and initialized with the content of
-          the row.
-        - If cls and instances are None, the raw data returned by the SOAP call
-          is returned.
-        '''
-
-        data = self.call(function_name, *args)
-        if cls or instances:
-            rows = self.parse_tabular_data(data)
-            kwargs = {}
-            if instances:
-                rows = zip(rows, instances)
-            for row in rows:
-                if instances:
-                    row, instance = row
-                if not row[0]:
-                    continue
-                for a, b in zip(columns or cls.COLUMNS, row):
-                    x, name, converter, desc = a
-                    kwargs[name] = converter(b.strip())
-                if instances:
-                    instance.__dict__.update(kwargs)
-                    yield instance
-                else:
-                    yield cls(client=self, **kwargs)
-        else:
-            yield data
-
-    def add_family(self, family):
-        result = self.call('AJOUTER_FAMILLE', family.serialize())
-        return int(result.strip())
-
-    def update_family(self, family):
-        if not hasattr(family, 'id'):
-            raise DominoException('Family lacks an "id" attribute, it usually means that it is new.')
-        result = self.call('MODIFIER_FAMILLE', unicode(family.id), family.serialize())
-        return result.strip() == 'OK'
-
-    def add_child(self, child):
-        result = self.call('AJOUTER_ENFANT', child.serialize())
-        return int(result.strip())
-
-    def update_child(self, child):
-        if not hasattr(child, 'id'):
-            raise DominoException('Family lacks an "id" attribute, it usually means that it is new.')
-        result = self.call('MODIFIER_ENFANT', unicode(child.id), child.serialize())
-        return result.strip() == 'OK'
-
-    @property
-    @object_cached
-    def families(self):
-        '''Dictionary of all families indexed by their id.
-
-           After the first use, the value is cached. Use clear_cache() to reset
-           it.
-        '''
-
-        return self.get_families()
-
-    def get_families(self, id_famille=0, full=False):
-        '''Get families informations.
-           There is no caching.
-
-           id_famille - if not 0, the family with this id is retrieved. If 0
-           all families are retrieved. Default to 0.
-           full - If True return all the columns of the family table. Default
-           to False.
-        '''
-        columns = Family.MORE_COLUMNS if full else Family.COLUMNS
-        families = self('LISTER_FAMILLES',
-                Family,
-                args=(','.join([x[0] for x in columns]), id_famille))
-        return dict([(int(x), x) for x in families])
-
-    def get_children(self, id_famille=0):
-        columns = Child.COLUMNS
-        if id_famille == 0:
-            children = self('LISTER_ENFANTS',
-                Child,
-                args=((','.join([x[0] for x in columns])),))
-        else:
-            children = self('LISTER_ENFANTS_FAMILLE',
-                Child,
-                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
-    def invoices(self):
-        '''Dictionnary of all invoices indexed by their id.
-
-           After the first use, the value is cached. Use clear_cache() to reset
-           it.
-        '''
-        invoices = self.get_invoices()
-        for invoice in invoices.values():
-            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.
-
-           id_famille - If value is not 0, only invoice for the family with
-           this id are retrieved. If value is 0, invoices for all families are
-           retrieved. Default to 0.
-           etat - state of the invoices to return, possible values are
-           'SOLDEES', 'NON_SOLDEES', 'TOUTES'.
-        '''
-        invoices = self('LISTER_FACTURES_FAMILLE', Invoice,
-            args=(id_famille, state))
-        invoices = list(invoices)
-        for invoice in invoices:
-            invoice.famille = self.families[invoice.id_famille]
-        return dict(((int(x), x) for x in invoices))
-
-    FACTURE_DETAIL_HEADERS = ['designation', 'quantite', 'prix', 'montant']
-    def factures_detail(self, invoices):
-        '''Retrieve details of some invoice'''
-        data = self.call('DETAILLER_FACTURES', (''.join(("%s;" % int(x) for x in invoices)),))
-        try:
-            tree = etree.fromstring(data.encode('utf8'))
-            for invoice, facture_node in zip(invoices, tree.findall('facture')):
-                rows = []
-                for ligne in facture_node.findall('detail_facture/ligne'):
-                    row = []
-                    rows.append(row)
-                    for header in self.FACTURE_DETAIL_HEADERS:
-                        if header in ligne.attrib:
-                            row.append((header, ligne.attrib[header]))
-                etablissement = facture_node.find('detail_etablissements/etablissement')
-                if etablissement is not None:
-                    nom = etablissement.get('nom').strip()
-                else:
-                    nom = ''
-                d = { 'etablissement': nom, 'lignes': rows }
-                invoice._detail = d
-        except Exception as e:
-            raise DominoException('Exception when retrieving invoice details', e)
-
-    def get_family_by_mail(self, email):
-        '''Return the first whose one email attribute matches the given email'''
-        for famille in self.families.values():
-            if email in (famille.email_pere, famille.email_mere,
-                    famille.adresse_internet):
-                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.
-
-           id_invoices - integer if of the invoice or Invoice instances
-           amount - amount as a Decimal object
-           other_information - free content to attach to the payment, like a
-           bank transaction number for correlation.
-           date - date of the payment, must be a datetime object. If None,
-           now() is used. Default to None.
-        '''
-
-        if not date:
-            date = datetime.datetime.now()
-        due = sum([self.invoices[int(id_invoice)].reste_du
-                 for id_invoice in id_invoices])
-        if Decimal(amount) == Decimal(due):
-            return self('SOLDER_FACTURE', None, args=(str(amount), 
-                    ''.join([ '%s;' % int(x) for x in id_invoices]),
-                    date.strftime('%Y-%m-%d'), other_information))
-        else:
-            raise DominoException('Amount due and paid do not match', { 'due': due, 'paid': amount})
diff --git a/auquotidien/modules/admin.py b/auquotidien/modules/admin.py
index 7785097..050f18d 100644
--- a/auquotidien/modules/admin.py
+++ b/auquotidien/modules/admin.py
@@ -18,15 +18,12 @@ from wcs.categories import Category
 from wcs.qommon.backoffice.menu import html_top
 
 import re
-from .abelium_domino_ui import AbeliumDominoDirectory
 
 
 class PanelDirectory(Directory):
-    _q_exports = ['', 'update', 'permissions', 'domino']
+    _q_exports = ['', 'update', 'permissions']
     label = N_('Control Panel')
 
-    domino = AbeliumDominoDirectory()
-
     def _verify_mask(self, form):
         if form.is_submitted():
             if not re.match("[0-9Xx]*$", form.get('mobile_mask') or ''):
@@ -76,8 +73,6 @@ class SettingsDirectory(wcs.admin.settings.SettingsDirectory):
         r += htmltext('<h2>%s</h2>') % _('Extra Options')
         r += htmltext('<ul>')
         r += htmltext('<li><a href="aq/permissions">%s</a></li>') % _('Permissions')
-        if get_publisher().has_site_option('domino'):
-            r += htmltext('<li><a href="aq/domino">%s</a></li>') % _('Abelium Domino Integration')
         r += htmltext('</ul>')
         r += htmltext('</div>')
         r += htmltext('</div>')
diff --git a/auquotidien/modules/connectors.py b/auquotidien/modules/connectors.py
index c1ebec6..3a418a7 100644
--- a/auquotidien/modules/connectors.py
+++ b/auquotidien/modules/connectors.py
@@ -1,2 +1 @@
-from . import abelium_domino_workflow
 from . import clicrdv
-- 
2.28.0

