facturation: implement regularization computation for b2 and printings.

This commit is contained in:
Mikaël Ates 2014-01-13 15:46:59 +01:00
parent 8386ed4d12
commit 8bc46b58a8
3 changed files with 258 additions and 96 deletions

View File

@ -16,7 +16,7 @@ from calebasse.facturation.models import Invoicing
from batches import build_batches
from transmission_utils import build_mail
DEFAULT_OUTPUT_DIRECTORY = '/var/lib/calebasse/B2'
DEFAULT_OUTPUT_DIRECTORY = '/Donnees/devs/aps42/travail_sur_stats/b2_test/'
DEFAULT_NORME = 'CP '
DEFAULT_TYPE_EMETTEUR = 'TE'
DEFAULT_APPLICATION = 'TR'
@ -24,6 +24,8 @@ DEFAULT_CATEGORIE = '189'
DEFAULT_STATUT = '60'
DEFAULT_MODE_TARIF = '05'
DEFAULT_MESSAGE = 'ENTROUVERT 0143350135 CALEBASSE 1307'
DEFAULT_NUMERO_EMETTEUR = '123456789'
DEFAULT_NOM = 'TBD'
# B2 informations / configuration
# from settings.py :
@ -44,14 +46,14 @@ except (ImportError, AttributeError):
NORME = b2_transmission_settings.get('norme', DEFAULT_NORME)
TYPE_EMETTEUR = b2_transmission_settings.get('type_emetteur', DEFAULT_TYPE_EMETTEUR)
NUMERO_EMETTEUR = b2_transmission_settings.get('numero_emetteur')
NUMERO_EMETTEUR = b2_transmission_settings.get('numero_emetteur', DEFAULT_NUMERO_EMETTEUR)
APPLICATION = b2_transmission_settings.get('application', DEFAULT_APPLICATION)
CATEGORIE = b2_transmission_settings.get('categorie', DEFAULT_CATEGORIE)
STATUT = b2_transmission_settings.get('statut', DEFAULT_STATUT)
MODE_TARIF = b2_transmission_settings.get('mode_tarif', DEFAULT_MODE_TARIF)
NOM = b2_transmission_settings.get('nom', '')[:40]
NOM = b2_transmission_settings.get('nom', DEFAULT_NOM)[:40]
NOM = NOM + ' '*(40-len(NOM))
MESSAGE = b2_transmission_settings.get('message', DEFAULT_MESSAGE)[:37]
@ -119,69 +121,97 @@ def write128(output_file, line):
(len(line), line))
output_file.write(line)
def write_invoice(output_file, invoice):
def write_invoice(output_file, invoice, operation='1', list_acts_prices=None):
invoice_lines = 0
start_date = invoice.start_date
start_2 = '2' + NUMERO_EMETTEUR + ' ' + \
invoice.policy_holder_social_security_id + \
get_control_key(invoice.policy_holder_social_security_id) + \
'000' + ('%0.9d' % invoice.number) + \
'1' + ('%0.9d' % invoice.patient_id) + \
invoice.policy_holder_healthcenter.large_regime.code + \
invoice.policy_holder_healthcenter.dest_organism + \
(invoice.policy_holder_other_health_center or '0000') + \
'3' + b2date(start_date) + '000000' + \
invoice.policy_holder_healthcenter.dest_organism + '000' + \
'10' + '3' + \
b2date(start_date) + \
'000000000' + ' ' + \
b2date(invoice.patient_birthdate) + \
('%d' % invoice.patient_twinning_rank)[-1:] + \
b2date(start_date) + b2date(invoice.end_date) + '01' + \
'00' + filler(10)
write128(output_file, start_2)
invoice_lines += 1
nb_type3 = 0
kind = invoice.first_tag[0]
prestation = u'SNS ' if kind == 'T' else u'SD '
for date in invoice.list_dates.split('$'):
line_3 = '3' + NUMERO_EMETTEUR + ' ' + \
try:
start_date = invoice.start_date
start_2 = '2' + NUMERO_EMETTEUR + ' ' + \
invoice.policy_holder_social_security_id + \
get_control_key(invoice.policy_holder_social_security_id) + \
'000' + ('%0.9d' % invoice.number) + \
'19' + '320' + \
b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
prestation + '001' + \
' ' + '00100' + ' ' + '00000' + \
('%0.7d' % invoice.ppa) + \
('%0.8d' % invoice.ppa) + \
'100' + \
('%0.8d' % invoice.ppa) + \
('%0.8d' % invoice.ppa) + \
'0000' + '000' + ' ' + filler(2) + ' ' + \
' ' + '0000000'
write128(output_file, line_3)
operation + ('%0.9d' % invoice.patient_id) + \
invoice.policy_holder_healthcenter.large_regime.code + \
invoice.policy_holder_healthcenter.dest_organism + \
(invoice.policy_holder_other_health_center or '0000') + \
'3' + b2date(start_date) + '000000' + \
invoice.policy_holder_healthcenter.dest_organism + '000' + \
'10' + '3' + \
b2date(start_date) + \
'000000000' + ' ' + \
b2date(invoice.patient_birthdate) + \
('%d' % invoice.patient_twinning_rank)[-1:] + \
b2date(start_date) + b2date(invoice.end_date) + '01' + \
'00' + filler(10)
# print "type2 : invoice.number %d" % invoice.number
write128(output_file, start_2)
invoice_lines += 1
nb_type3 += 1
nb_type3 = 0
kind = invoice.first_tag[0]
prestation = u'SNS ' if kind == 'T' else u'SD '
if operation == '4' and list_acts_prices:
for date, ppa in list_acts_prices:
line_3 = '3' + NUMERO_EMETTEUR + ' ' + \
invoice.policy_holder_social_security_id + \
get_control_key(invoice.policy_holder_social_security_id) + \
'000' + ('%0.9d' % invoice.number) + \
'19' + '320' + \
b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
prestation + '001' + \
' ' + '00100' + ' ' + '00000' + \
('%0.7d' % ppa) + \
('%0.8d' % ppa) + \
'100' + \
('%0.8d' % ppa) + \
('%0.8d' % ppa) + \
'0000' + '000' + ' ' + filler(2) + ' ' + \
' ' + '0000000'
write128(output_file, line_3)
nb_type3 += 1
invoice_lines += 1
else:
for date in invoice.list_dates.split('$'):
line_3 = '3' + NUMERO_EMETTEUR + ' ' + \
invoice.policy_holder_social_security_id + \
get_control_key(invoice.policy_holder_social_security_id) + \
'000' + ('%0.9d' % invoice.number) + \
'19' + '320' + \
b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
b2date(datetime.datetime.strptime(date, "%d/%m/%Y")) + \
prestation + '001' + \
' ' + '00100' + ' ' + '00000' + \
('%0.7d' % invoice.ppa) + \
('%0.8d' % invoice.ppa) + \
'100' + \
('%0.8d' % invoice.ppa) + \
('%0.8d' % invoice.ppa) + \
'0000' + '000' + ' ' + filler(2) + ' ' + \
' ' + '0000000'
write128(output_file, line_3)
nb_type3 += 1
invoice_lines += 1
# print "type3 : invoice.number %d" % invoice.number
end_5 = '5' + NUMERO_EMETTEUR + ' ' + \
invoice.policy_holder_social_security_id + \
get_control_key(invoice.policy_holder_social_security_id) + \
'000' + ('%0.9d' % invoice.number) + \
('%0.3d' % nb_type3) + \
('%0.8d' % invoice.amount) + \
('%0.8d' % invoice.amount) + \
'00000000' + '00000000' + '00000000' + '00000000' + '00000000' + \
filler(17) + \
('%0.8d' % invoice.amount) + \
filler(4+2)
write128(output_file, end_5)
invoice_lines += 1
end_5 = '5' + NUMERO_EMETTEUR + ' ' + \
invoice.policy_holder_social_security_id + \
get_control_key(invoice.policy_holder_social_security_id) + \
'000' + ('%0.9d' % invoice.number) + \
('%0.3d' % nb_type3) + \
('%0.8d' % invoice.amount) + \
('%0.8d' % invoice.amount) + \
'00000000' + '00000000' + '00000000' + '00000000' + '00000000' + \
filler(17) + \
('%0.8d' % invoice.amount) + \
filler(4+2)
write128(output_file, end_5)
invoice_lines += 1
# print "type5 : invoice.amount %d" % invoice.amount
except Exception, e:
print "Invoice (ID: %d, number: %d) generation error: %s" % (invoice.id, invoice.number, e)
return invoice_lines
def b2(seq_id, hc, batches):
def b2(seq_id, hc, batches, adj_date=None, adj_price=None):
to = hc.b2_000()
total = sum(b.total for b in batches)
first_batch = min(b.number for b in batches)
@ -228,6 +258,7 @@ def b2(seq_id, hc, batches):
' ' + '062007' + 'U' + filler(2+3+1+34)
write128(output_file, start_1)
nb_lines += 1
# print "type1 : batch.number %d" % batch.number
infos['batches'].append({
'batch': batch.number,
@ -237,8 +268,30 @@ def b2(seq_id, hc, batches):
'number_of_acts': batch.number_of_acts
})
for i in batch.invoices:
nb_lines += write_invoice(output_file, i)
if adj_date and adj_price:
for i in batch.invoices:
nb_lines += write_invoice(output_file, i, operation='5')
i.number += 1
list_acts_prices = list()
amount = 0
for date in i.list_dates.split('$'):
date_o = datetime.datetime.strptime(date, '%d/%m/%Y')
price = None
if date_o < adj_date:
price = i.ppa
else:
price = adj_price
amount += price
list_acts_prices.append((date, price))
a_tmp = i.amount
i.amount = amount
nb_lines += write_invoice(output_file, i, operation='4',
list_acts_prices=list_acts_prices)
i.amount = a_tmp
i.number -= 1
else:
for i in batch.invoices:
nb_lines += write_invoice(output_file, i)
end_6 = '6' + NUMERO_EMETTEUR + \
('%0.3d' % batch.number_of_invoices) + \
@ -252,6 +305,7 @@ def b2(seq_id, hc, batches):
write128(output_file, end_6)
nb_lines += 1
nb_batches += 1
# print "type6 : batch.number_of_invoices %d batch.number_of_acts %d batch.total %d" % (batch.number_of_invoices, batch.number_of_acts, batch.total)
if nb_lines > 990:
raise

