Project

General

Profile

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

calebasse / calebasse / facturation / models.py @ 05cadd08

1
# -*- coding: utf-8 -*-
2

    
3
from datetime import date, datetime
4
from dateutil.relativedelta import relativedelta
5
from decimal import Decimal
6

    
7
from django.db import models
8
from django.db.models import Max, Q
9

    
10
from model_utils import Choices
11

    
12
from calebasse.dossiers.models import PatientRecord
13
from calebasse.ressources.models import ServiceLinkedManager, PricePerAct
14

    
15
import list_acts
16

    
17
def quarter_start_and_end_dates(today=None):
18
    '''Returns the first and last day of the current quarter'''
19
    if today is None:
20
        today = date.today()
21
    quarter = (today.month - 1) / 3
22
    start_date = date(day=1, month=((quarter*3) + 1), year=today.year)
23
    end_date = start_date + relativedelta(months=3) + relativedelta(days=-1)
24
    return start_date, end_date
25

    
26
class InvoicingManager(ServiceLinkedManager):
27
    def current_for_service(self, service):
28
        '''Return the currently open invoicing'''
29
        if service.name != 'CMPP':
30
            start_date, end_date = quarter_start_and_end_dates()
31
            invoicing, created = \
32
                self.get_or_create(start_date=start_date,
33
                end_date=end_date, service=service)
34
            if created:
35
                invoicing.status = Invoicing.STATUS.closed
36
                invoicing.save()
37
        else:
38
            try:
39
                invoicing = self.get(service=service,
40
                        status=Invoicing.STATUS.open)
41
            except Invoicing.DoesNotExist:
42
                today = date.today()
43
                start_date = date(day=today.day, month=today.month, year=today.year)
44
                invoicing, created = self.get_or_create(service=service,
45
                    start_date=start_date,
46
                    status=Invoicing.STATUS.open)
47
        return invoicing
48

    
49
    def last_for_service(self, service):
50
        current = self.current_for_service(service)
51
        last_seq_id = current.seq_id - 1
52
        try:
53
            return self.get(service=service,
54
                seq_id=last_seq_id)
55
        except:
56
            return None
57

    
58

    
59
def build_invoices_from_acts(acts_diagnostic, acts_treatment):
60
    invoices = {}
61
    len_invoices = 0
62
    len_invoices_hors_pause = 0
63
    len_acts_invoiced = 0
64
    len_acts_invoiced_hors_pause = 0
65
    pricing = PricePerAct.pricing()
66
    for patient, acts in acts_diagnostic.items():
67
        invoices[patient] = []
68
        act, hc = acts[0]
69
        invoice = {}
70
        invoice['ppa'] = pricing.price_at_date(act.date)
71
        invoice['year'] = act.date.year
72
        invoice['acts'] = [(act, hc)]
73
        if len(acts) > 1:
74
            for act, hc in acts[1:]:
75
                if invoice['ppa'] != pricing.price_at_date(act.date) or \
76
                        invoice['year'] != act.date.year:
77
                    invoices[patient].append(invoice)
78
                    len_invoices = len_invoices + 1
79
                    len_acts_invoiced = len_acts_invoiced + len(invoice['acts'])
80
                    if not patient.pause:
81
                        len_invoices_hors_pause = len_invoices_hors_pause + 1
82
                        len_acts_invoiced_hors_pause = len_acts_invoiced_hors_pause + len(invoice['acts'])
83
                    invoice['ppa'] = pricing.price_at_date(act.date)
84
                    invoice['year'] = act.date.year
85
                    invoice['acts'] = [(act, hc)]
86
                else:
87
                    invoice['acts'].append((act, hc))
88
        invoices[patient].append(invoice)
89
        len_invoices = len_invoices + 1
90
        len_acts_invoiced = len_acts_invoiced + len(invoice['acts'])
91
        if not patient.pause:
92
            len_invoices_hors_pause = len_invoices_hors_pause + 1
