Arrondi URSSAF/TVA/VFL a l'euro + CFP + fix montant popup + fix categorie favori
Deploy via Portainer / deploy (push) Successful in 0s
Deploy via Portainer / deploy (push) Successful in 0s
This commit is contained in:
+1
-1
@@ -39,7 +39,7 @@ class CategorieAdmin(admin.ModelAdmin):
|
||||
@admin.register(Bareme)
|
||||
class BaremeAdmin(admin.ModelAdmin):
|
||||
list_display = ("annee", "activite", "taux_urssaf", "abattement_fiscal",
|
||||
"taux_vl", "seuil_ca", "seuil_tva_base")
|
||||
"taux_vl", "taux_cfp", "seuil_ca", "seuil_tva_base")
|
||||
list_filter = ("annee", "activite")
|
||||
|
||||
|
||||
|
||||
@@ -12,13 +12,14 @@ from django.contrib.auth.models import Group, Permission
|
||||
from compta.models import Bareme, Categorie, Activite
|
||||
from compta.categories_indy import CATALOGUE
|
||||
|
||||
# activite, taux_urssaf, abattement, taux_vl, seuil_ca, seuil_tva_base, seuil_tva_majore, taux_cfp
|
||||
BAREMES_2026 = [
|
||||
(Activite.VENTE, Decimal("12.30"), Decimal("71"), Decimal("1.0"),
|
||||
Decimal("203100"), Decimal("85000"), Decimal("93500")),
|
||||
Decimal("203100"), Decimal("85000"), Decimal("93500"), Decimal("0.10")),
|
||||
(Activite.SERVICE_BIC, Decimal("21.20"), Decimal("50"), Decimal("1.7"),
|
||||
Decimal("83600"), Decimal("37500"), Decimal("41250")),
|
||||
Decimal("83600"), Decimal("37500"), Decimal("41250"), Decimal("0.30")),
|
||||
(Activite.SERVICE_BNC, Decimal("25.60"), Decimal("34"), Decimal("2.2"),
|
||||
Decimal("83600"), Decimal("37500"), Decimal("41250")),
|
||||
Decimal("83600"), Decimal("37500"), Decimal("41250"), Decimal("0.20")),
|
||||
]
|
||||
|
||||
GROUPE_NOM = "Gestionnaire entreprise"
|
||||
@@ -46,11 +47,12 @@ def charger_groupes():
|
||||
|
||||
|
||||
def charger_reference(stdout=None, style=None):
|
||||
for act, urssaf, ab, vl, sca, tb, tm in BAREMES_2026:
|
||||
for act, urssaf, ab, vl, sca, tb, tm, cfp in BAREMES_2026:
|
||||
Bareme.objects.update_or_create(
|
||||
activite=act, annee=2026,
|
||||
defaults=dict(taux_urssaf=urssaf, abattement_fiscal=ab, taux_vl=vl,
|
||||
seuil_ca=sca, seuil_tva_base=tb, seuil_tva_majore=tm))
|
||||
seuil_ca=sca, seuil_tva_base=tb, seuil_tva_majore=tm,
|
||||
taux_cfp=cfp))
|
||||
cat = {}
|
||||
for i, (nom, usage, excl, compte) in enumerate(CATALOGUE):
|
||||
c, _ = Categorie.objects.update_or_create(
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.15 on 2026-07-15 09:28
|
||||
|
||||
from decimal import Decimal
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('compta', '0010_categorie_compte_pcg'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='bareme',
|
||||
name='taux_cfp',
|
||||
field=models.DecimalField(decimal_places=2, default=Decimal('0'), help_text='Contribution à la formation professionnelle : vente 0,1 % · artisan 0,3 % · service/libéral 0,2 %.', max_digits=4, verbose_name='Taux CFP (%)'),
|
||||
),
|
||||
]
|
||||
@@ -62,6 +62,10 @@ class Bareme(models.Model):
|
||||
taux_urssaf = models.DecimalField("Taux cotisations URSSAF (%)", max_digits=5, decimal_places=2)
|
||||
abattement_fiscal = models.DecimalField("Abattement forfaitaire (%)", max_digits=5, decimal_places=2)
|
||||
taux_vl = models.DecimalField("Taux versement libératoire (%)", max_digits=4, decimal_places=2)
|
||||
taux_cfp = models.DecimalField(
|
||||
"Taux CFP (%)", max_digits=4, decimal_places=2, default=Decimal("0"),
|
||||
help_text="Contribution à la formation professionnelle : vente 0,1 % · "
|
||||
"artisan 0,3 % · service/libéral 0,2 %.")
|
||||
seuil_ca = models.DecimalField("Plafond CA micro (€)", max_digits=12, decimal_places=2)
|
||||
seuil_tva_base = models.DecimalField("Seuil franchise TVA (€)", max_digits=12, decimal_places=2)
|
||||
seuil_tva_majore = models.DecimalField("Seuil franchise TVA majoré (€)", max_digits=12, decimal_places=2)
|
||||
|
||||
+39
-16
@@ -5,7 +5,7 @@ Bases : CA HORS TAXES (HT) encaissé.
|
||||
TVA collectée = TVA ventes + TVA auto-liquidée (UE/import).
|
||||
TVA déductible = TVA achats nationaux + TVA auto-liquidée. Neutres exclus.
|
||||
"""
|
||||
from decimal import Decimal
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
from django.db.models import Sum
|
||||
from django.db.models.functions import TruncMonth
|
||||
|
||||
@@ -21,6 +21,16 @@ def _q(v):
|
||||
return (v or Decimal("0")).quantize(CENT)
|
||||
|
||||
|
||||
def _euro(v):
|
||||
"""Arrondi à l'euro le plus proche (règle URSSAF / TVA : 0,50 → euro sup.)."""
|
||||
return (v or Decimal("0")).quantize(Decimal("1"), rounding=ROUND_HALF_UP)
|
||||
|
||||
|
||||
def _somme_euro(lignes, cle):
|
||||
vals = [l[cle] for l in lignes if l.get(cle) is not None]
|
||||
return _euro(sum(vals, Decimal("0"))) if vals else None
|
||||
|
||||
|
||||
# ---- Sélections de période ---------------------------------------------
|
||||
|
||||
def factures_encaissees(entreprise, annee, mois=None):
|
||||
@@ -120,9 +130,11 @@ def detail_activite(activite, ca, bareme):
|
||||
if bareme:
|
||||
d.update({
|
||||
"taux_urssaf": bareme.taux_urssaf,
|
||||
"cotisations": _q(ca * bareme.taux_urssaf / Decimal("100")),
|
||||
"cotisations": _euro(ca * bareme.taux_urssaf / Decimal("100")),
|
||||
"taux_vl": bareme.taux_vl,
|
||||
"versement_liberatoire": _q(ca * bareme.taux_vl / Decimal("100")),
|
||||
"versement_liberatoire": _euro(ca * bareme.taux_vl / Decimal("100")),
|
||||
"taux_cfp": bareme.taux_cfp,
|
||||
"cfp": _euro(ca * bareme.taux_cfp / Decimal("100")),
|
||||
"abattement_fiscal": bareme.abattement_fiscal,
|
||||
"revenu_imposable": _q(ca * (Decimal("100") - bareme.abattement_fiscal) / Decimal("100")),
|
||||
"seuil_ca": bareme.seuil_ca,
|
||||
@@ -133,8 +145,8 @@ def detail_activite(activite, ca, bareme):
|
||||
})
|
||||
else:
|
||||
for k in ("taux_urssaf", "cotisations", "taux_vl", "versement_liberatoire",
|
||||
"abattement_fiscal", "revenu_imposable", "seuil_ca", "pct_seuil_ca",
|
||||
"seuil_tva_base"):
|
||||
"taux_cfp", "cfp", "abattement_fiscal", "revenu_imposable",
|
||||
"seuil_ca", "pct_seuil_ca", "seuil_tva_base"):
|
||||
d[k] = None
|
||||
d["depasse_seuil_tva"] = d["depasse_seuil_ca"] = False
|
||||
return d
|
||||
@@ -165,13 +177,13 @@ def synthese(entreprise, annee):
|
||||
"entreprise": entreprise, "annee": annee, "lignes_activite": lignes,
|
||||
"bareme_manquant": any(l["bareme"] is None and l["ca_ht"] for l in lignes),
|
||||
"ca_ht": ca_ht(entreprise, annee),
|
||||
"cotisations_urssaf": _somme(lignes, "cotisations"),
|
||||
"versement_liberatoire": (_somme(lignes, "versement_liberatoire")
|
||||
"cotisations_urssaf": _somme_euro(lignes, "cotisations"),
|
||||
"versement_liberatoire": (_somme_euro(lignes, "versement_liberatoire")
|
||||
if entreprise.versement_liberatoire else None),
|
||||
"revenu_imposable": _somme(lignes, "revenu_imposable"),
|
||||
"tva_sur_ventes": tva_ventes, "tva_autoliquidee": tva_autoliq,
|
||||
"tva_collectee": tva_col, "tva_deductible": tva_ded,
|
||||
"tva_a_reverser": _q(tva_col - tva_ded),
|
||||
"tva_a_reverser": _euro(_euro(tva_col) - _euro(tva_ded)),
|
||||
"ca_mensuel": ca_ht_mensuel(entreprise, annee),
|
||||
}
|
||||
|
||||
@@ -195,10 +207,10 @@ def tableau_mensuel(entreprise, annee):
|
||||
rows.append({
|
||||
"mois": m, "nom": MOIS_FR[m - 1],
|
||||
"ca_ht": ca_ht(entreprise, annee, m),
|
||||
"cotisations": _q(cot),
|
||||
"versement_liberatoire": _q(vl) if entreprise.versement_liberatoire else None,
|
||||
"cotisations": _euro(cot),
|
||||
"versement_liberatoire": _euro(vl) if entreprise.versement_liberatoire else None,
|
||||
"tva_collectee": tva_col, "tva_deductible": tva_ded,
|
||||
"tva_a_reverser": _q(tva_col - tva_ded),
|
||||
"tva_a_reverser": _euro(_euro(tva_col) - _euro(tva_ded)),
|
||||
})
|
||||
return rows
|
||||
|
||||
@@ -207,14 +219,23 @@ def tableau_mensuel(entreprise, annee):
|
||||
|
||||
def declaration_urssaf(entreprise, annee, mois=None):
|
||||
lignes = _lignes_activite(entreprise, annee, mois)
|
||||
# URSSAF : le CA déclaré et les cotisations sont arrondis à l'euro le plus proche.
|
||||
for l in lignes:
|
||||
l["ca_ht"] = _euro(l["ca_ht"])
|
||||
return {
|
||||
"entreprise": entreprise, "annee": annee, "mois": mois,
|
||||
"mois_nom": MOIS_FR[mois - 1] if mois else "Année entière",
|
||||
"lignes": lignes,
|
||||
"ca_ht": ca_ht(entreprise, annee, mois),
|
||||
"cotisations": _somme(lignes, "cotisations"),
|
||||
"versement_liberatoire": (_somme(lignes, "versement_liberatoire")
|
||||
"ca_ht": _euro(ca_ht(entreprise, annee, mois)),
|
||||
"cotisations": _somme_euro(lignes, "cotisations"),
|
||||
"cfp": _somme_euro(lignes, "cfp"),
|
||||
"versement_liberatoire": (_somme_euro(lignes, "versement_liberatoire")
|
||||
if entreprise.versement_liberatoire else None),
|
||||
"total_regle": _euro(
|
||||
(_somme_euro(lignes, "cotisations") or Decimal("0"))
|
||||
+ (_somme_euro(lignes, "cfp") or Decimal("0"))
|
||||
+ ((_somme_euro(lignes, "versement_liberatoire") or Decimal("0"))
|
||||
if entreprise.versement_liberatoire else Decimal("0"))),
|
||||
}
|
||||
|
||||
|
||||
@@ -225,8 +246,10 @@ def declaration_tva(entreprise, annee, mois=None):
|
||||
intra_base, intra_tva = intracom_periode(entreprise, annee, mois)
|
||||
tva_ventes = sum((t for _, t in par_taux.values()), Decimal("0"))
|
||||
tva_ded = tva_deductible(entreprise, annee, mois)
|
||||
tva_brute = _q(tva_ventes + intra_tva)
|
||||
a_payer = _q(tva_brute - tva_ded)
|
||||
# CA3 : TVA collectée, déductible et à payer arrondies à l'euro le plus proche.
|
||||
tva_brute = _euro(tva_ventes + intra_tva)
|
||||
tva_ded = _euro(tva_ded)
|
||||
a_payer = tva_brute - tva_ded
|
||||
|
||||
def couple(taux):
|
||||
return par_taux.get(Decimal(taux), (Decimal("0.00"), Decimal("0.00")))
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
{% verbatim %}
|
||||
<script>
|
||||
var BM = "javascript:(async()=>{const CC=[['701','Vente de produits finis'],['707','Vente de produits finis'],['706','Prestation de services'],['605','Matériel et outillage'],['606','Matériel et outillage'],['607','Matériel et outillage'],['6256','Frais de repas hors domicile'],['6253','Frais de repas hors domicile'],['626','Télécom, fournitures, documentation'],['6181','Télécom, fournitures, documentation'],['6183','Télécom, fournitures, documentation'],['6136','Abonnement logiciel'],['6226','Abonnement logiciel'],['646','Cotisation sociale Urssaf'],['44551','TVA payée'],['44558','TVA payée'],['44583','Remboursement de TVA'],['108','Prélèvement personnel']];const CA=[['701','vente'],['707','vente'],['706','service_bic']];const cat=n=>{n=String(n||'');let b=null;for(const[p,c]of CC){if(n.startsWith(p)&&(!b||p.length>b[0].length))b=[p,c];}return b?b[1]:'';};const act=n=>{n=String(n||'');for(const[p,a]of CA){if(n.startsWith(p))return a;}return '';};const norm=tx=>{const ss=(tx.subdivisions||[]).filter(s=>{const nn=String((s.accounting_account||{}).number||'');return !nn.startsWith('512')&&!s.is_tva;});if(!ss.length)return [];const md=tx.tva_selected||(tx.vat&&tx.vat.tvaSelected)||'tva_ht';const inc=md==='tva_ttc';const gid=tx._id||'';const lib=(tx.description||tx.raw_description||'').replace(/;/g,' ');return ss.map(s=>{const num=String((s.accounting_account||{}).number||'');const amt=s.amount_in_cents||0,tv=s.tva_amount_in_cents||0;const ttc=((inc?amt:amt+tv)/100).toFixed(2);let rg='',t2=0;if(s.tva_intracom&&s.tva_intracom.type==='eu'){rg='intracom';t2=(s.tva_intracom.rate||0)/100;}else{t2=(s.tva_rate||0)/100;}return[tx.date||'',lib,cat(num),act(num),String(t2),rg,ttc,gid].join(';');});};const mk=(t,css)=>{const e=document.createElement(t);if(css)e.style.cssText=css;return e;};const askDates=()=>new Promise(res=>{const t=new Date(),y=t.getFullYear(),mo=String(t.getMonth()+1).padStart(2,'0'),ld=String(new Date(y,t.getMonth()+1,0).getDate()).padStart(2,'0');const ov=mk('div','position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:2147483647;display:flex;align-items:center;justify-content:center');const bx=mk('div','background:#fff;color:#111;padding:20px;border-radius:12px;font-family:sans-serif;min-width:280px');const h=mk('div','font-weight:700;margin-bottom:12px');h.textContent='Indy vers CSV : choisis la periode';const l1=mk('div','font-size:12px;color:#555');l1.textContent='Du';const i1=mk('input','width:100%;margin:4px 0 10px;padding:6px');i1.type='date';i1.value=y+'-'+mo+'-01';const l2=mk('div','font-size:12px;color:#555');l2.textContent='Au';const i2=mk('input','width:100%;margin:4px 0 14px;padding:6px');i2.type='date';i2.value=y+'-'+mo+'-'+ld;const row=mk('div','text-align:right');const an=mk('button','margin-right:8px;padding:6px 12px');an.textContent='Annuler';const ok=mk('button','background:#38bdf8;border:none;padding:6px 14px;border-radius:6px;cursor:pointer');ok.textContent='Recuperer';row.appendChild(an);row.appendChild(ok);[h,l1,i1,l2,i2,row].forEach(x=>bx.appendChild(x));ov.appendChild(bx);document.body.appendChild(ov);ok.onclick=()=>{const a=i1.value,b=i2.value;document.body.removeChild(ov);res([a,b]);};an.onclick=()=>{document.body.removeChild(ov);res([null,null]);};});const[d1,d2]=await askDates();if(!d1||!d2)return;const getTok=()=>new Promise(r=>{const o=indexedDB.open('firebaseLocalStorageDb');o.onsuccess=()=>{try{const q=o.result.transaction('firebaseLocalStorage','readonly').objectStore('firebaseLocalStorage').getAll();q.onsuccess=()=>{const v=(q.result||[]).map(x=>x.value).find(v=>v&&v.stsTokenManager&&v.stsTokenManager.accessToken);r(v?v.stsTokenManager.accessToken:null);};q.onerror=()=>r(null);}catch(e){r(null);}};o.onerror=()=>r(null);});const tk=await getTok();const H={'Accept':'application/json','x-client-app-type':'web'};if(tk)H['Authorization']='Bearer '+tk;let all=[],pg=1,tot=1e9;try{while(all.length<tot){const u='/api/transactions/transactions-list?'+new URLSearchParams({search:'',dateFrom:d1,dateTo:d2,page:pg});const r=await fetch(u,{headers:H,credentials:'include'});if(!r.ok)throw new Error('HTTP '+r.status);const j=await r.json();tot=j.nbTransactions!=null?j.nbTransactions:(j.transactions||[]).length;const t=j.transactions||[];if(!t.length)break;all=all.concat(t);pg++;if(pg>60)break;}}catch(e){alert('Erreur Indy : '+e.message);return;}const rows=[].concat(...all.map(norm));const NL=String.fromCharCode(10);const csv='date;libelle;categorie;activite;taux_tva;regime;montant;groupe'+NL+rows.join(NL);try{await navigator.clipboard.writeText(csv);alert(rows.length+' operations -> CSV copie ! Colle-le dans JB Compta (/import/).');}catch(e){window.prompt('Copie ce CSV (Ctrl+C) :',csv);}})();";
|
||||
var BM = "javascript:(async()=>{const CC=[['701','Vente de produits finis'],['707','Vente de produits finis'],['706','Prestation de services'],['605','Matériel et outillage'],['606','Matériel et outillage'],['607','Matériel et outillage'],['6256','Frais de repas hors domicile'],['6253','Frais de repas hors domicile'],['626','Télécom, fournitures, documentation'],['6181','Télécom, fournitures, documentation'],['6183','Télécom, fournitures, documentation'],['6136','Abonnement logiciel'],['6226','Abonnement logiciel'],['646','Cotisation sociale Urssaf'],['44551','TVA payée'],['44558','TVA payée'],['44583','Remboursement de TVA'],['108','Prélèvement personnel']];const CA=[['701','vente'],['707','vente'],['706','service_bic']];const cat=n=>{n=String(n||'');let b=null;for(const[p,c]of CC){if(n.startsWith(p)&&(!b||p.length>b[0].length))b=[p,c];}return b?b[1]:'';};const act=n=>{n=String(n||'');for(const[p,a]of CA){if(n.startsWith(p))return a;}return '';};const norm=tx=>{const ss=(tx.subdivisions||[]).filter(s=>{const nn=String((s.accounting_account||{}).number||'');return !nn.startsWith('512')&&!s.is_tva;});if(!ss.length)return [];const md=tx.tva_selected||(tx.vat&&tx.vat.tvaSelected)||'tva_ht';const inc=md==='tva_ttc';const gid=tx._id||'';const lib=(tx.description||tx.raw_description||'').replace(/;/g,' ');return ss.map(s=>{const num=String((s.accounting_account||{}).number||'');const amt=s.amount_in_cents||0,tv=s.tva_amount_in_cents||0;const ttc=((inc?amt:amt+tv)/100).toFixed(2);let rg='',t2=0;if(s.tva_intracom&&s.tva_intracom.type==='eu'){rg='intracom';t2=(s.tva_intracom.rate||0)/100;}else{t2=(s.tva_rate||0)/100;}return[tx.date||'',lib,num,act(num),String(t2),rg,ttc,gid].join(';');});};const mk=(t,css)=>{const e=document.createElement(t);if(css)e.style.cssText=css;return e;};const askDates=()=>new Promise(res=>{const t=new Date(),y=t.getFullYear(),mo=String(t.getMonth()+1).padStart(2,'0'),ld=String(new Date(y,t.getMonth()+1,0).getDate()).padStart(2,'0');const ov=mk('div','position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:2147483647;display:flex;align-items:center;justify-content:center');const bx=mk('div','background:#fff;color:#111;padding:20px;border-radius:12px;font-family:sans-serif;min-width:280px');const h=mk('div','font-weight:700;margin-bottom:12px');h.textContent='Indy vers CSV : choisis la periode';const l1=mk('div','font-size:12px;color:#555');l1.textContent='Du';const i1=mk('input','width:100%;margin:4px 0 10px;padding:6px');i1.type='date';i1.value=y+'-'+mo+'-01';const l2=mk('div','font-size:12px;color:#555');l2.textContent='Au';const i2=mk('input','width:100%;margin:4px 0 14px;padding:6px');i2.type='date';i2.value=y+'-'+mo+'-'+ld;const row=mk('div','text-align:right');const an=mk('button','margin-right:8px;padding:6px 12px');an.textContent='Annuler';const ok=mk('button','background:#38bdf8;border:none;padding:6px 14px;border-radius:6px;cursor:pointer');ok.textContent='Recuperer';row.appendChild(an);row.appendChild(ok);[h,l1,i1,l2,i2,row].forEach(x=>bx.appendChild(x));ov.appendChild(bx);document.body.appendChild(ov);ok.onclick=()=>{const a=i1.value,b=i2.value;document.body.removeChild(ov);res([a,b]);};an.onclick=()=>{document.body.removeChild(ov);res([null,null]);};});const[d1,d2]=await askDates();if(!d1||!d2)return;const getTok=()=>new Promise(r=>{const o=indexedDB.open('firebaseLocalStorageDb');o.onsuccess=()=>{try{const q=o.result.transaction('firebaseLocalStorage','readonly').objectStore('firebaseLocalStorage').getAll();q.onsuccess=()=>{const v=(q.result||[]).map(x=>x.value).find(v=>v&&v.stsTokenManager&&v.stsTokenManager.accessToken);r(v?v.stsTokenManager.accessToken:null);};q.onerror=()=>r(null);}catch(e){r(null);}};o.onerror=()=>r(null);});const tk=await getTok();const H={'Accept':'application/json','x-client-app-type':'web'};if(tk)H['Authorization']='Bearer '+tk;let all=[],pg=1,tot=1e9;try{while(all.length<tot){const u='/api/transactions/transactions-list?'+new URLSearchParams({search:'',dateFrom:d1,dateTo:d2,page:pg});const r=await fetch(u,{headers:H,credentials:'include'});if(!r.ok)throw new Error('HTTP '+r.status);const j=await r.json();tot=j.nbTransactions!=null?j.nbTransactions:(j.transactions||[]).length;const t=j.transactions||[];if(!t.length)break;all=all.concat(t);pg++;if(pg>60)break;}}catch(e){alert('Erreur Indy : '+e.message);return;}const rows=[].concat(...all.map(norm));const NL=String.fromCharCode(10);const csv='date;libelle;categorie;activite;taux_tva;regime;montant;groupe'+NL+rows.join(NL);try{await navigator.clipboard.writeText(csv);alert(rows.length+' operations -> CSV copie ! Colle-le dans JB Compta (/import/).');}catch(e){window.prompt('Copie ce CSV (Ctrl+C) :',csv);}})();";
|
||||
document.getElementById('lnk').href = BM;
|
||||
document.getElementById('ta').value = BM;
|
||||
</script>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Activité</th><th>CA HT à déclarer</th><th>Taux URSSAF</th><th>Cotisations</th>
|
||||
<th>CFP</th>
|
||||
{% if decl.versement_liberatoire is not None %}<th>Taux VL</th><th>Impôt (VL)</th>{% endif %}</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -27,6 +28,7 @@
|
||||
<td>{{ l.ca_ht }} €</td>
|
||||
<td>{% if l.taux_urssaf is not None %}{{ l.taux_urssaf }} %{% else %}—{% endif %}</td>
|
||||
<td>{% if l.cotisations is not None %}{{ l.cotisations }} €{% else %}—{% endif %}</td>
|
||||
<td>{% if l.cfp is not None %}{{ l.cfp }} €{% else %}—{% endif %}</td>
|
||||
{% if decl.versement_liberatoire is not None %}
|
||||
<td>{% if l.taux_vl is not None %}{{ l.taux_vl }} %{% else %}—{% endif %}</td>
|
||||
<td>{% if l.versement_liberatoire is not None %}{{ l.versement_liberatoire }} €{% else %}—{% endif %}</td>
|
||||
@@ -35,8 +37,13 @@
|
||||
{% endfor %}
|
||||
<tr class="total">
|
||||
<td>Total</td><td>{{ decl.ca_ht }} €</td><td></td><td>{{ decl.cotisations|default:"—" }} €</td>
|
||||
<td>{{ decl.cfp|default:"—" }} €</td>
|
||||
{% if decl.versement_liberatoire is not None %}<td></td><td>{{ decl.versement_liberatoire }} €</td>{% endif %}
|
||||
</tr>
|
||||
<tr class="total">
|
||||
<td colspan="3">Total cotisations et contributions à régler</td>
|
||||
<td colspan="{% if decl.versement_liberatoire is not None %}4{% else %}2{% endif %}">{{ decl.total_regle|default:"—" }} €</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
data-type="{{ r.type }}" data-id="{{ r.id }}"
|
||||
data-libelle="{{ r.libelle }}"
|
||||
data-date="{{ r.date|date:'Y-m-d' }}"
|
||||
data-montant="{{ r.montant|floatformat:2|unlocalize }}"
|
||||
data-montant="{{ r.montant|unlocalize }}"
|
||||
data-cat="{{ r.categorie_id }}"
|
||||
data-activite="{{ r.activite }}"
|
||||
data-regime="{{ r.regime }}"
|
||||
|
||||
@@ -99,6 +99,8 @@ def _parse_csv(text, cats):
|
||||
delim = ";" if text.count(";") >= text.count(",") else ","
|
||||
rows = list(csv.reader(io.StringIO(text), delimiter=delim))
|
||||
lignes, erreurs = [], []
|
||||
# Résolution par numéro de compte PCG (favori Indy) OU par nom (CSV manuel).
|
||||
compte_map = {c.compte_pcg: c for c in Categorie.objects.all() if c.compte_pcg}
|
||||
start = 1 if rows and rows[0] and rows[0][0].strip().lower() == "date" else 0
|
||||
for n, raw in enumerate(rows[start:], start=start + 1):
|
||||
if not any(c.strip() for c in raw):
|
||||
@@ -110,7 +112,8 @@ def _parse_csv(text, cats):
|
||||
erreurs.append(f"Ligne {n} : date invalide « {c[0]} »."); continue
|
||||
if montant == 0:
|
||||
erreurs.append(f"Ligne {n} : montant nul."); continue
|
||||
cat = cats.get((c[2] or "").strip().lower())
|
||||
val = (c[2] or "").strip()
|
||||
cat = compte_map.get(val) or cats.get(val.lower())
|
||||
grp = (c[7] or "").strip() # colonne « groupe » (ventilation), optionnelle
|
||||
lignes.append(_row(dt, (c[1] or "").strip() or "(sans libellé)", montant,
|
||||
_dec(c[4]), _regime(c[5]), cat, _activite(c[3]),
|
||||
|
||||
Reference in New Issue
Block a user