Projet

Général

Profil

Télécharger (7,14 ko) Statistiques
| Branche: | Tag: | Révision:

root / auquotidien / modules / abelium_domino_synchro.py @ 8b02623d

1
import sys
2
from datetime import datetime
3
import collections
4
from decimal import Decimal
5

    
6
from qommon import _
7
from qommon.cron import CronJob
8
from qommon.publisher import get_publisher_class
9
from qommon import get_logger
10

    
11
from wcs.users import User
12

    
13
from abelium_domino_ui import (get_client, is_activated, get_invoice_regie,
14
        abelium_domino_ws)
15
from payments import Invoice, Transaction
16

    
17
DOMINO_ID_PREFIX = 'DOMINO-'
18

    
19
def synchronize_domino(publisher):
20
    regie = get_invoice_regie(publisher)
21
    logger = get_logger()
22
    if not is_activated(publisher) or not regie:
23
        return
24
    client = get_client(publisher)
25
    if client is None:
26
        logger.warning('Unable to create a DominoWS object')
27
        return
28
    client.clear_cache()
29
    users = User.values()
30
    users_by_mail = dict(((user.email, user) for user in users))
31
    users_by_code_interne = {}
32
    for user in users:
33
        if hasattr(user, 'abelium_domino_code_famille'):
34
            users_by_code_interne[user.abelium_domino_code_famille] = user
35
    try:
36
        invoices = client.invoices
37
    except abelium_domino_ws.DominoException, e:
38
        publisher.notify_of_exception(sys.exc_info(), context='[DOMINO]')
39
        logger.error('domino cron: failure to retrieve invoice list from domino '
40
                'for synchronization [error:%s]', e)
41
        return
42
    # import new invoices
43
    logger.info('domino cron: retrieved %i invoices', len(invoices))
44
    for invoice_id, invoice in invoices.iteritems():
45
        user = None
46
        if invoice.family.code_interne in users_by_code_interne:
47
            user = users_by_code_interne[invoice.family.code_interne]
48
        if user is None:
49
            for email in (invoice.family.email_pere, invoice.family.email_mere,
50
                    invoice.family.adresse_internet):
51
                user = users_by_mail.get(email)
52
                if user:
53
                    break
54
            else:
55
                continue
56
        external_id = '%s%s' % (DOMINO_ID_PREFIX, invoice.id)
57
        payment_invoice = Invoice.get_on_index(external_id, 'external_id', ignore_errors=True)
58
        if payment_invoice:
59
            continue
60
        if invoice.reste_du == Decimal(0) or invoice.reste_du < Decimal(0):
61
            continue
62
        payment_invoice = Invoice()
63
        payment_invoice.user_id = user.id
64
        payment_invoice.external_id = external_id
65
        payment_invoice.regie_id = regie.id
66
        payment_invoice.formdef_id = None
67
        payment_invoice.formdata_id = None
68
        payment_invoice.amount = invoice.reste_du
69
        payment_invoice.date = invoice.creation
70
        payment_invoice.domino_synchro_date = datetime.now()
71
        if 'etablissement' in invoice._detail:
72
            etablissement = invoice._detail['etablissement'].encode('utf-8')
73
            payment_invoice.subject = _('%s - Childcare services') % etablissement
74
        else:
75
            payment_invoice.subject = _('Childcare services')
76
        if invoice._detail.get('lignes'):
77
            details = []
78
            details.append('<table class="invoice-details"><thead>')
79
            tpl = '''<tr>
80
    <td>%(designation)s</td>
81
    <td>%(quantite)s</td>
82
    <td>%(prix)s</td>
83
    <td>%(montant)s</td>
84
</tr>'''
85
            captions = {
86
                    'designation': _('Caption'),
87
                    'quantite': _('Quantity'),
88
                    'prix': _('Price'),
89
                    'amount': _('Amount')
90
            }
91
            details.append(tpl % captions)
92
            details.append('</thead>')
93
            details.append('<tbody>')
94
            for ligne in invoice._detail['lignes']:
95
                def encode(x):
96
                    a, b = x
97
                    b = b.encode('utf-8')
98
                    return (a,b)
99
                ligne = map(encode, ligne)
100
                ligne = dict(ligne)
101
                base = collections.defaultdict(lambda:'')
102
                base.update(ligne)
103
                details.append(tpl % base)
104
            details.append('</tbody></table>')
105
            payment_invoice.details = '\n'.join(details)
106
        payment_invoice.store()
107
        logger.info('domino cron: remote invoice %s for family %s added to user %s invoices with id %s',
108
                invoice.id, invoice.family.id, user.id, payment_invoice.id)
109

    
110
    # update invoices
111
    invoices_ids = dict(invoices.iteritems())
112
    for payment_invoice in Invoice.values():
113
        if payment_invoice.external_id is None or not payment_invoice.external_id.startswith(DOMINO_ID_PREFIX):
114
            continue # not a payment related to domino we skip
115
        i = payment_invoice.external_id[len(DOMINO_ID_PREFIX):]
116
        i = int(i)
117
        invoice = invoices_ids.get(i)
118
        if payment_invoice.paid:
119
            if not invoice: 
120
                # invoice has been paid (locally or not) but remote invoice has
121
                # been deleted do, we do nothing.
122
                continue
123
            if getattr(payment_invoice, 'domino_knows_its_paid', None) or getattr(payment_invoice, 'paid_by_domino', None):
124
                # synchronization of payment already done, skip
125
                continue
126
            transactions = Transaction.get_with_indexed_value('invoice_ids', payment_invoice.id)
127
            if not transactions:
128
                logger.warning("domino cron: invoice %s is marked paid but does "
129
                        "not have any linked transaction.", payment_invoice.id)
130
                details = '' # no details about the payment, problem
131
            else:
132
                details = repr(transactions[0].__dict__)
133
            if invoice.montant != payment_invoice.amount:
134
                pass # add warning logs
135
            try:
136
                client.pay_invoice([invoice], invoice.montant, details,
137
                        payment_invoice.paid_date)
138
            except abelium_domino_ws.DominoException, e:
139
                logger.error('domino cron: invoice %s has been paid, but the remote system '
140
                        'is unreachable, notification will be done again '
141
                        'later [error: %s]', invoice.id, e)
142
            else:
143
                # memorize the date of synchronization
144
                payment_invoice.domino_knows_its_paid = datetime.now()
145
                payment_invoice.store()
146
                logger.info('domino cron: domino: invoice %s has been paid; remote system has been '
147
                        'notified', payment_invoice.id)
148
        else: # unpaid
149
            if not invoice:
150
                logger.info('domino cron: remote invoice %s disapearred, so its '
151
                        'still-unpaid local counterpart invoice %s was deleted.',
152
                        i, payment_invoice.id)
153
                payment_invoice.remove_self()
154
            elif invoice.paid():
155
                payment_invoice.paid_by_domino = True
156
                payment_invoice.pay()
157
                logger.info('domino cron: remote invoice %s has beend paid, '
158
                        'local invoice %s of user %s is now marked as paid.',
159
                        invoice.id, payment_invoice.id, payment_invoice.user_id)
160
            else: # not invoice.paid()
161
                pass # still waiting for the payment
162

    
163
get_publisher_class().register_cronjob(CronJob(function=synchronize_domino,
164
    hours=range(0, 24), minutes=range(0, 60, 30)))
(2-2/27)