93
            len_acts_invoiced_hors_pause = len_acts_invoiced_hors_pause + len(invoice['acts'])
94
    pricing = PricePerAct.pricing()
95
    for patient, acts in acts_treatment.items():
96
        if not patient in invoices:
97
            invoices[patient] = []
98
        act, hc = acts[0]
99
        invoice = dict()
100
        invoice['ppa'] = pricing.price_at_date(act.date)
101
        invoice['year'] = act.date.year
102
        invoice['acts'] = [(act, hc)]
103
        if len(acts) > 1:
104
            for act, hc in acts[1:]:
105
                if invoice['ppa'] != pricing.price_at_date(act.date) or \
106
                        invoice['year'] != act.date.year:
107
                    invoices[patient].append(invoice)
108
                    len_invoices = len_invoices + 1
109
                    len_acts_invoiced = len_acts_invoiced + len(invoice['acts'])
110
                    if not patient.pause:
111
                        len_invoices_hors_pause = len_invoices_hors_pause + 1
112
                        len_acts_invoiced_hors_pause = len_acts_invoiced_hors_pause + len(invoice['acts'])
113
                    invoice = dict()
114
                    invoice['ppa'] = pricing.price_at_date(act.date)
115
                    invoice['year'] = act.date.year
116
                    invoice['acts'] = [(act, hc)]
117
                else:
118
                    invoice['acts'].append((act, hc))
119
        invoices[patient].append(invoice)
120
        len_invoices = len_invoices + 1
121
        len_acts_invoiced = len_acts_invoiced + len(invoice['acts'])
122
        if not patient.pause:
123
            len_invoices_hors_pause = len_invoices_hors_pause + 1
124
            len_acts_invoiced_hors_pause = len_acts_invoiced_hors_pause + len(invoice['acts'])
125
    return (invoices, len_invoices, len_invoices_hors_pause,
126
        len_acts_invoiced, len_acts_invoiced_hors_pause)
127

    
128
# The firts cmpp invoicing with calebasse
129
INVOICING_OFFSET = 134
130

    
131
class Invoicing(models.Model):
132
    '''Represent a batch of invoices:
133

    
134
       end_date - only acts before this date will be considered
135
       status   - current status of the invoicing
136
       acts     - acts bounded to this invoicing when the invoicing is validated
137

    
138
       STATUS - the possible status:
139
        - open, the invoicing is open for new acts
140
        - closed, invoicing has been closed, no new acts will be accepted after
141
          the end_date,
142
        - validated,
143
    '''
144
    STATUS = Choices('open', 'closed', 'validated', 'sent')
145

    
146
    seq_id = models.IntegerField(blank=True, null=True)
147

    
148
    service = models.ForeignKey('ressources.Service', on_delete='PROTECT')
149

    
150
    start_date = models.DateField(
151
            verbose_name=u'Ouverture de la facturation')
152

    
153
    end_date = models.DateField(
154
            verbose_name=u'Clôturation de la facturation',
155
            blank=True,
156
            null=True)
157

    
158
    status = models.CharField(
159
            verbose_name=u'Statut',
160
            choices=STATUS,
161
            default=STATUS.open,
162
            max_length=20)
163

    
164
    acts = models.ManyToManyField('actes.Act')
165

    
166
    objects = InvoicingManager()
167

    
168
    class Meta:
169
        unique_together = (('seq_id', 'service'),)
170

    
171
    def allocate_seq_id(self):
172
        '''Allocate a new sequence id for a new invoicing.'''
173
        seq_id = 1
174
        max_seq_id = Invoicing.objects.for_service(self.service) \
175
                .aggregate(Max('seq_id'))['seq_id__max']
176
        if not max_seq_id:
177
            if self.service.name == 'CMPP':
178
                seq_id = INVOICING_OFFSET
179
        else:
180
            seq_id = max_seq_id + 1
181
        return seq_id
