Project

General

Profile

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

calebasse / calebasse / facturation / models.py @ f28b22e1

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 or '',
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 or '',
260
                                    patient_entry_date=patient.entry_date,
261
                                    patient_exit_date=patient.exit_date)
262
                            if patient.policyholder != patient.patientcontact:
263
                                policy_holder = patient.policyholder
264
                                try:
265
                                    address = unicode(policy_holder.adresses.get(place_of_life=True))
266
                                except:
267
                                    try:
268
                                        address = unicode(policy_holder.adresses.all()[0])
269
                                    except:
270
                                        address = u''
271
                                invoice_kwargs.update(dict(
272
                                    policy_holder_id=policy_holder.id,
273
                                    policy_holder_last_name=policy_holder.last_name,
274
                                    policy_holder_first_name=policy_holder.first_name,
275
                                    policy_holder_social_security_id=policy_holder.social_security_id,
276
                                    policy_holder_healthcenter=policy_holder.health_center,
277
                                    policy_holder_address=address))
278
                            for invoice in invoices[patient]:
279
                                ppa = invoice['ppa'] * 100
280
                                acts = invoice['acts']
281
                                amount = ppa * len(acts)
282
                                in_o = Invoice(
283
                                        invoicing=self,
284
                                        ppa=ppa,
285
                                        amount=amount,
286
                                        **invoice_kwargs)
287
                                in_o.batch = Invoice.objects.new_batch_number(
288
                                            health_center=in_o.health_center,
289
                                            invoicing=self)
290
                                in_o.save()
291
                                for act, hc in acts:
292
                                    act.is_billed = True
293
                                    act.healthcare = hc
294
                                    act.save()
295
                                    in_o.acts.add(act)
296
                            pass
297
                    if patient in acts_losts.keys():
298
                        # TODO: More details about healthcare
299
                        dic['losts'] = acts_losts[patient]
300
                        len_patient_with_lost_acts = len_patient_with_lost_acts + 1
301
                        len_acts_lost = len_acts_lost + len(acts_losts[patient])
302
                    if patient in acts_pause.keys():
303
                        dic['acts_paused'] = acts_pause[patient]
304
                        len_patient_acts_paused = len_patient_acts_paused + 1
305
                        len_acts_paused = len_acts_paused + len(acts_pause[patient])
306
                    if patient in acts_losts_missing_policy.keys():
307
                        # TODO: More details about healthcare
308
                        dic['losts_missing_policy'] = acts_losts_missing_policy[patient]
309
                        len_patient_with_lost_acts_missing_policy = len_patient_with_lost_acts_missing_policy + 1
310
                        len_acts_losts_missing_policy = len_acts_losts_missing_policy + len(acts_losts_missing_policy[patient])
311
                    patients_stats.append((patient, dic))
312
                patients_stats = sorted(patients_stats, key=lambda patient: (patient[0].last_name, patient[0].first_name))
313

    
314
                len_patients = len(patients_stats)
315

    
316
                if commit:
317
                    self.status = Invoicing.STATUS.validated
318
                    self.save()
319

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

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

    
504
    def save(self, *args, **kwargs):
505
        if not self.seq_id:
506
            self.seq_id = self.allocate_seq_id()
507
        super(Invoicing, self).save(*args, **kwargs)
508

    
509
    def close(self, end_date=None):
510
        '''Close an open invoicing'''
511
        if self.service.name != 'CMPP':
512
            raise RuntimeError('closing Invoicing is only for the CMPP')
513
        if self.status != Invoicing.STATUS.open:
514
            raise RuntimeError('closing an un-opened Invoicing')
515
        if not end_date:
516
            today = date.today()
517
            end_date = date(day=today.day, month=today.month, year=today.year)
518
            if end_date < self.start_date:
519
                end_date = self.start_date + relativedelta(days=1)
520
        self.status = Invoicing.STATUS.closed
521
        self.end_date = end_date
522
        self.save()
523
        start_date = self.end_date + relativedelta(days=1)
524
        invoicing = Invoicing(service=self.service,
525
            start_date=start_date,
526
            status=Invoicing.STATUS.open)
527
        invoicing.save()
528
        return invoicing
