This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
auquotidien/auquotidien/modules/abelium_domino_synchro.py

166 lines
7.2 KiB
Python

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, 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.iteritems():
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.iteritems())
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, 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)))