Multi-utilisateur : droits par entreprise + renommage Operation bancaire
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+48
-10
@@ -2,11 +2,34 @@ from django.contrib import admin
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import (
|
||||
Bareme, Entreprise, Client, Facture, LigneFacture, Depense, Paiement,
|
||||
Categorie,
|
||||
Bareme, Entreprise, Client, Facture, LigneFacture, Depense, Paiement, Categorie,
|
||||
)
|
||||
|
||||
|
||||
class ScopedAdmin(admin.ModelAdmin):
|
||||
"""Cloisonne les données par entreprise pour les non-superadmins."""
|
||||
scope_path = "entreprise"
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super().get_queryset(request)
|
||||
if request.user.is_superuser:
|
||||
return qs
|
||||
return qs.filter(**{f"{self.scope_path}__in": Entreprise.accessibles(request.user)})
|
||||
|
||||
def formfield_for_foreignkey(self, db_field, request, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
acc = Entreprise.accessibles(request.user)
|
||||
if db_field.name == "entreprise":
|
||||
kwargs["queryset"] = acc
|
||||
elif db_field.name == "client":
|
||||
kwargs["queryset"] = Client.objects.filter(entreprise__in=acc)
|
||||
elif db_field.name == "paiement":
|
||||
kwargs["queryset"] = Paiement.objects.filter(entreprise__in=acc)
|
||||
return super().formfield_for_foreignkey(db_field, request, **kwargs)
|
||||
|
||||
|
||||
# ----- Référentiels mutualisés (visibles par tous) -----
|
||||
|
||||
@admin.register(Categorie)
|
||||
class CategorieAdmin(admin.ModelAdmin):
|
||||
list_display = ("nom", "usage", "exclure_calculs", "actif", "ordre")
|
||||
@@ -22,16 +45,33 @@ class BaremeAdmin(admin.ModelAdmin):
|
||||
list_filter = ("annee", "activite")
|
||||
|
||||
|
||||
# ----- Entreprise (accès) -----
|
||||
|
||||
@admin.register(Entreprise)
|
||||
class EntrepriseAdmin(admin.ModelAdmin):
|
||||
list_display = ("nom", "activite", "franchise_tva", "versement_liberatoire",
|
||||
"num_tva_intracom", "vue_tva", "email")
|
||||
list_filter = ("activite", "franchise_tva", "versement_liberatoire")
|
||||
search_fields = ("nom", "siret", "num_tva_intracom")
|
||||
filter_horizontal = ("utilisateurs", "groupes")
|
||||
|
||||
def get_queryset(self, request):
|
||||
qs = super().get_queryset(request)
|
||||
if request.user.is_superuser:
|
||||
return qs
|
||||
return Entreprise.accessibles(request.user)
|
||||
|
||||
def get_readonly_fields(self, request, obj=None):
|
||||
# Seul un superadmin gère les droits d'accès.
|
||||
if not request.user.is_superuser:
|
||||
return ("utilisateurs", "groupes")
|
||||
return ()
|
||||
|
||||
|
||||
# ----- Données cloisonnées par entreprise -----
|
||||
|
||||
@admin.register(Client)
|
||||
class ClientAdmin(admin.ModelAdmin):
|
||||
class ClientAdmin(ScopedAdmin):
|
||||
list_display = ("nom", "entreprise", "email", "siret")
|
||||
list_filter = ("entreprise",)
|
||||
search_fields = ("nom", "email", "siret")
|
||||
@@ -48,10 +88,9 @@ def marquer_encaissee(modeladmin, request, queryset):
|
||||
|
||||
|
||||
@admin.register(Facture)
|
||||
class FactureAdmin(admin.ModelAdmin):
|
||||
class FactureAdmin(ScopedAdmin):
|
||||
list_display = ("numero", "entreprise", "client", "date_emission",
|
||||
"date_encaissement", "statut", "montant_ht",
|
||||
"montant_tva", "montant_ttc")
|
||||
"date_encaissement", "statut", "montant_ht", "montant_tva", "montant_ttc")
|
||||
list_filter = ("entreprise", "statut", "activite", "date_emission")
|
||||
search_fields = ("numero", "client__nom")
|
||||
date_hierarchy = "date_emission"
|
||||
@@ -72,7 +111,7 @@ class DepenseInline(admin.TabularInline):
|
||||
|
||||
|
||||
@admin.register(Paiement)
|
||||
class PaiementAdmin(admin.ModelAdmin):
|
||||
class PaiementAdmin(ScopedAdmin):
|
||||
list_display = ("date", "entreprise", "libelle", "sens", "montant_total",
|
||||
"reparti", "reste", "equilibre")
|
||||
list_filter = ("entreprise", "sens", "date")
|
||||
@@ -94,10 +133,9 @@ class PaiementAdmin(admin.ModelAdmin):
|
||||
|
||||
|
||||
@admin.register(Depense)
|
||||
class DepenseAdmin(admin.ModelAdmin):
|
||||
class DepenseAdmin(ScopedAdmin):
|
||||
list_display = ("date", "entreprise", "libelle", "categorie", "activite",
|
||||
"regime_tva", "montant_ttc", "montant_tva", "tva_autoliq",
|
||||
"paiement")
|
||||
"regime_tva", "montant_ttc", "montant_tva", "tva_autoliq", "paiement")
|
||||
list_filter = ("entreprise", "categorie", "regime_tva", "activite", "date")
|
||||
search_fields = ("libelle",)
|
||||
date_hierarchy = "date"
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 5.2.15 on 2026-06-30 06:30
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('auth', '0012_alter_user_first_name_max_length'),
|
||||
('compta', '0006_paiement_categorie_alter_depense_paiement_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='paiement',
|
||||
options={'ordering': ['-date'], 'verbose_name': 'Opération bancaire', 'verbose_name_plural': 'Opérations bancaires'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='entreprise',
|
||||
name='groupes',
|
||||
field=models.ManyToManyField(blank=True, help_text='Tous les membres de ces groupes ont accès à cette entreprise.', related_name='entreprises', to='auth.group', verbose_name='Groupes autorisés'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='entreprise',
|
||||
name='utilisateurs',
|
||||
field=models.ManyToManyField(blank=True, help_text='Utilisateurs ayant accès directement à cette entreprise.', related_name='entreprises', to=settings.AUTH_USER_MODEL, verbose_name='Utilisateurs autorisés'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='depense',
|
||||
name='paiement',
|
||||
field=models.ForeignKey(blank=True, help_text='Opération bancaire dont cette dépense fait partie.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='depenses', to='compta.paiement', verbose_name='Opération bancaire'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='entreprise',
|
||||
name='franchise_tva',
|
||||
field=models.BooleanField(default=False, help_text='Décochez si vous facturez la TVA.', verbose_name='En franchise de TVA'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='paiement',
|
||||
name='categorie',
|
||||
field=models.ForeignKey(blank=True, help_text='Surtout pour les mouvements neutres.', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='paiements', to='compta.categorie'),
|
||||
),
|
||||
]
|
||||
+33
-17
@@ -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(
|
||||
|
||||
+10
-8
@@ -12,20 +12,22 @@ MOIS = services.MOIS_FR
|
||||
|
||||
|
||||
def _entreprise(request):
|
||||
"""Entreprise courante, restreinte à celles accessibles par l'utilisateur."""
|
||||
accessibles = Entreprise.accessibles(request.user)
|
||||
eid = request.GET.get("entreprise")
|
||||
if eid:
|
||||
return get_object_or_404(Entreprise, pk=eid)
|
||||
return Entreprise.objects.first()
|
||||
return get_object_or_404(accessibles, pk=eid)
|
||||
return accessibles.first()
|
||||
|
||||
|
||||
def _annee(request):
|
||||
return int(request.GET.get("annee", date.today().year))
|
||||
|
||||
|
||||
def _base_ctx(entreprise, annee, vue):
|
||||
def _base_ctx(request, entreprise, annee, vue):
|
||||
return {
|
||||
"entreprise": entreprise,
|
||||
"entreprises": Entreprise.objects.all(),
|
||||
"entreprises": Entreprise.accessibles(request.user),
|
||||
"annee": annee,
|
||||
"annees": services.annees_disponibles(entreprise) or [annee],
|
||||
"vue": vue,
|
||||
@@ -40,7 +42,7 @@ def dashboard(request):
|
||||
return render(request, "compta/dashboard.html", {"entreprise": None})
|
||||
annee = _annee(request)
|
||||
ctx = services.synthese(entreprise, annee)
|
||||
ctx.update(_base_ctx(entreprise, annee, "global"))
|
||||
ctx.update(_base_ctx(request, entreprise, annee, "global"))
|
||||
ctx.update({
|
||||
"mois_labels": ["Jan", "Fév", "Mar", "Avr", "Mai", "Juin",
|
||||
"Juil", "Août", "Sep", "Oct", "Nov", "Déc"],
|
||||
@@ -55,7 +57,7 @@ def vue_mensuelle(request):
|
||||
if entreprise is None:
|
||||
return render(request, "compta/mensuel.html", {"entreprise": None})
|
||||
annee = _annee(request)
|
||||
ctx = _base_ctx(entreprise, annee, "mensuel")
|
||||
ctx = _base_ctx(request, entreprise, annee, "mensuel")
|
||||
ctx["rows"] = services.tableau_mensuel(entreprise, annee)
|
||||
return render(request, "compta/mensuel.html", ctx)
|
||||
|
||||
@@ -67,7 +69,7 @@ def declaration_urssaf(request):
|
||||
return render(request, "compta/decl_urssaf.html", {"entreprise": None})
|
||||
annee = _annee(request)
|
||||
mois = int(request.GET.get("mois", date.today().month))
|
||||
ctx = _base_ctx(entreprise, annee, "urssaf")
|
||||
ctx = _base_ctx(request, entreprise, annee, "urssaf")
|
||||
ctx["mois_sel"] = mois
|
||||
ctx["decl"] = services.declaration_urssaf(entreprise, annee, mois)
|
||||
return render(request, "compta/decl_urssaf.html", ctx)
|
||||
@@ -81,7 +83,7 @@ def declaration_tva(request):
|
||||
annee = _annee(request)
|
||||
mois = int(request.GET.get("mois", date.today().month))
|
||||
mode = request.GET.get("mode") or entreprise.vue_tva
|
||||
ctx = _base_ctx(entreprise, annee, "tva")
|
||||
ctx = _base_ctx(request, entreprise, annee, "tva")
|
||||
ctx["mois_sel"] = mois
|
||||
ctx["mode"] = mode
|
||||
ctx["decl"] = services.declaration_tva(entreprise, annee, mois)
|
||||
|
||||
+20
-36
@@ -1,8 +1,9 @@
|
||||
"""
|
||||
Saisie unifiée : une opération bancaire signée.
|
||||
- Montant négatif -> dépense(s) (éclatement possible).
|
||||
- Montant positif -> facture (vente) avec création de client à la volée,
|
||||
- Montant positif -> facture (vente) + création de client à la volée,
|
||||
OU mouvement neutre (ex. remboursement de TVA).
|
||||
Cloisonnée : un utilisateur ne voit que ses entreprises.
|
||||
"""
|
||||
from decimal import Decimal, InvalidOperation
|
||||
from datetime import date
|
||||
@@ -37,7 +38,7 @@ def _numero_unique(entreprise, annee):
|
||||
def _context(entreprises, post=None):
|
||||
return {
|
||||
"entreprises": entreprises,
|
||||
"clients": Client.objects.select_related("entreprise"),
|
||||
"clients": Client.objects.filter(entreprise__in=entreprises).select_related("entreprise"),
|
||||
"activites": Activite.choices,
|
||||
"regimes": RegimeTva.choices,
|
||||
"categories_depense": Categorie.objects.filter(actif=True).exclude(usage="vente"),
|
||||
@@ -49,7 +50,7 @@ def _context(entreprises, post=None):
|
||||
|
||||
@login_required
|
||||
def saisie_paiement(request):
|
||||
entreprises = Entreprise.objects.all()
|
||||
entreprises = Entreprise.accessibles(request.user)
|
||||
if request.method != "POST":
|
||||
return render(request, "compta/saisie_paiement.html", _context(entreprises))
|
||||
|
||||
@@ -61,34 +62,28 @@ def saisie_paiement(request):
|
||||
|
||||
erreurs = []
|
||||
if not entreprise:
|
||||
erreurs.append("Sélectionne une entreprise.")
|
||||
erreurs.append("Sélectionne une entreprise autorisée.")
|
||||
if not libelle:
|
||||
erreurs.append("Renseigne le libellé du paiement.")
|
||||
erreurs.append("Renseigne le libellé de l'opération.")
|
||||
if montant_total == 0:
|
||||
erreurs.append("Le montant ne peut pas être nul.")
|
||||
|
||||
if erreurs:
|
||||
for e in erreurs:
|
||||
messages.error(request, e)
|
||||
return render(request, "compta/saisie_paiement.html",
|
||||
_context(entreprises, request.POST))
|
||||
return render(request, "compta/saisie_paiement.html", _context(entreprises, request.POST))
|
||||
|
||||
cats = {str(c.pk): c for c in Categorie.objects.all()}
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# CRÉDIT (montant positif) -> facture (vente) ou mouvement neutre
|
||||
# ---------------------------------------------------------------
|
||||
# --- CRÉDIT (positif) -> facture (vente) ou mouvement neutre ---
|
||||
if montant_total > 0:
|
||||
cat = cats.get(request.POST.get("v_categorie"))
|
||||
if cat and cat.exclure_calculs:
|
||||
# Mouvement neutre (ex. remboursement de TVA) : pas de CA.
|
||||
Paiement.objects.create(
|
||||
entreprise=entreprise, date=d, libelle=libelle,
|
||||
montant_total=montant_total, sens="credit", categorie=cat)
|
||||
messages.success(request, f"Mouvement neutre « {libelle} » enregistré.")
|
||||
return redirect("saisie_paiement")
|
||||
|
||||
# Vente -> facture encaissée
|
||||
client = None
|
||||
nouveau = (request.POST.get("v_client_nouveau") or "").strip()
|
||||
if nouveau:
|
||||
@@ -98,29 +93,23 @@ def saisie_paiement(request):
|
||||
entreprise=entreprise, pk=request.POST.get("v_client")).first()
|
||||
if not client:
|
||||
messages.error(request, "Choisis un client existant ou saisis-en un nouveau.")
|
||||
return render(request, "compta/saisie_paiement.html",
|
||||
_context(entreprises, request.POST))
|
||||
return render(request, "compta/saisie_paiement.html", _context(entreprises, request.POST))
|
||||
|
||||
activite = request.POST.get("v_activite") or entreprise.activite
|
||||
taux = _dec(request.POST.get("v_taux"), "0")
|
||||
designation = (request.POST.get("v_designation") or libelle).strip()
|
||||
ttc = montant_total
|
||||
ht = (ttc / (Decimal("1") + taux / Decimal("100"))).quantize(Decimal("0.01"))
|
||||
|
||||
f = Facture.objects.create(
|
||||
entreprise=entreprise, client=client,
|
||||
numero=_numero_unique(entreprise, annee), activite=activite,
|
||||
date_emission=d, date_encaissement=d, statut="encaissee")
|
||||
LigneFacture.objects.create(
|
||||
facture=f, designation=designation, quantite=Decimal("1"),
|
||||
prix_unitaire_ht=ht, taux_tva=taux)
|
||||
entreprise=entreprise, client=client, numero=_numero_unique(entreprise, annee),
|
||||
activite=activite, date_emission=d, date_encaissement=d, statut="encaissee")
|
||||
LigneFacture.objects.create(facture=f, designation=designation, quantite=Decimal("1"),
|
||||
prix_unitaire_ht=ht, taux_tva=taux)
|
||||
f.recompute_totaux()
|
||||
messages.success(request, f"Vente « {libelle} » enregistrée (facture {f.numero}).")
|
||||
return redirect("saisie_paiement")
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# DÉBIT (montant négatif) -> dépense(s), éclatement possible
|
||||
# ---------------------------------------------------------------
|
||||
# --- DÉBIT (négatif) -> dépense(s), éclatement possible ---
|
||||
total_abs = -montant_total
|
||||
libelles = request.POST.getlist("l_libelle")
|
||||
categories = request.POST.getlist("l_categorie")
|
||||
@@ -149,24 +138,19 @@ def saisie_paiement(request):
|
||||
somme = sum((l["montant"] for l in lignes), Decimal("0"))
|
||||
if not lignes:
|
||||
messages.error(request, "Ajoute au moins une ligne de dépense.")
|
||||
return render(request, "compta/saisie_paiement.html",
|
||||
_context(entreprises, request.POST))
|
||||
return render(request, "compta/saisie_paiement.html", _context(entreprises, request.POST))
|
||||
if abs(somme - total_abs) >= Decimal("0.01"):
|
||||
messages.error(request,
|
||||
f"La somme des lignes ({somme} €) ne correspond pas au montant "
|
||||
f"({total_abs} €). Écart : {somme - total_abs} €.")
|
||||
return render(request, "compta/saisie_paiement.html",
|
||||
_context(entreprises, request.POST))
|
||||
return render(request, "compta/saisie_paiement.html", _context(entreprises, request.POST))
|
||||
|
||||
paiement = Paiement.objects.create(
|
||||
entreprise=entreprise, date=d, libelle=libelle,
|
||||
montant_total=total_abs, sens="debit")
|
||||
entreprise=entreprise, date=d, libelle=libelle, montant_total=total_abs, sens="debit")
|
||||
for l in lignes:
|
||||
Depense.objects.create(
|
||||
entreprise=entreprise, paiement=paiement, date=d,
|
||||
libelle=l["libelle"], categorie=l["categorie"],
|
||||
activite=l["activite"] or "", regime_tva=l["regime"],
|
||||
entreprise=entreprise, paiement=paiement, date=d, libelle=l["libelle"],
|
||||
categorie=l["categorie"], activite=l["activite"] or "", regime_tva=l["regime"],
|
||||
taux_tva=l["taux"], montant_ttc=l["montant"], montant_tva=l["tva"])
|
||||
messages.success(request,
|
||||
f"Paiement « {libelle} » enregistré ({len(lignes)} dépense(s)).")
|
||||
messages.success(request, f"Opération « {libelle} » enregistrée ({len(lignes)} dépense(s)).")
|
||||
return redirect("saisie_paiement")
|
||||
|
||||
Reference in New Issue
Block a user