166 lines
7.2 KiB
Python
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)))
|