529

    
530

    
531
#class PricePerAct(models.Model):
532
#    price = models.IntegerField()
533
#    start_date = models.DateField(
534
#            verbose_name=u"Prise d'effet",
535
#            default=date(day=5,month=1,year=1970))
536
#    end_date = models.DateField(
537
#            verbose_name=u"Fin d'effet",
538
#            blank=True,
539
#            null=True)
540

    
541
#    @classmethod
542
#    def get_price(cls, at_date=None):
543
#        if not at_date:
544
#            at_date = date.today()
545
#        if isinstance(at_date, datetime):
546
#            at_date = date(day=at_date.day, month=at_date.month,
547
#                year=at_date.year)
548
#        found = cls.objects.filter(start_date__lte = at_date).latest('start_date')
549
#        if not found:
550
#            raise Exception('No price to apply')
551
#        return found.price
552

    
553
#    def __unicode__(self):
554
#        val = str(self.price) + ' from ' + str(self.start_date)
555
#        if self.end_date:
556
#            val = val + ' to ' + str(self.end_date)
557
#        return val
558

    
559

    
560
#def add_price(price, start_date=None):
561
#    price_o = None
562
#    ppas = PricePerAct.objects.all()
563
#    if ppas:
564
#        if not start_date:
565
#            raise Exception('A start date is mandatory to add a new Price')
566
#        last_ppa = PricePerAct.objects.latest('start_date')
567
#        if last_ppa.start_date >= start_date:
568
#            raise Exception('The new price cannot apply before the price that currently applies.')
569
#        if last_ppa.end_date and last_ppa.end_date != (start_date + relativedelta(days=-1)):
570
#            raise Exception('The new price should apply the day after the last price ends.')
571
#        last_ppa.end_date = start_date + relativedelta(days=-1)
572
#        last_ppa.save()
573
#    if not start_date:
574
#        price_o = PricePerAct(price=price)
575
#    else:
576
#        price_o = PricePerAct(price=price, start_date=start_date)
577
#    price_o.save()
578
#    return price_o
579

    
580

    
581
PREVIOUS_MAX_BATCH_NUMBERS = {
582
    'CF00000004001110': 34,
583
    'CT00000001016421': 1,
584
    'CT00000001016422': 141,
585
    'CT00000001025691': 20,
586
    'CT00000002011011': 8,
587
    'CT00000002381421': 15,
588
    'MA00000002381421': 48,
589
    'SM00000091007381': 98,
590
    'SM00000092001422': 14,
591
    'SM00000092001691': 13,
592
    'SM00000099038939': 24,
593
}
594

    
595

    
596
class InvoiceManager(models.Manager):
597
    def new_batch_number(self, health_center, invoicing):
598
        '''Compute the next batch number for the given health center'''
599
        global PREVIOUS_MAX_BATCH_NUMBERS
600
        agg = self \
601
                .filter(invoicing__seq_id__lt=invoicing.seq_id) \
602
                .filter(
603
                    Q(patient_healthcenter=health_center,
604
                        policy_holder_healthcenter__isnull=True)|
605
                    Q(policy_holder_healthcenter=health_center)) \
606
                        .aggregate(Max('batch'))
607
        max_bn = agg['batch__max']
608
        if max_bn is None:
609
            max_bn = PREVIOUS_MAX_BATCH_NUMBERS.get(health_center.b2_000(), 0)
610
        return max_bn + 1
611

    
612

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

    
657
    created = models.DateTimeField(u'Création', auto_now_add=True)
658
    invoicing = models.ForeignKey('facturation.Invoicing',
659
        on_delete='PROTECT')
660
    acts = models.ManyToManyField('actes.Act')
661
    amount = models.IntegerField()
662
    ppa = models.IntegerField()
663

    
664
    def save(self, *args, **kwargs):
665
        invoicing = self.invoicing
666
        self.number = invoicing.seq_id * 100000 + 1
667
        max_number = invoicing.invoice_set.aggregate(Max('number'))['number__max']
668
        if max_number:
669
            self.number = max_number + 1
670
        super(Invoice, self).save(*args, **kwargs)
671

    
672
    @property
673
    def start_date(self):
674
        res = date.max
675
        for act in self.acts.all():
676
            res = min(res, act.date)
677
        return res
678

    
679
    @property
680
    def health_center(self):
681
        return self.policy_holder_healthcenter or self.patient_healthcenter
682

    
683
    @property
684
    def end_date(self):
685
        res = date.min
686
        for act in self.acts.all():
687
            res = max(res, act.date)
688
        return res
689

    
690
    @property
691
    def decimal_amount(self):
692
        return Decimal(self.amount) / Decimal(100)
693

    
694
    @property
695
    def decimal_ppa(self):
696
        return Decimal(self.ppa) / Decimal(100)
697

    
698
    def __unicode__(self):
699
        return "Facture %d de %d euros (%d actes)" % (self.number, self.amount, len(self.acts.all()))
(7-7/11)