Project

General

Profile

Download (12.2 KB) Statistics
| Branch: | Tag: | Revision:

calebasse / calebasse / facturation / invoice_header.py @ 2f2a7de9

1
# -*- coding: utf-8 -*-
2
import os
3
import os.path
4
import tempfile
5
import datetime
6
import textwrap
7
from decimal import Decimal
8
from collections import defaultdict
9

    
10
from xhtml2pdf.pisa import CreatePDF
11
from django.template import loader, Context
12

    
13
from invoice_template import InvoiceTemplate
14
from ..pdftk import PdfTk
15
from batches import build_batches
16
from calebasse.utils import get_nir_control_key
17

    
18
class Counter(object):
19
    def __init__(self, initial_value=0):
20
        self.counter = initial_value
21

    
22
    def increment(self):
23
        self.counter += 1
24
        return (self.counter-1)
25

    
26
    def __str__(self):
27
        return str(self.counter)
28

    
29

    
30
def render_to_pdf_file(templates, ctx, prefix='tmp', delete=False):
31
    temp = tempfile.NamedTemporaryFile(prefix=prefix, suffix='.pdf',
32
            delete=False)
33
    try:
34
        t = loader.select_template(templates)
35
        html = t.render(Context(ctx))
36
        CreatePDF(html, temp)
37
        temp.flush()
38
        return temp.name
39
    except:
40
        if delete:
41
            try:
42
                os.unlink(temp.name)
43
            except:
44
                pass
45
        raise
46

    
47

    
48
def header_file(service, invoicing, health_center, batches,
49
        header_service_template='facturation/bordereau-%s.html',
50
        header_template='facturation/bordereau.html',
51
        delete=False,
52
        counter=None):
53
    synthesis = {
54
            'total': sum(batch.total for batch in batches),
55
            'number_of_acts': sum(batch.number_of_acts for batch in batches),
56
            'number_of_invoices': sum(batch.number_of_invoices for batch in batches),
57
    }
58
    ctx = {
59
            'now': datetime.datetime.now(),
60
            'health_center': health_center,
61
            'service': service,
62
            'batches': batches,
63
            'synthesis': synthesis,
64
            'counter': counter,
65
    }
66
    prefix = '%s-invoicing-%s-healthcenter-%s-' % (
67
            service.slug, invoicing.id, health_center.id)
68
    return render_to_pdf_file(
69
            (header_service_template % service.slug,
70
            header_template), ctx, prefix=prefix, delete=delete)
71

    
72

    
73
def invoice_files(service, invoicing, batch, invoice, counter=None):
74
    template_path = os.path.join(
75
            os.path.dirname(__file__),
76
            'static',
77
            'facturation',
78
            'invoice.pdf')
79
    tpl = InvoiceTemplate(
80
            template_path=template_path,
81
            prefix='%s-invoicing-%s-invoice-%s-'
82
                % ( service.slug, invoicing.id, invoice.id),
83
            suffix='-%s.pdf' % datetime.datetime.now())
84
    health_center = invoice.health_center
85
    code_organisme = u'%s - %s %s' % (
86
      health_center.large_regime.code,
87
      health_center.dest_organism,
88
      health_center.name)
89
    address = textwrap.fill(invoice.policy_holder_address, 40)
90
    if invoice.acts.all()[0].get_hc_tag()[0] == 'D':
91
        subtitle = 'DIAGNOSTIC'
92
    else:
93
        subtitle = 'TRAITEMENT'
94
    ctx = {
95
            'NUM_FINESS': '420788606',
96
            'NUM_LOT': unicode(batch.number),
97
            'NUM_FACTURE': unicode(invoice.number),
98
            'NUM_ENTREE': unicode(invoice.patient_id),
99
            'IDENTIFICATION_ETABLISSEMENT': '''%s SAINT ETIENNE
100
66/68, RUE MARENGO
101
42000 SAINT ETIENNE''' % service.name,
102
            'DATE_ELABORATION': datetime.datetime.now().strftime('%d/%m/%Y'),
103
            'NOM_BENEFICIAIRE': u' '.join((invoice.patient_first_name,
104
                invoice.patient_last_name.upper())),
105
            'NIR_BENEFICIAIRE': invoice.patient_social_security_id_full,
106
            'DATE_NAISSANCE_RANG': u' '.join(
107
                (unicode(invoice.patient_birthdate),
108
                    unicode(invoice.patient_twinning_rank))),
109
            'CODE_ORGANISME':  code_organisme,
110
            'ABSENCE_SIGNATURE': True,
111
            'ADRESSE_ASSURE': address,
112
            'SUBTITLE': subtitle,
113
            'PART_OBLIGATOIRE': True,
114
            'PART_COMPLEMENTAIRE': True,
115
    }
