292 lines
11 KiB
Python
292 lines
11 KiB
Python
from django.shortcuts import render
|
|
from django.template import RequestContext
|
|
from django.http import HttpResponse
|
|
from django.db.models import Sum
|
|
|
|
from reportlab.pdfgen import canvas
|
|
from reportlab.lib.colors import Color, black, blue, red
|
|
from reportlab.lib.pagesizes import A4
|
|
|
|
# from PIL import Image
|
|
import os
|
|
from django.conf import settings
|
|
|
|
from datetime import date
|
|
|
|
from comptabilite.facture_config import loadFactureConfig
|
|
|
|
from .models import (
|
|
Client,
|
|
Contract,
|
|
Prestation,
|
|
)
|
|
|
|
|
|
def contract_listing(request):
|
|
"""
|
|
Renvoie la liste de tous les contrats.
|
|
"""
|
|
|
|
contract_list = Contract.objects.all()
|
|
context = {'contract_list': contract_list}
|
|
return render(request, 'billing/contract/listing.html', context)
|
|
|
|
|
|
def contract_detail(request, contractid):
|
|
"""
|
|
Renvoie toutes les informations relatives à un contrat, en ce y compris les prestations
|
|
relatives à celui-ci.
|
|
"""
|
|
|
|
contract = Contract.objects.get(pk=contractid)
|
|
prestation_list = contract.get_prestation.all()
|
|
prestation_count = prestation_list.count()
|
|
total = list(contract.get_prestation.all().aggregate(Sum('total_amount')).values())[0]
|
|
context = {'contract': contract,
|
|
'prestation_list': prestation_list,
|
|
'prestation_count': prestation_count,
|
|
'total': total}
|
|
return render(request, 'billing/contract/detail.html', context)
|
|
|
|
|
|
def client_listing(request):
|
|
"""
|
|
Renvoie la liste de tous les clients.
|
|
"""
|
|
client_list = Client.objects.all()
|
|
context = {'client_list': client_list}
|
|
return render(request, 'billing/client/listing.html', context)
|
|
|
|
|
|
def prestation_listing(request):
|
|
"""
|
|
Renvoie la liste de toutes les prestations.
|
|
"""
|
|
prestation_list = Prestation.objects.all()
|
|
context = {'prestation_list': prestation_list}
|
|
return render(request, 'billing/prestation/listing.html', context)
|
|
|
|
|
|
Y = 841.89
|
|
X = 35
|
|
RIGHT_X = 595.27 - X
|
|
TITLED_X = 125
|
|
INDENTED_X = X + 5
|
|
INDENTED_RIGHT_X = RIGHT_X - 5
|
|
|
|
PRESTATION_COLUMN_2 = INDENTED_X + 65
|
|
PRESTATION_COLUMN_3 = INDENTED_X + 400
|
|
PRESTATION_COLUMN_4 = INDENTED_X + 455
|
|
|
|
COMMON_LINE_HEIGHT = -15
|
|
DOUBLE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 2
|
|
BIG_LINE_HEIGHT = COMMON_LINE_HEIGHT * 3
|
|
HUGE_LINE_HEIGHT = COMMON_LINE_HEIGHT * 4
|
|
|
|
class MyDocument(object):
|
|
# Create the PDF object, using the response object as its "file."
|
|
# http://www.reportlab.com/docs/reportlab-userguide.pdf
|
|
# canvas.rect(x, y, width, height, stroke=1, fill=0)
|
|
# localhost:8000/billing/contract/pdf/2
|
|
|
|
def __init__(self, response):
|
|
# Create the PDF object, using the response object as its "file."
|
|
self.document = canvas.Canvas(response, pagesize=A4)
|
|
self.y = Y - X
|
|
|
|
def newline(self, height=None):
|
|
"""
|
|
Passe à la ligne, la hauteur de la ligne étant passée en paramètre.
|
|
"""
|
|
if height == DOUBLE_LINE_HEIGHT:
|
|
self.y += DOUBLE_LINE_HEIGHT
|
|
elif height == BIG_LINE_HEIGHT:
|
|
self.y += BIG_LINE_HEIGHT
|
|
elif height == HUGE_LINE_HEIGHT:
|
|
self.y += HUGE_LINE_HEIGHT
|
|
else:
|
|
self.y += COMMON_LINE_HEIGHT
|
|
|
|
# if y < 120;
|
|
# document.PageBreak()
|
|
# y = 790
|
|
|
|
def drawString(self, x, string, font_family="Helvetica", font_decoration=None, font_size=10):
|
|
font = font_family
|
|
if font_decoration is not None:
|
|
font += "-" + font_decoration
|
|
self.document.setFont(font, font_size)
|
|
self.document.drawString(x, self.y, string)
|
|
|
|
def drawNewLine(self, x, string, height=None, font_family="Helvetica", font_decoration=None, font_size=10):
|
|
self.newline(height)
|
|
self.drawString(x, string, font_family, font_decoration, font_size)
|
|
|
|
def header(self, info, contract):
|
|
"""
|
|
Génère le header de la facture.
|
|
"""
|
|
# self.document.rect(X, 735, 525, 70, fill=0)
|
|
self.drawNewLine(INDENTED_X, info['NAME'])
|
|
self.document.drawRightString(RIGHT_X, self.y, "N° de Référence : " + str(contract.reference))
|
|
self.drawNewLine(INDENTED_X, info['ADDRESS'])
|
|
self.drawNewLine(INDENTED_X, info['CITY'])
|
|
self.drawNewLine(INDENTED_X, info['GSM'])
|
|
self.newline(DOUBLE_LINE_HEIGHT)
|
|
|
|
def title(self, contract):
|
|
"""
|
|
Génère le "titre" de la facture.
|
|
"""
|
|
theString = "A l'attention de"
|
|
self.drawString(TITLED_X, "A l'attention de")
|
|
self.drawString(194, contract.client.contact, font_decoration="Bold")
|
|
self.drawString(194 + (len(contract.client.contact) * 5.2), " pour la")
|
|
self.drawNewLine(TITLED_X, contract.client.name, font_decoration="Bold")
|
|
self.drawNewLine(TITLED_X, contract.client.address)
|
|
self.drawNewLine(TITLED_X, str(contract.client.postal_code) + " " + contract.client.city)
|
|
self.newline()
|
|
self.drawNewLine(TITLED_X, "Concernant la/le")
|
|
self.drawString(200, contract.name, font_decoration="Bold")
|
|
self.newline()
|
|
|
|
def payementInformation(self, info, contract):
|
|
"""
|
|
Génère les informations de payement.
|
|
"""
|
|
self.newline()
|
|
height = 40
|
|
self.document.rect(X, self.y - height, RIGHT_X - X, height, fill=0)
|
|
self.drawNewLine(INDENTED_X, "N° Entreprise : " + info['COMPANY_NUMBER'])
|
|
self.document.drawRightString(INDENTED_RIGHT_X, self.y, "Votre N° Entreprise : " + contract.client.company_number)
|
|
self.drawNewLine(INDENTED_X, "N° de compte : " + info['BANK'] + " - " + info['ACCOUNT'])
|
|
self.newline(DOUBLE_LINE_HEIGHT)
|
|
|
|
def prestations(self, contract):
|
|
"""
|
|
Génère l'affichage des prestations : tableau, liste des prestations, …
|
|
"""
|
|
self.drawNewLine(X, "Prestations", font_decoration="Bold")
|
|
total = self.drawPrestationsTable(contract.get_prestation.all())
|
|
self.newline(DOUBLE_LINE_HEIGHT)
|
|
self.document.setFont("Helvetica", 10)
|
|
self.document.drawRightString(INDENTED_X + 445, self.y, "Acompte")
|
|
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(contract.advance))
|
|
self.newline()
|
|
self.document.setFont("Helvetica-Bold", 10)
|
|
self.document.drawRightString(INDENTED_X + 445, self.y, "Solde à payer")
|
|
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(total - contract.advance))
|
|
|
|
def drawColoredRow(self):
|
|
"""
|
|
Génère une ligne colorée.
|
|
"""
|
|
self.document.setFillColorCMYK(0.43,0.2,0,0)
|
|
self.document.rect(X, self.y - 4, RIGHT_X - X, COMMON_LINE_HEIGHT, fill=True, stroke=False)
|
|
self.document.setFillColorCMYK(0,0,0,1)
|
|
|
|
def drawHeaderPrestationsTable(self):
|
|
"""
|
|
Génère le header de la table des prestations.
|
|
"""
|
|
self.drawColoredRow()
|
|
self.newline()
|
|
|
|
self.document.setFillColorCMYK(0,0,0,1)
|
|
self.drawString(INDENTED_X, "Date")
|
|
self.drawString(PRESTATION_COLUMN_2, "Libellé")
|
|
self.drawString(INDENTED_X + 365, "Nbre")
|
|
self.drawString(INDENTED_X + 420, "Prix Unit.")
|
|
|
|
self.document.setFont("Helvetica-Bold", 10)
|
|
self.document.drawRightString(INDENTED_X + 510, self.y, "Total")
|
|
|
|
def drawFooterPrestationTable(self, total):
|
|
"""
|
|
Génère le footer de la table des prestations.
|
|
"""
|
|
self.drawColoredRow()
|
|
self.newline()
|
|
self.document.setFont("Helvetica-Bold", 10)
|
|
self.document.drawRightString(INDENTED_X + 445, self.y, "Total")
|
|
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(total))
|
|
|
|
def displayPrestation(self, prestation, total):
|
|
"""
|
|
Affiche une ligne de prestations dans le tableau.
|
|
"""
|
|
# self.newline()
|
|
total += prestation.total_amount
|
|
self.drawNewLine(INDENTED_X, str(prestation.date))
|
|
self.drawString(PRESTATION_COLUMN_2, prestation.label)
|
|
self.document.drawRightString(PRESTATION_COLUMN_3, self.y, str(prestation.unit))
|
|
# self.document.drawRightString(INDENTED_X + 400, self.y, str(prestation.unit))
|
|
self.document.drawRightString(PRESTATION_COLUMN_4, self.y, str(prestation.unit_price))
|
|
# self.document.drawRightString(INDENTED_X + 455, self.y, str(prestation.unit_price))
|
|
self.document.drawRightString(INDENTED_RIGHT_X, self.y, str(prestation.total_amount))
|
|
return total
|
|
|
|
def drawPrestationsTable(self, prestation_list):
|
|
"""
|
|
Génère le tableau des prestations.
|
|
"""
|
|
self.drawHeaderPrestationsTable()
|
|
total = 0
|
|
for prestation in prestation_list:
|
|
total = self.displayPrestation(prestation, total)
|
|
self.drawFooterPrestationTable(total)
|
|
return total
|
|
|
|
def conclusion(self, info, contract):
|
|
"""
|
|
Affiche la conclusion de la facture.
|
|
"""
|
|
self.newline(DOUBLE_LINE_HEIGHT)
|
|
self.document.rect(X, self.y, RIGHT_X - X, BIG_LINE_HEIGHT, fill=0)
|
|
self.drawNewLine(INDENTED_X, "Merci de bien vouloir payer sur le compte ")
|
|
self.drawString(INDENTED_X + 185, info['BANK'] + " : " + info['ACCOUNT'], font_decoration="Bold")
|
|
self.newline(COMMON_LINE_HEIGHT)
|
|
self.drawString(INDENTED_X, "Avec la référence :")
|
|
self.drawString(INDENTED_X + 85, "\"" + str(contract.reference) + "\"", font_decoration="Bold")
|
|
|
|
def addSignature(self):
|
|
"""
|
|
Génère la signature.
|
|
"""
|
|
self.newline(BIG_LINE_HEIGHT)
|
|
self.document.drawRightString(RIGHT_X, self.y, "Rebecq, le " + date.today().strftime('%d-%m-%Y'))
|
|
self.newline(COMMON_LINE_HEIGHT)
|
|
url = os.path.join(settings.STATICFILES_DIRS[0], 'img/signature.png')
|
|
self.newline(DOUBLE_LINE_HEIGHT)
|
|
im = self.document.drawImage(url, INDENTED_X + 340, self.y, width=180, height=39)
|
|
# im.hAlign = 'CENTER'
|
|
|
|
def download(self):
|
|
# Close the PDF object cleanly, and we're done.
|
|
self.document.showPage()
|
|
self.document.save()
|
|
|
|
|
|
def contract_export(request, contractid):
|
|
"""
|
|
Génere une fichier PDF pour fournir au client.
|
|
"""
|
|
|
|
info = loadFactureConfig(request)
|
|
contract = Contract.objects.get(pk=contractid)
|
|
|
|
# Create the HttpResponse object with the appropriate PDF headers.
|
|
response = HttpResponse(content_type='application/pdf')
|
|
response['Content-Disposition'] = 'attachment; filename="facture_' + str(contract.reference) + '.pdf"'
|
|
document = MyDocument(response)
|
|
|
|
document.header(info, contract)
|
|
document.title(contract)
|
|
document.payementInformation(info, contract)
|
|
document.prestations(contract)
|
|
document.conclusion(info, contract)
|
|
document.addSignature()
|
|
|
|
document.download()
|
|
return response
|