182

    
183
    def list_for_billing(self):
184
        '''Return the acts candidates for billing'''
185
        if self.service.name == 'CMPP':
186
            end_date = self.end_date
187
            if not end_date:
188
                today = date.today()
189
                end_date = date(day=today.day, month=today.month, year=today.year)
190
            return list_acts.list_acts_for_billing_CMPP_2(end_date,
191
                    service=self.service)
192
        elif self.service.name == 'CAMSP':
193
            return list_acts.list_acts_for_billing_CAMSP(self.start_date,
194
                    self.end_date, service=self.service)
195
        elif 'SESSAD' in self.service.name:
196
            return list_acts.list_acts_for_billing_SESSAD(self.start_date,
197
                    self.end_date, service=self.service)
198
        else:
199
            raise RuntimeError('Unknown service', self.service)
200

    
201

    
202
    def get_stats_or_validate(self, commit=False):
203
        '''
204
            If the invoicing is in state open or closed and commit is False
205
                Return the stats of the billing
206
            If the invoicing is in state open or closed and commit is True
207
                Proceed to invoices creation, healthcare charging, acts as billed
208
                Return the stats of the billing
209
            If the invoicing is in state validated or sent
210
                Return the stats of the billing
211
        '''
212
        days_not_locked = 0
213
        if self.service.name == 'CMPP':
214
            if self.status in (Invoicing.STATUS.open,
215
                    Invoicing.STATUS.closed):
216
                '''
217
                    The stats are build dynamiccaly according to the
218
                    acts billable and the healthcares
219
                '''
220
                (acts_not_locked, days_not_locked, acts_not_valide,
221
                    acts_not_billable, acts_pause, acts_diagnostic,
222
                    acts_treatment, acts_losts,
223
                    acts_losts_missing_policy) = \
224
                        self.list_for_billing()
225

    
226
                (invoices, len_invoices, len_invoices_hors_pause,
227
                    len_acts_invoiced, len_acts_invoiced_hors_pause) = \
228
                        build_invoices_from_acts(acts_diagnostic, acts_treatment)
229
                len_patient_invoiced = len(invoices.keys())
230
                len_patient_invoiced_hors_pause = 0
231
                for patient in invoices.keys():
232
                    if not patient.pause:
233
                        len_patient_invoiced_hors_pause = len_patient_invoiced_hors_pause + 1
234

    
235
                patients = set(acts_not_locked.keys() + acts_not_valide.keys() + \
236
                    acts_not_billable.keys() + acts_diagnostic.keys() + acts_treatment.keys() + \
237
                    acts_losts.keys() + acts_pause.keys() + acts_losts_missing_policy.keys())
238

    
239
                patients_stats = []
240
                len_patient_with_lost_acts = 0
241
                len_acts_lost = 0
242
                len_patient_acts_paused = 0
243
                len_acts_paused = 0
244
                len_patient_with_lost_acts_missing_policy = 0
245
                len_acts_losts_missing_policy = 0
246
                for patient in patients:
247
                    dic = {}
248
                    if patient in invoices.keys():
249
                        dic['invoices'] = invoices[patient]
250
                        if commit and not patient.pause:
251
                            invoice_kwargs = dict(
252
                                    patient_id=patient.id,
253
                                    patient_last_name=patient.last_name,
254
                                    patient_first_name=patient.first_name,
255
                                    patient_social_security_id=patient.social_security_id,
256
                                    patient_birthdate=patient.birthdate,
257
                                    patient_twinning_rank=patient.twinning_rank,
258
                                    patient_healthcenter=patient.health_center,
259
                                    patient_other_health_center=patient.other_health_center)
260
                            if patient.policyholder != patient.patientcontact:
261
                                policy_holder = patient.policyholder
