Project

General

Profile

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

calebasse / calebasse / facturation / invoice_header.py @ 0e34ab8f

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

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

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

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

    
28

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

    
46

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

    
71

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

    
162

    
163
def render_invoicing(invoicing, delete=False, headers=True, invoices=True):
164
    service = invoicing.service
165
    now = datetime.datetime.now()
166
    batches_by_health_center = build_batches(invoicing)
167
    centers = sorted(batches_by_health_center.keys())
168
    all_files = []
169
    output_file = None
170
    counter = Counter(1)
171
    try:
172
        for center in centers:
173
            if headers is not True and headers is not False and headers != center:
174
                continue
175
            for batch in batches_by_health_center[center]:
176
                files = batches_files(service, invoicing, center,
177
                    [batch], delete=delete,
178
                    headers=headers, invoices=invoices, counter=counter)
179
                all_files.extend(files)
180
        output_file = tempfile.NamedTemporaryFile(prefix='%s-invoicing-%s-' %
181
                (service.slug, invoicing.id), suffix='-%s.pdf' % now, delete=False)
182
        pdftk = PdfTk()
183
        pdftk.concat(all_files, output_file.name)
184
        return output_file.name
185
    except:
186
        if delete and output_file:
187
            try:
188
                os.unlink(output_file.name)
189
            except:
190
                pass
191
        raise
192
    finally:
193
        # eventual cleanup
194
        if delete:
195
            for path in all_files:
196
                try:
197
                    os.unlink(path)
198
                except:
199
                    pass
200

    
201

    
202

    
203
def batches_files(service, invoicing, health_center, batches, delete=False,
204
        headers=True, invoices=True, counter=None):
205
    files = []
206
    try:
207
        if headers:
208
            files.append(header_file(service, invoicing, health_center,
209
                batches, delete=delete, counter=counter))
210

    
211
        if invoices:
212
            for batch in batches:
213
                for invoice in batch.invoices:
214
                    # if invoices is a sequence, skip unlisted invoices
215
                    if invoices is not True and invoice not in invoices:
216
                        continue
217
                    files.extend(invoice_files(service, invoicing, batch, invoice, counter=counter))
218
        return files
219
    except:
220
        # cleanup
221
        if delete:
222
            for path in files:
223
                try:
224
                    os.unlink(path)
225
                except:
226
                    pass
227
        raise
(6-6/14)