Multi-utilisateur : droits par entreprise + renommage Operation bancaire

This commit is contained in:
2026-06-30 08:33:05 +02:00
parent 80042faf0f
commit 688fa3fc97
9 changed files with 157 additions and 71 deletions
+33 -17
View File
@@ -3,8 +3,9 @@ Modèles de données — JB Compta.
"""
from decimal import Decimal
from django.conf import settings
from django.db import models
from django.db.models import Sum
from django.db.models import Sum, Q
class Activite(models.TextChoices):
@@ -27,7 +28,7 @@ class RegimeTva(models.TextChoices):
class Categorie(models.Model):
"""Catégorie globale. exclure_calculs=True => mouvement neutre (hors fiscal)."""
"""Catégorie globale (mutualisée). exclure_calculs=True => mouvement neutre."""
USAGE = [("depense", "Dépense"), ("vente", "Vente"), ("neutre", "Mouvement neutre")]
nom = models.CharField(max_length=100, unique=True)
usage = models.CharField(max_length=10, choices=USAGE, default="depense")
@@ -48,6 +49,7 @@ class Categorie(models.Model):
class Bareme(models.Model):
"""Barème mutualisé (partagé entre toutes les entreprises)."""
activite = models.CharField(max_length=20, choices=Activite.choices)
annee = models.PositiveIntegerField()
taux_urssaf = models.DecimalField("Taux cotisations URSSAF (%)", max_digits=5, decimal_places=2)
@@ -73,18 +75,24 @@ class Entreprise(models.Model):
siret = models.CharField(max_length=20, blank=True)
activite = models.CharField(
"Activité principale", max_length=20, choices=Activite.choices,
default=Activite.SERVICE_BNC,
help_text="Activité par défaut des nouvelles factures.")
default=Activite.SERVICE_BNC, help_text="Activité par défaut des nouvelles factures.")
franchise_tva = models.BooleanField(
"En franchise de TVA", default=False,
help_text="Décochez si vous facturez et déclarez la TVA.")
"En franchise de TVA", default=False, help_text="Décochez si vous facturez la TVA.")
taux_tva_defaut = models.DecimalField(
"Taux de TVA par défaut (%)", max_digits=4, decimal_places=2, default=Decimal("20.00"))
versement_liberatoire = models.BooleanField("Option versement libératoire", default=False)
num_tva_intracom = models.CharField("N° TVA intracommunautaire", max_length=20, blank=True)
vue_tva = models.CharField(
"Mode d'affichage de la déclaration TVA", max_length=10,
choices=VUE_TVA, default="simplifie")
"Mode d'affichage de la déclaration TVA", max_length=10, choices=VUE_TVA, default="simplifie")
# --- Droits d'accès (multi-utilisateur) ---
utilisateurs = models.ManyToManyField(
settings.AUTH_USER_MODEL, blank=True, related_name="entreprises",
verbose_name="Utilisateurs autorisés",
help_text="Utilisateurs ayant accès directement à cette entreprise.")
groupes = models.ManyToManyField(
"auth.Group", blank=True, related_name="entreprises",
verbose_name="Groupes autorisés",
help_text="Tous les membres de ces groupes ont accès à cette entreprise.")
email = models.EmailField(blank=True)
adresse = models.TextField(blank=True)
cree_le = models.DateTimeField(auto_now_add=True)
@@ -100,6 +108,16 @@ class Entreprise(models.Model):
def bareme(self, annee):
return Bareme.objects.filter(activite=self.activite, annee=annee).first()
@classmethod
def accessibles(cls, user):
"""Entreprises visibles par un utilisateur (toutes si superadmin)."""
if not user or not user.is_authenticated:
return cls.objects.none()
if user.is_superuser:
return cls.objects.all()
return cls.objects.filter(
Q(utilisateurs=user) | Q(groupes__in=user.groups.all())).distinct()
class Client(models.Model):
entreprise = models.ForeignKey(Entreprise, on_delete=models.CASCADE, related_name="clients")
@@ -125,8 +143,7 @@ class Facture(models.Model):
activite = models.CharField(max_length=20, choices=Activite.choices)
date_emission = models.DateField()
date_encaissement = models.DateField(
null=True, blank=True,
help_text="Le CA micro est compté à l'encaissement.")
null=True, blank=True, help_text="Le CA micro est compté à l'encaissement.")
statut = models.CharField(max_length=12, choices=StatutFacture.choices, default=StatutFacture.BROUILLON)
montant_ht = models.DecimalField(max_digits=12, decimal_places=2, default=Decimal("0"))
montant_tva = models.DecimalField(max_digits=12, decimal_places=2, default=Decimal("0"))
@@ -184,15 +201,14 @@ class Paiement(models.Model):
libelle = models.CharField("Libellé bancaire", max_length=255)
montant_total = models.DecimalField(max_digits=12, decimal_places=2)
sens = models.CharField(max_length=6, choices=SENS, default="debit")
categorie = models.ForeignKey(Categorie, on_delete=models.SET_NULL,
null=True, blank=True, related_name="paiements",
help_text="Surtout pour les mouvements neutres "
"(remboursement TVA, virement…).")
categorie = models.ForeignKey(Categorie, on_delete=models.SET_NULL, null=True, blank=True,
related_name="paiements",
help_text="Surtout pour les mouvements neutres.")
cree_le = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Paiement"
verbose_name_plural = "Paiements"
verbose_name = "Opération bancaire"
verbose_name_plural = "Opérations bancaires"
ordering = ["-date"]
def __str__(self):
@@ -215,7 +231,7 @@ class Paiement(models.Model):
class Depense(models.Model):
entreprise = models.ForeignKey(Entreprise, on_delete=models.CASCADE, related_name="depenses")
paiement = models.ForeignKey(Paiement, on_delete=models.SET_NULL, null=True, blank=True,
related_name="depenses",
related_name="depenses", verbose_name="Opération bancaire",
help_text="Opération bancaire dont cette dépense fait partie.")
date = models.DateField()
activite = models.CharField(