262
                                invoice_kwargs.update(dict(
263
                                    policy_holder_id=policy_holder.id,
264
                                    policy_holder_last_name=policy_holder.last_name,
265
                                    policy_holder_first_name=policy_holder.first_name,
266
                                    policy_holder_social_security_id=policy_holder.social_security_id,
267
                                    policy_holder_healthcenter=policy_holder.health_center))
268
                            for invoice in invoices[patient]:
269
                                ppa = invoice['ppa']
270
                                acts = invoice['acts']
271
                                amount = ppa * len(acts)
272
                                in_o = Invoice(
273
                                        invoicing=self,
274
                                        ppa=invoice['ppa'],
275
                                        amount=amount,
276
                                        **invoice_kwargs)
277
                                in_o.batch = Invoice.objects.new_batch_number(
278
                                            health_center=in_o.health_center,
279
                                            invoicing=self)
280
                                in_o.save()
281
                                for act, hc in acts:
282
                                    act.is_billed = True
283
                                    act.healthcare = hc
284
                                    act.save()
285
                                    in_o.acts.add(act)
286
                            pass
287
                    if patient in acts_losts.keys():
288
                        # TODO: More details about healthcare
289
                        dic['losts'] = acts_losts[patient]
290
                        len_patient_with_lost_acts = len_patient_with_lost_acts + 1
291
                        len_acts_lost = len_acts_lost + len(acts_losts[patient])
292
                    if patient in acts_pause.keys():
293
                        dic['acts_paused'] = acts_pause[patient]
294
                        len_patient_acts_paused = len_patient_acts_paused + 1
295
                        len_acts_paused = len_acts_paused + len(acts_pause[patient])
296
                    if patient in acts_losts_missing_policy.keys():
297
                        # TODO: More details about healthcare
298
                        dic['losts_missing_policy'] = acts_losts_missing_policy[patient]
299
                        len_patient_with_lost_acts_missing_policy = len_patient_with_lost_acts_missing_policy + 1
300
                        len_acts_losts_missing_policy = len_acts_losts_missing_policy + len(acts_losts_missing_policy[patient])
301
                    patients_stats.append((patient, dic))
302
                patients_stats = sorted(patients_stats, key=lambda patient: (patient[0].last_name, patient[0].first_name))
303

    
304
                len_patients = len(patients_stats)
305

    
306
                if commit:
307
                    self.status = Invoicing.STATUS.validated
308
                    self.save()
309

    
310
            else:
311
                '''
312
                    Grab stats from the invoices
313
                '''
314
                len_patients = 0
315
                len_invoices = 0
316
                len_acts_invoiced = 0
317
                patients_stats = {}
318
                days_not_locked = []
319
                invoices = self.invoice_set.all()
320
                patients = {}
321
                for invoice in invoices:
322
                    len_invoices = len_invoices + 1
323
                    len_acts_invoiced = len_acts_invoiced + len(invoice.acts.all())
324
                    patient = None
325
                    if not invoice.patient_id in patients.keys():
326
                        try:
327
                            patient = PatientRecord.objects.get(id=invoice.patient_id)
328
                        except:
329
                            patient = PatientRecord(last_name=patient_last_name, first_name=patient_first_name)
330
                        patients[invoice.patient_id] = patient
331
                        len_patients = len_patients + 1
332
                        patients_stats[patient] = {}
333
                        patients_stats[patient]['invoices'] = []
334
                    else:
335
                        patient = patients[invoice.patient_id]
336
                    patients_stats[patient]['invoices'].append(invoice)
337
                patients_stats = sorted(patients_stats.items(), key=lambda patient: (patient[0].last_name, patient[0].first_name))
338
                # all patients in the invoicing are invoiced
339
                len_patient_invoiced = 0
340
                # These stats are not necessary because excluded form the validated invoicing
341
                len_invoices_hors_pause = 0
342
                len_acts_invoiced_hors_pause = 0
343
                len_patient_invoiced_hors_pause = 0
344
                len_acts_lost = 0
345
                len_patient_with_lost_acts = 0
346
                len_patient_acts_paused = 0
