238 lines
7.1 KiB
Python
238 lines
7.1 KiB
Python
from django.db import models
|
|
from django.db.models import Sum
|
|
|
|
from datetime import date
|
|
|
|
DISCOUNT_UNIT_CHOICE = [
|
|
(0, "%"),
|
|
(1, "€"),
|
|
]
|
|
|
|
|
|
class Client(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Client'
|
|
verbose_name_plural = 'Clients'
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
address = models.CharField(max_length=255, verbose_name="Adresse")
|
|
postal_code = models.IntegerField(verbose_name="Code postal")
|
|
city = models.CharField(max_length=255, verbose_name="Ville")
|
|
contact = models.CharField(max_length=255, verbose_name="Personne de contact")
|
|
email = models.EmailField(max_length=254)
|
|
phone_number = models.CharField(max_length=20, verbose_name="Téléphone")
|
|
company_number = models.CharField(
|
|
max_length=50,
|
|
verbose_name="N° d'entreprise",
|
|
blank=True,
|
|
null=True
|
|
)
|
|
|
|
def __str__(self):
|
|
return "%s" % (self.name)
|
|
|
|
|
|
class DiscountClient(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Réduction client'
|
|
verbose_name_plural = 'Réductions clients'
|
|
|
|
label = models.CharField(max_length=255, verbose_name='Libellé')
|
|
client = models.ManyToManyField(Client, verbose_name="discounts" )
|
|
quantity = models.DecimalField(
|
|
max_digits=5,
|
|
decimal_places=2,
|
|
verbose_name="Quantité",
|
|
default=1
|
|
)
|
|
unit = models.PositiveSmallIntegerField(
|
|
choices=DISCOUNT_UNIT_CHOICE, verbose_name="Unité"
|
|
)
|
|
|
|
def __str__(self):
|
|
return f"{self.label} - {self.quantity} {self.unit}"
|
|
|
|
# def amount_htva(self):
|
|
# if self.unit:
|
|
# return - self.quantity
|
|
# return (self.contract.get_contract_sum("total_amount_htva") * self.quantity / 100)
|
|
|
|
# def amount_tvac(self):
|
|
# if self.unit:
|
|
# return self.quantity * 0.21
|
|
# return (self.contract.get_contract_sum("total_amount_tvac") * self.quantity / 100)
|
|
|
|
|
|
class Estimate(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Devis'
|
|
verbose_name_plural = 'Devis'
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name="estimates")
|
|
date = models.DateField(auto_now_add=True)
|
|
details = models.TextField()
|
|
|
|
def __str__(self):
|
|
return "%s" % (self.name)
|
|
|
|
|
|
class Contract(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Contrat'
|
|
verbose_name_plural = 'Contrats'
|
|
|
|
name = models.CharField(max_length=255, verbose_name="Nom")
|
|
client = models.ForeignKey(Client, on_delete=models.CASCADE, related_name="contracts")
|
|
advance = models.DecimalField(
|
|
max_digits=6,
|
|
decimal_places=2,
|
|
blank=True,
|
|
verbose_name="Acompte",
|
|
default=0
|
|
)
|
|
reference = models.CharField(max_length=255, verbose_name="Référence", blank=True, null=True)
|
|
is_finished = models.BooleanField(default=True, blank=True)
|
|
date = models.DateField(auto_now_add=True)
|
|
invoiced_date = models.DateField(default=None, blank=True, null=True)
|
|
|
|
def __str__(self):
|
|
return "%s" % (self.name)
|
|
|
|
def get_contract_sum(self, key):
|
|
return self.get_prestation.aggregate(Sum(key))[key + '__sum']
|
|
|
|
# def __generate_reference(self):
|
|
# """
|
|
# Génère automatiquement la référence du contract
|
|
# """
|
|
# if self.id is None:
|
|
# object_id = "XX"
|
|
# elif self.id < 10:
|
|
# object_id = "0" + str(self.id)
|
|
# else:
|
|
# object_id = self.id
|
|
# self.reference = str(self.date.year) + "-" + object_id
|
|
|
|
# def save(self, *args, **kwargs):
|
|
# """
|
|
# Enregistre l'objet en DB après avoir calculé le montant total.
|
|
# """
|
|
# super().save(*args, **kwargs)
|
|
# self.__generate_reference()
|
|
# super().save(*args, **kwargs)
|
|
|
|
class PrestationType(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Type de prestations'
|
|
verbose_name_plural = 'Types de prestations'
|
|
|
|
label = models.CharField(max_length=255, verbose_name='Libellé')
|
|
|
|
def __str__(self):
|
|
return f"{self.label}"
|
|
|
|
class Prestation(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Prestations'
|
|
verbose_name_plural = 'Prestations'
|
|
ordering = ['date']
|
|
|
|
contract = models.ForeignKey(
|
|
Contract,
|
|
on_delete=models.CASCADE,
|
|
related_name="get_prestation",
|
|
blank=True,
|
|
null=True
|
|
)
|
|
prestation_type = models.ForeignKey(PrestationType, blank=True, null=True, on_delete=models.SET_NULL)
|
|
date = models.DateField()
|
|
label = models.CharField(max_length=255, verbose_name='Libellé')
|
|
unit = models.DecimalField(
|
|
max_digits=5,
|
|
decimal_places=2,
|
|
verbose_name="Unité",
|
|
default=1
|
|
)
|
|
unit_price = models.DecimalField(
|
|
max_digits=5,
|
|
decimal_places=2,
|
|
verbose_name="Prix unitaire",
|
|
default="12,5"
|
|
)
|
|
total_amount_htva = models.DecimalField(
|
|
max_digits=6,
|
|
decimal_places=2,
|
|
blank=True,
|
|
verbose_name="Prix (htva)",
|
|
default=0
|
|
)
|
|
tva_value = models.DecimalField(
|
|
max_digits=5,
|
|
decimal_places=2,
|
|
blank=True,
|
|
verbose_name="TVA",
|
|
default=21
|
|
)
|
|
total_amount_tvac = models.DecimalField(
|
|
max_digits=6,
|
|
decimal_places=2,
|
|
blank=True,
|
|
verbose_name="Prix (tvac)",
|
|
default=0
|
|
)
|
|
duration = models.PositiveIntegerField(null=True, blank=True)
|
|
time_estimated = models.PositiveIntegerField(null=True, blank=True)
|
|
time_tracked = models.PositiveIntegerField(null=True, blank=True)
|
|
|
|
def __compute_total_amount(self):
|
|
"""
|
|
Calcule le montant total de la prestation.
|
|
"""
|
|
self.total_amount_htva = self.unit * self.unit_price
|
|
self.total_amount_tvac = self.unit * self.unit_price * self.tva_value
|
|
|
|
def save(self, *args, **kwargs):
|
|
"""
|
|
Enregistre l'objet en DB après avoir calculé le montant total.
|
|
"""
|
|
self.__compute_total_amount()
|
|
super().save(*args, **kwargs)
|
|
|
|
|
|
class DiscountContract(models.Model):
|
|
class Meta:
|
|
verbose_name = 'Réduction contrat'
|
|
verbose_name_plural = 'Réductions contrat'
|
|
|
|
contract = models.ForeignKey(
|
|
Contract,
|
|
on_delete=models.CASCADE,
|
|
related_name="discounts",
|
|
blank=True,
|
|
null=True
|
|
)
|
|
label = models.CharField(max_length=255, verbose_name='Libellé')
|
|
quantity = models.DecimalField(
|
|
max_digits=5,
|
|
decimal_places=2,
|
|
verbose_name="Quantité",
|
|
default=1
|
|
)
|
|
unit = models.PositiveSmallIntegerField(
|
|
choices=DISCOUNT_UNIT_CHOICE, verbose_name="Unité"
|
|
)
|
|
|
|
def __str__(self):
|
|
return f"{self.label} ({self.contract}) - {self.quantity} {self.unit}"
|
|
|
|
def amount_htva(self):
|
|
if self.unit:
|
|
return - self.quantity
|
|
return (self.contract.get_contract_sum("total_amount_htva") * self.quantity / 100)
|
|
|
|
def amount_tvac(self):
|
|
if self.unit:
|
|
return self.quantity * 0.21
|
|
return (self.contract.get_contract_sum("total_amount_tvac") * self.quantity / 100)
|