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)