347
                len_acts_paused = 0
348
                len_patient_with_lost_acts_missing_policy = 0
349
                len_acts_losts_missing_policy = 0
350
            return (len_patients, len_invoices, len_invoices_hors_pause,
351
                len_acts_invoiced, len_acts_invoiced_hors_pause,
352
                len_patient_invoiced, len_patient_invoiced_hors_pause,
353
                len_acts_lost, len_patient_with_lost_acts, patients_stats,
354
                days_not_locked, len_patient_acts_paused,
355
                len_acts_paused, len_acts_losts_missing_policy,
356
                len_patient_with_lost_acts_missing_policy)
357
        elif self.service.name == 'CAMSP':
358
            if self.status in Invoicing.STATUS.closed:
359
                (acts_not_locked, days_not_locked, acts_not_valide,
360
                acts_not_billable, acts_pause, acts_bad_state,
361
                acts_accepted) = self.list_for_billing()
362
                len_patient_pause = 0
363
                len_patient_hors_pause = 0
364
                len_acts_pause = 0
365
                len_acts_hors_pause = 0
366
                len_patient_acts_paused = 0
367
                len_acts_paused = 0
368
                patients = set(acts_accepted.keys() + acts_pause.keys())
369
                patients_stats = []
370
                for patient in patients:
371
                    dic = {}
372
                    if patient in acts_accepted.keys():
373
                        acts = acts_accepted[patient]
374
                        dic['accepted'] = acts
375
                        if patient.pause:
376
                            len_patient_pause = len_patient_pause + 1
377
                            len_acts_pause = len_acts_pause + len(acts)
378
                        else:
379
                            len_patient_hors_pause = len_patient_hors_pause + 1
380
                            len_acts_hors_pause = len_acts_hors_pause + len(acts)
381
                            if commit:
382
                                for act in acts:
383
                                    self.acts.add(act)
384
                    if patient in acts_pause.keys():
385
                        dic['acts_paused'] = acts_pause[patient]
386
                        len_patient_acts_paused = len_patient_acts_paused + 1
387
                        len_acts_paused = len_acts_paused + len(acts_pause[patient])
388
                    patients_stats.append((patient, dic))
389
                patients_stats = sorted(patients_stats, key=lambda patient: (patient[0].last_name, patient[0].first_name))
390
                if commit:
391
                    self.status = Invoicing.STATUS.validated
392
                    self.save()
393
            else:
394
                patients_stats = {}
395
                len_patient_pause = 0
396
                len_patient_hors_pause = 0
397
                len_acts_pause = 0
398
                len_acts_hors_pause = 0
399
                len_patient_acts_paused = 0
400
                len_acts_paused = 0
401
                days_not_locked = []
402
                for act in self.acts.all():
403
                    if act.patient in patients_stats.keys():
404
                        patients_stats[act.patient]['accepted'].append(act)
405
                        len_acts_hors_pause = len_acts_hors_pause + 1
406
                    else:
407
                        len_patient_hors_pause = len_patient_hors_pause + 1
408
                        len_acts_hors_pause = len_acts_hors_pause + 1
409
                        patients_stats[act.patient] = {}
410
                        patients_stats[act.patient]['accepted'] = [act]
411
                patients_stats = sorted(patients_stats.items(), key=lambda patient: (patient[0].last_name, patient[0].first_name))
412
            return (len_patient_pause, len_patient_hors_pause,
413
                len_acts_pause, len_acts_hors_pause, patients_stats,
414
                days_not_locked, len_patient_acts_paused,
415
                len_acts_paused)
416
        else:
417
            if self.status in Invoicing.STATUS.closed:
418
                (acts_not_locked, days_not_locked, acts_not_valide,
419
                acts_not_billable, acts_pause, acts_bad_state,
420
                acts_missing_valid_notification, acts_accepted) = \
421
                    self.list_for_billing()
422

    
423
                len_patient_pause = 0
