Projet

Général

Profil

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

root / extra / modules / abelium_domino_synchro.py @ 1469ea26

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

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

    
10
from wcs.users import User
11

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

    
16
DOMINO_ID_PREFIX = 'DOMINO-'
17

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

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

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