116
    if counter is not None:
117
        ctx['COUNTER'] = counter.increment()
118
    if invoice.patient_entry_date is not None:
119
        ctx['DATE_ENTREE'] = invoice.patient_entry_date.strftime('%d/%m/%Y')
120
    if invoice.patient_exit_date is not None:
121
        ctx['DATE_SORTIE'] = invoice.patient_exit_date.strftime('%d/%m/%Y')
122
    if invoice.policy_holder_id != invoice.patient_id:
123
        ctx.update({
124
                'NOM_ASSURE': u' '.join((
125
                    invoice.policy_holder_first_name,
126
                    invoice.policy_holder_last_name.upper())),
127
                'NIR_ASSURE': invoice.policy_holder_social_security_id_full,
128
            })
129
    total1 = Decimal(0)
130
    total2 = Decimal(0)
131
    acts = invoice.acts.order_by('date')
132
    if len(acts) > 24:
133
        raise RuntimeError('Too much acts in invoice %s' % invoice.id)
134
    tableau1 = []
135
    tableau2 = []
136
    for act in acts[:12]:
137
        hc_tag = act.get_hc_tag()
138
        prestation = u'SNS' if hc_tag.startswith('T') else u'SD'
139
        d = act.date.strftime('%d/%m/%Y')
140
        total1 += invoice.decimal_ppa
141
        tableau1.append([u'19', u'320', prestation, d, d, invoice.decimal_ppa,
142
            1, invoice.decimal_ppa, act.get_hc_tag()])
143
    for act in acts[12:24]:
144
        hc_tag = act.get_hc_tag()
145
        prestation = u'SNS' if hc_tag.startswith('T') else u'SD'
146
        d = act.date.strftime('%d/%m/%Y')
147
        total2 += invoice.decimal_ppa
148
        tableau2.append([u'19', u'320', prestation, d, d, invoice.decimal_ppa,
149
            1, invoice.decimal_ppa, act.get_hc_tag()])
150
    ctx.update({
151
            'TABLEAU1': tableau1,
152
            'TABLEAU2': tableau2,
153
        })
154
    ctx['SOUS_TOTAL1'] = total1
155
    if total2 != Decimal(0):
156
        ctx['SOUS_TOTAL2'] = total2
157
    assert invoice.decimal_amount == (total1+total2), "decimal_amount(%s) != " \
158
        "total1+total2(%s), ppa: %s len(acts): %s" % (invoice.decimal_amount,
159
    total1+total2, invoice.ppa, len(acts))
160
    ctx['TOTAL'] = total1+total2
161
    return [tpl.generate(ctx)]
162

    
163
def render_not_cmpp_header(invoicing, counter):
164
    header_template='facturation/bordereau_not_cmpp_header.html'
165
    management_codes = dict()
166
    total_acts = 0
167
    for invoice in invoicing.invoice_set.all():
168
        total_acts += invoice.acts.count()
169
        if invoice.policy_holder_management_code:
170
            management_codes.setdefault(invoice.policy_holder_management_code, []).append(invoice)
171
    list_management_codes = list()
172
    for mc, invoices in management_codes.iteritems():
173
        dic = dict()
174
        dic['code'] = mc
175
        dic['title'] = invoices[0].policy_holder_management_code_name
176
        dic['nb_files'] = len(invoices)
177
        nb_acts = 0
178
        for invoice in invoices:
179
            nb_acts += invoice.acts.count()
180
        dic['nb_acts'] = nb_acts
181
        list_management_codes.append(dic)
182
    list_management_codes.sort(key=lambda dic: dic['code'])
183
    ctx = {
184
            'now': datetime.datetime.now(),
185
            'service': invoicing.service,
186
            'start_date': invoicing.start_date,
187
            'end_date': invoicing.end_date,
188
            'counter': counter,
189
            'list_management_codes': list_management_codes,
190
            'total_files': invoicing.invoice_set.count(),
191
            'total_acts': total_acts
192
    }
193
    prefix = '%s-invoicing-header-%s' % (
194
            invoicing.service.slug, invoicing.id)
195
    return render_to_pdf_file(
196
            (header_template, ), ctx, prefix=prefix, delete=True)
197

    
198
def render_not_cmpp_content(invoicing, counter):
199
    header_template='facturation/bordereau_not_cmpp_content.html'
200
    total_acts = 0
201
    list_patients = list()
202
    for invoice in invoicing.invoice_set.all():
203
        total_acts += invoice.acts.count()
204
        policy_holder = ''