424
                len_patient_hors_pause = 0
425
                len_acts_pause = 0
426
                len_acts_hors_pause = 0
427
                len_patient_acts_paused = 0
428
                len_acts_paused = 0
429
                len_patient_missing_notif = 0
430
                len_acts_missing_notif = 0
431
                patients = set(acts_accepted.keys() + acts_pause.keys())
432
                patients_stats = []
433
                for patient in patients:
434
                    dic = {}
435
                    if patient in acts_accepted.keys():
436
                        acts = acts_accepted[patient]
437
                        dic['accepted'] = acts
438
                        if patient.pause:
439
                            len_patient_pause = len_patient_pause + 1
440
                            len_acts_pause = len_acts_pause + len(acts)
441
                        else:
442
                            len_patient_hors_pause = len_patient_hors_pause + 1
443
                            len_acts_hors_pause = len_acts_hors_pause + len(acts)
444
                            if commit:
445
                                for act in acts:
446
                                    self.acts.add(act)
447
                    if patient in acts_missing_valid_notification.keys():
448
                        acts = acts_missing_valid_notification[patient]
449
                        dic['missings'] = acts
450
                        len_patient_missing_notif = len_patient_missing_notif + 1
451
                        len_acts_missing_notif = len_acts_missing_notif + len(acts)
452
                        if not 'accepted' in dic:
453
                            len_patient_hors_pause = len_patient_hors_pause + 1
454
                        if commit:
455
                            for act in acts:
456
                                self.acts.add(act)
457
                    if patient in acts_pause.keys():
458
                        dic['acts_paused'] = acts_pause[patient]
459
                        len_patient_acts_paused = len_patient_acts_paused + 1
460
                        len_acts_paused = len_acts_paused + len(acts_pause[patient])
461
                    patients_stats.append((patient, dic))
462
                patients_stats = sorted(patients_stats, key=lambda patient: (patient[0].last_name, patient[0].first_name))
463
                len_acts_hors_pause = len_acts_hors_pause + len_acts_missing_notif
464
                if commit:
465
                    self.status = Invoicing.STATUS.validated
466
                    self.save()
467
            else:
468
                patients_stats = {}
469
                len_patient_pause = 0
470
                len_patient_hors_pause = 0
471
                len_acts_pause = 0
472
                len_acts_hors_pause = 0
473
                len_patient_acts_paused = 0
474
                len_acts_paused = 0
475
                len_patient_missing_notif = 0
476
                len_acts_missing_notif = 0
477
                days_not_locked = []
478
                for act in self.acts.all():
479
                    if act.patient in patients_stats.keys():
480
                        patients_stats[act.patient]['accepted'].append(act)
481
                        len_acts_hors_pause = len_acts_hors_pause + 1
482
                    else:
483
                        len_patient_hors_pause = len_patient_hors_pause + 1
484
                        len_acts_hors_pause = len_acts_hors_pause + 1
485
                        patients_stats[act.patient] = {}
486
                        patients_stats[act.patient]['accepted'] = [act]
487
                patients_stats = sorted(patients_stats.items(), key=lambda patient: (patient[0].last_name, patient[0].first_name))
488
            return (len_patient_pause, len_patient_hors_pause,
489
                len_acts_pause, len_acts_hors_pause,
490
                len_patient_missing_notif, len_acts_missing_notif,
491
                patients_stats, days_not_locked,
492
                len_patient_acts_paused, len_acts_paused)
493

    
494
    def save(self, *args, **kwargs):
495
        if not self.seq_id:
496
            self.seq_id = self.allocate_seq_id()
497
        super(Invoicing, self).save(*args, **kwargs)
498

    
499
    def close(self, end_date=None):
500
        '''Close an open invoicing'''
501
        if self.service.name != 'CMPP':
502
            raise RuntimeError('closing Invoicing is only for the CMPP')
503
        if self.status != Invoicing.STATUS.open:
504
            raise RuntimeError('closing an un-opened Invoicing')
505
        if not end_date:
506
            today = date.today()
507
            end_date = date(day=today.day, month=today.month, year=today.year)
508
            if end_date < self.start_date:
509
                end_date = self.start_date + relativedelta(days=1)
510
        self.status = Invoicing.STATUS.closed
511
        self.end_date = end_date
512
        self.save()
513
        start_date = self.end_date + relativedelta(days=1)
514
        invoicing = Invoicing(service=self.service,
515
            start_date=start_date,
516
            status=Invoicing.STATUS.open)
517
        invoicing.save()
518
        return invoicing
519

    
520

    
521
#class PricePerAct(models.Model):
522
#    price = models.IntegerField()
523
#    start_date = models.DateField(
524
#            verbose_name=u"Prise d'effet",
525
#            default=date(day=5,month=1,year=1970))
526
#    end_date = models.DateField(
527
#            verbose_name=u"Fin d'effet",
528
#            blank=True,
529
#            null=True)
530

    
531
#    @classmethod
532
#    def get_price(cls, at_date=None):
533
#        if not at_date:
534
#            at_date = date.today()
535
#        if isinstance(at_date, datetime):
536
#            at_date = date(day=at_date.day, month=at_date.month,
537
#                year=at_date.year)
538
#        found = cls.objects.filter(start_date__lte = at_date).latest('start_date')
539
#        if not found:
540
#            raise Exception('No price to apply')
541
#        return found.price
542

    
543
#    def __unicode__(self):
544
#        val = str(self.price) + ' from ' + str(self.start_date)
545
#        if self.end_date:
546
#            val = val + ' to ' + str(self.end_date)
547
#        return val
548

    
549

    
550
#def add_price(price, start_date=None):
551
#    price_o = None
552
#    ppas = PricePerAct.objects.all()
553
#    if ppas:
554
#        if not start_date:
555
#            raise Exception('A start date is mandatory to add a new Price')
556
#        last_ppa = PricePerAct.objects.latest('start_date')
557
#        if last_ppa.start_date >= start_date:
558
#            raise Exception('The new price cannot apply before the price that currently applies.')
559
#        if last_ppa.end_date and last_ppa.end_date != (start_date + relativedelta(days=-1)):
560
#            raise Exception('The new price should apply the day after the last price ends.')
561
#        last_ppa.end_date = start_date + relativedelta(days=-1)
562
#        last_ppa.save()
563
#    if not start_date:
564
#        price_o = PricePerAct(price=price)
565
#    else:
566
#        price_o = PricePerAct(price=price, start_date=start_date)
567
#    price_o.save()
568
#    return price_o
569

    
570

    
571
PREVIOUS_MAX_BATCH_NUMBERS = {
572
    'CF00000004001110': 34,
573
    'CT00000001016421': 1,
574
    'CT00000001016422': 141,
575
    'CT00000001025691': 20,
576
    'CT00000002011011': 8,
577
    'CT00000002381421': 15,
578
    'MA00000002381421': 48,
579
    'SM00000091007381': 98,
580
    'SM00000092001422': 14,
581
    'SM00000092001691': 13,
582
    'SM00000099038939': 24,
583
}
584

    
585

    
586
class InvoiceManager(models.Manager):
587
    def new_batch_number(self, health_center, invoicing):
588
        '''Compute the next batch number for the given health center'''
589
        global PREVIOUS_MAX_BATCH_NUMBERS
590
        agg = self \
591
                .filter(invoicing__seq_id__lt=invoicing.seq_id) \
592
                .filter(
593
                    Q(patient_healthcenter=health_center,
594
                        policy_holder_healthcenter__isnull=True)|
595
                    Q(policy_holder_healthcenter=health_center)) \
596
                        .aggregate(Max('batch'))
597
        max_bn = agg['batch__max']
598
        if max_bn is None:
599
            max_bn = PREVIOUS_MAX_BATCH_NUMBERS.get(health_center.b2_000(), 0)
600
        return max_bn + 1
601

    
602

    
603
class Invoice(models.Model):
604
    objects = InvoiceManager()
605
    number = models.IntegerField(blank=True, null=True)
606
    batch = models.IntegerField(blank=True, null=True)
607
    # the patient can be modified (or even deleted) after invoice creation, so
608
    # we copy his informations here
609
    patient_id = models.IntegerField(blank=True, null=True)
610
    patient_last_name = models.CharField(max_length=128,
611
            verbose_name=u'Nom du patient', default='', blank=True)
612
    patient_first_name = models.CharField(max_length=128,
613
            verbose_name=u'Prénom(s) du patient', default='', blank=True)
614
    patient_social_security_id = models.CharField(max_length=13,
615
            verbose_name=u"NIR", default='', blank=True)
616
    patient_birthdate = models.DateField(verbose_name=u"Date de naissance",
617
            null=True, blank=True)
618
    patient_twinning_rank = models.IntegerField(
619
        verbose_name=u"Rang (gémellité)",
620
        null=True, blank=True)
621
    patient_healthcenter = models.ForeignKey('ressources.HealthCenter',
622
            verbose_name=u"Centre d'assurance maladie",
623
            related_name='related_by_patient_invoices',
624
            null=True, blank=True)
625
    patient_other_health_center = models.CharField(
626
        verbose_name=u"Centre spécifique", max_length=4, default='',
627
        blank=True)
628
    # policy holder informations
629
    policy_holder_id = models.IntegerField(blank=True, null=True)
630
    policy_holder_last_name = models.CharField(max_length=128,
631
            verbose_name=u'Nom de l\'assuré', default='', blank=True)
632
    policy_holder_first_name = models.CharField(max_length=128,
633
            verbose_name=u'Prénom(s) de l\' assuré', default='', blank=True)
634
    policy_holder_social_security_id = models.CharField(max_length=13,
635
            verbose_name=u"NIR de l\'assuré", default='', blank=True)
636
    policy_holder_healthcenter = models.ForeignKey('ressources.HealthCenter',
637
            verbose_name=u"Centre d'assurance maladie de l\'assuré",
638
            related_name='related_by_policy_holder_invoices',
639
            null=True, blank=True)
640
    policy_holder_address = models.CharField(max_length=128,
641
            verbose_name=u'Adresse de l\'assuré', default='', blank=True)
642

    
643
    created = models.DateTimeField(u'Création', auto_now_add=True)
644
    invoicing = models.ForeignKey('facturation.Invoicing',
645
        on_delete='PROTECT')
646
    acts = models.ManyToManyField('actes.Act')
647
    amount = models.IntegerField()
648
    ppa = models.IntegerField()
649

    
650
    def save(self, *args, **kwargs):
651
        invoicing = self.invoicing
652
        self.number = invoicing.seq_id * 100000 + 1
653
        max_number = invoicing.invoice_set.aggregate(Max('number'))['number__max']
654
        if max_number:
655
            self.number = max_number + 1
656
        super(Invoice, self).save(*args, **kwargs)
657

    
658
    @property
659
    def start_date(self):
660
        res = date.max
661
        for act in self.acts.all():
662
            res = min(res, act.date)
663
        return res
664

    
665
    @property
666
    def health_center(self):
667
        return self.policy_holder_healthcenter or self.patient_healthcenter
668

    
669
    @property
670
    def end_date(self):
671
        res = date.min
672
        for act in self.acts.all():
673
            res = max(res, act.date)
674
        return res
675

    
676
    @property
677
    def decimal_amount(self):
678
        return Decimal(self.amout) / Decimal(100)
679

    
680
    def __unicode__(self):
681
        return "Facture %d de %d euros (%d actes)" % (self.number, self.amount, len(self.acts.all()))
(6-6/10)