View File

@ -15,6 +15,7 @@ from invoice_template import InvoiceTemplate
from ..pdftk import PdfTk
from batches import build_batches
from calebasse.utils import get_nir_control_key
from calebasse.ressources.models import Service
class Counter(object):
@ -62,7 +63,26 @@ def header_file(service, invoicing, health_center, batches,
header_service_template='facturation/bordereau-%s.html',
header_template='facturation/bordereau.html',
delete=False,
counter=None):
counter=None,
adj_date=None, adj_price=None, seq_id=0):
if adj_date and adj_price:
for batch in batches:
invoices_n = list()
amount = 0
for i in batch.invoices:
acts = list()
for date in i.list_dates.split('$'):
date_o = datetime.datetime.strptime(date, '%d/%m/%Y')
if date_o >= adj_date:
amount = amount + adj_price - i.ppa
price = None
if date_o < adj_date:
price = i.ppa
else:
price = adj_price
acts.append((date, price))
i.list_dates = acts
synthesis = {
'total': sum(batch.total for batch in batches),
'number_of_acts': sum(batch.number_of_acts for batch in batches),
@ -76,24 +96,30 @@ def header_file(service, invoicing, health_center, batches,
'synthesis': synthesis,
'counter': counter,
}
if adj_date and adj_price:
ctx['adjustment'] = True
if invoicing:
seq_id = invoicing.id
prefix = '%s-invoicing-%s-healthcenter-%s-' % (
service.slug, invoicing.id, health_center.id)
service.slug, seq_id, health_center.id)
return render_to_pdf_file(
(header_service_template % service.slug,
header_template), ctx, prefix=prefix, delete=delete)
def invoice_files(service, invoicing, batch, invoice, counter=None):
def invoice_files(service, invoicing, batch, invoice, counter=None,
adjustment=False, seq_id=0):
template_path = os.path.join(
os.path.dirname(__file__),
'static',
'facturation',
'invoice.pdf')
if invoicing:
seq_id = invoicing.id
tpl = InvoiceTemplate(
template_path=template_path,
prefix='%s-invoicing-%s-invoice-%s-'
% ( service.slug, invoicing.id, invoice.id),
% ( service.slug, seq_id, invoice.number),
suffix='-%s.pdf' % datetime.datetime.now())
health_center = invoice.health_center
code_organisme = u'%s - %s %s' % (
@ -144,14 +170,14 @@ def invoice_files(service, invoicing, batch, invoice, counter=None):
})
total1 = Decimal(0)
total2 = Decimal(0)
total1_a = Decimal(0)
total2_a = Decimal(0)
tableau1 = []
tableau2 = []
tableau1_a = []
tableau2_a = []
dates = []
if invoice.list_dates:
dates = invoice.list_dates.split('$')
if dates:
if len(dates) > 30:
raise RuntimeError('Too much acts in invoice %s' % invoice.id)
if adjustment:
kind = 'X'
offset = 0
prestation = u'X'
@ -159,32 +185,77 @@ def invoice_files(service, invoicing, batch, invoice, counter=None):
kind = invoice.first_tag[0]
offset = int(invoice.first_tag[1:])
prestation = u'SNS' if kind == 'T' else u'SD'
for date in dates[:15]:
for date, price in invoice.list_dates[:15]:
tableau1.append([u'19', u'320', prestation, date, date,
invoice.decimal_ppa, 1, invoice.decimal_ppa, kind + str(offset)])
total1 += invoice.decimal_ppa
(invoice.decimal_ppa * (-1)), 1, (invoice.decimal_ppa * (-1)), kind + str(offset)])
total1 += (invoice.decimal_ppa * (-1))
tableau1_a.append([u'19', u'320', prestation, date, date,
Decimal(price) / Decimal(100), 1, Decimal(price) / Decimal(100), kind + str(offset)])
total1_a += Decimal(price) / Decimal(100)
offset += 1
for date in dates[15:30]:
for date, price in invoice.list_dates[15:30]:
tableau2.append([u'19', u'320', prestation, date, date,
invoice.decimal_ppa, 1, invoice.decimal_ppa, kind + str(offset)])
total2 += invoice.decimal_ppa
(invoice.decimal_ppa * (-1)), 1, (invoice.decimal_ppa * (-1)), kind + str(offset)])
total2 += (invoice.decimal_ppa * (-1))
tableau2_a.append([u'19', u'320', prestation, date, date,
Decimal(price) / Decimal(100), 1, Decimal(price) / Decimal(100), kind + str(offset)])
total2_a += Decimal(price) / Decimal(100)
offset += 1
else:
if invoice.list_dates:
dates = invoice.list_dates.split('$')
if dates:
if len(dates) > 30:
raise RuntimeError('Too much acts in invoice %s' % invoice.id)
kind = 'X'
offset = 0
prestation = u'X'
if invoice.first_tag:
kind = invoice.first_tag[0]
offset = int(invoice.first_tag[1:])
prestation = u'SNS' if kind == 'T' else u'SD'
for date in dates[:15]:
tableau1.append([u'19', u'320', prestation, date, date,
invoice.decimal_ppa, 1, invoice.decimal_ppa, kind + str(offset)])
total1 += invoice.decimal_ppa
offset += 1
for date in dates[15:30]:
tableau2.append([u'19', u'320', prestation, date, date,
invoice.decimal_ppa, 1, invoice.decimal_ppa, kind + str(offset)])
total2 += invoice.decimal_ppa
offset += 1
ctx.update({
'TABLEAU1': tableau1,
'TABLEAU2': tableau2,
})
ctx['SOUS_TOTAL1'] = total1
if total2 != Decimal(0):
ctx['SOUS_TOTAL2'] = total2
ctx['TOTAL'] = invoice.decimal_amount
if adjustment:
ctx['SOUS_TOTAL1'] = total1
if total2 != Decimal(0):
ctx['SOUS_TOTAL2'] = total2
ctx['TOTAL'] = total1 + total2
neg = tpl.generate(ctx)
ctx['TABLEAU1'] = tableau1_a
ctx['TABLEAU2'] = tableau2_a
ctx['SOUS_TOTAL1'] = total1_a
if total2 != Decimal(0):
ctx['SOUS_TOTAL2'] = total2_a
ctx['TOTAL'] = total1_a + total2_a
ctx['NUM_FACTURE'] = unicode(invoice.number + 1)
pos = tpl.generate(ctx)
return [neg, pos]
else:
ctx['SOUS_TOTAL1'] = total1
if total2 != Decimal(0):
ctx['SOUS_TOTAL2'] = total2
ctx['TOTAL'] = invoice.decimal_amount
try:
repeat = settings.BATCH_CONTENT_TIMES_IN_INVOINCING_FILE
except:
repeat = 1
try:
repeat = settings.BATCH_CONTENT_TIMES_IN_INVOINCING_FILE
except:
repeat = 1
output = tpl.generate(ctx)
return [output for i in xrange(repeat)]
output = tpl.generate(ctx)
return [output for i in xrange(repeat)]
def render_not_cmpp_header(invoicing):
header_template='facturation/bordereau_not_cmpp_header.html'
@ -277,14 +348,24 @@ def render_not_cmpp_content(invoicing):
(header_template, ), ctx, prefix=prefix, delete=True)
def render_invoicing(invoicing, delete=False, headers=True, invoices=True):
service = invoicing.service
def render_invoicing(invoicing=None, delete=False, headers=True, invoices=True,
batches_by_health_center=None,
adj_date=None, adj_price=None, seq_id=0):
service = None
if not invoicing:
service = Service.objects.get(name='CMPP')
else:
service = invoicing.service
now = datetime.datetime.now()
output_file = None
all_files = [price_details(service, invoicing)]
all_files = []
if invoicing:
all_files = [price_details(service, invoicing)]
seq_id = invoicing.seq_id
try:
if service.name == 'CMPP':
batches_by_health_center = build_batches(invoicing)
if invoicing and not batches_by_health_center:
batches_by_health_center = build_batches(invoicing)
centers = sorted(batches_by_health_center.keys())
counter = Counter(1)
for center in centers:
@ -293,7 +374,8 @@ def render_invoicing(invoicing, delete=False, headers=True, invoices=True):
for batch in batches_by_health_center[center]:
files = batches_files(service, invoicing, center,
[batch], delete=delete,
headers=headers, invoices=invoices, counter=counter)
headers=headers, invoices=invoices, counter=counter,
adj_date=adj_date, adj_price=adj_price)
all_files.extend(files)
else:
header = render_not_cmpp_header(invoicing)
@ -306,11 +388,11 @@ def render_invoicing(invoicing, delete=False, headers=True, invoices=True):
if not os.path.exists(to_path):
os.makedirs(to_path)
to_path = os.path.join(to_path, '%s-facturation-%s-%s.pdf' \
% (service.slug, invoicing.seq_id, now.strftime('%d%m%Y-%H%M')))
% (service.slug, seq_id, now.strftime('%d%m%Y-%H%M')))
output_file = open(to_path, 'w')
if not output_file:
output_file = tempfile.NamedTemporaryFile(prefix='%s-invoicing-%s-' %
(service.slug, invoicing.id), suffix='-%s.pdf' % now, delete=False)
(service.slug, seq_id), suffix='-%s.pdf' % now, delete=False)
pdftk = PdfTk()
pdftk.concat(all_files, output_file.name)
return output_file.name
@ -332,12 +414,14 @@ def render_invoicing(invoicing, delete=False, headers=True, invoices=True):
def batches_files(service, invoicing, health_center, batches, delete=False,
headers=True, invoices=True, counter=None):
headers=True, invoices=True, counter=None,
adj_date=None, adj_price=None, seq_id=0):
files = []
try:
if headers:
header = header_file(service, invoicing, health_center, batches,
delete=delete, counter=counter)
delete=delete, counter=counter,
adj_date=adj_date, adj_price=adj_price, seq_id=seq_id)
try:
repeat = settings.BATCH_HEADER_TIMES_IN_INVOICING_FILE
@ -351,8 +435,9 @@ def batches_files(service, invoicing, health_center, batches, delete=False,
# if invoices is a sequence, skip unlisted invoices
if invoices is not True and invoice not in invoices:
continue
files.extend(invoice_files(service, invoicing, batch, invoice, counter=counter))
files.extend(invoice_files(service, invoicing, batch,
invoice, counter=counter,
adjustment=True, seq_id=seq_id))
return files
except:
# cleanup

View File

@ -176,6 +176,28 @@
</tr>
</thead>
<tbody class="batch-content" style="border: none;">
{% if adjustment %}
{% for invoice in batch.invoices %}
<tr>
<td>{{ invoice.number }}</td>
<td>{{ invoice.patient_first_name}} {{ invoice.patient_last_name|upper }}</td>
<td>{% firstof invoice.policy_holder_social_security_id_full invoice.patient_social_security_id_full %}</td>
<td>{% if invoice.kind %}{{ invoice.kind }}{% endif %}</td>
<td>{{ invoice.start_date|date:"d/m/Y" }}</td>
<td>{{ invoice.end_date|date:"d/m/Y" }}</td>
<td>- {{ invoice.decimal_amount|floatformat:2 }}</td>
</tr>
<tr>
<td>{{ invoice.number|add:'1' }}</td>
<td>{{ invoice.patient_first_name}} {{ invoice.patient_last_name|upper }}</td>
<td>{% firstof invoice.policy_holder_social_security_id_full invoice.patient_social_security_id_full %}</td>
<td>{% if invoice.kind %}{{ invoice.kind }}{% endif %}</td>
<td>{{ invoice.start_date|date:"d/m/Y" }}</td>
<td>{{ invoice.end_date|date:"d/m/Y" }}</td>
<td>{{ invoice.decimal_amount_corrected|floatformat:2 }}</td>
</tr>
{% endfor %}
{% else %}
{% for invoice in batch.invoices %}
<tr>
<td>{{ invoice.number }}</td>
@ -187,6 +209,7 @@
<td>{{ invoice.decimal_amount|floatformat:2 }}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
<div style="text-align: right; border: none;">