205
        if invoice.policy_holder_last_name and invoice.policy_holder_first_name:
206
            policy_holder = invoice.policy_holder_last_name.upper() + ' ' + invoice.policy_holder_first_name
207
        nir = None
208
        if invoice.policy_holder_social_security_id:
209
            nir = invoice.policy_holder_social_security_id + ' ' + str(get_nir_control_key(invoice.policy_holder_social_security_id))
210
        health_center = ''
211
        tp = ''
212
        cai = ''
213
        if invoice.policy_holder_healthcenter:
214
            health_center = invoice.policy_holder_healthcenter.name
215
            if invoice.policy_holder_healthcenter.large_regime:
216
                tp = invoice.policy_holder_healthcenter.large_regime.code
217
            cai = invoice.policy_holder_healthcenter.health_fund
218
        name = ''
219
        if invoice.patient_last_name and invoice.patient_first_name:
220
            name = invoice.patient_last_name.upper() + ' ' + invoice.patient_first_name
221
        list_patients.append({\
222
              'code' : invoice.policy_holder_management_code,
223
              'policy_holder': policy_holder,
224
              'nir': nir,
225
              'health_center': health_center,
226
              'tp': tp,
227
              'cai': cai,
228
              'cen': invoice.policy_holder_other_health_center,
229
              'number': invoice.patient_id,
230
              'name': name,
231
              'birth_date': invoice.patient_birthdate,
232
              'inscription_date': invoice.patient_entry_date,
233
              'sortie_date': invoice.patient_exit_date,
234
              'nb_actes': invoice.acts.count()})
235
    list_patients.sort(key=lambda dic: dic['code'])
236
    ctx = {
237
            'now': datetime.datetime.now(),
238
            'service': invoicing.service,
239
            'start_date': invoicing.start_date,
240
            'end_date': invoicing.end_date,
241
            'counter': counter,
242
            'total_files': invoicing.invoice_set.count(),
243
            'total_acts': total_acts,
244
            'patients': list_patients
245
    }
246
    prefix = '%s-invoicing-content-%s' % (
247
            invoicing.service.slug, invoicing.id)
248
    return render_to_pdf_file(
249
            (header_template, ), ctx, prefix=prefix, delete=True)
250

    
251

    
252
def render_invoicing(invoicing, delete=False, headers=True, invoices=True):
253
    service = invoicing.service
254
    now = datetime.datetime.now()
255
    output_file = None
256
    all_files = []
257
    try:
258
        if service.name == 'CMPP':
259
            batches_by_health_center = build_batches(invoicing)
260
            centers = sorted(batches_by_health_center.keys())
261
            counter = Counter(1)
262
            for center in centers:
263
                if headers is not True and headers is not False and headers != center:
264
                    continue
265
                for batch in batches_by_health_center[center]:
266
                    files = batches_files(service, invoicing, center,
267
                        [batch], delete=delete,
268
                        headers=headers, invoices=invoices, counter=counter)
269
                    all_files.extend(files)
270
        else:
271
            counter = Counter(1)
272
            header = render_not_cmpp_header(invoicing, counter)
273
            all_files.append(header)
274
            content = render_not_cmpp_content(invoicing, counter)
275
            all_files.append(content)
276
        output_file = tempfile.NamedTemporaryFile(prefix='%s-invoicing-%s-' %
277
                (service.slug, invoicing.id), suffix='-%s.pdf' % now, delete=False)
278
        pdftk = PdfTk()
279
        pdftk.concat(all_files, output_file.name)
280
        return output_file.name
281
    except:
282
        if delete and output_file:
283
            try:
284
                os.unlink(output_file.name)
285
            except:
286
                pass
287
        raise
288
    finally:
289
        # eventual cleanup
290
        if delete:
291
            for path in all_files:
292
                try:
293
                    os.unlink(path)
294
                except:
295
                    pass
296

    
297

    
298
def batches_files(service, invoicing, health_center, batches, delete=False,
299
        headers=True, invoices=True, counter=None):
300
    files = []
301
    try:
302
        if headers:
303
            files.append(header_file(service, invoicing, health_center,
304
                batches, delete=delete, counter=counter))
305

    
306
        if invoices:
307
            for batch in batches:
308
                for invoice in batch.invoices:
309
                    # if invoices is a sequence, skip unlisted invoices
310
                    if invoices is not True and invoice not in invoices:
311
                        continue
312
                    files.extend(invoice_files(service, invoicing, batch, invoice, counter=counter))
313
        return files
314
    except:
315
        # cleanup
316
        if delete:
317
            for path in files:
318
                try:
319
                    os.unlink(path)
320
                except:
321
                    pass
322
        raise
(6-6/14)