diff --git a/app.py b/app.py index e950414..692a781 100644 --- a/app.py +++ b/app.py @@ -98,11 +98,30 @@ def init_db(): ('handling_rate_per_hour','40.0'),('handling_minutes_per_plate','5'), ('material_margin_pct','20.0'), ('cotisations_rate_pct','12.3'), - ('vfl_rate_pct','1.7'), - ('tva_rate_pct','0.0'), + ('vfl_rate_pct','1.0'), + ('tva_rate_pct','20.0'), ('printer_power_kw','0.35'), ] conn.executemany('INSERT OR IGNORE INTO settings VALUES (?,?)', defaults) + + # Migrations : ajout de colonnes si elles n'existent pas (upgrade DB existante) + migrations = [ + 'ALTER TABLE jobs ADD COLUMN machine_profile_id INTEGER', + 'ALTER TABLE jobs ADD COLUMN handling_profile_id INTEGER', + 'ALTER TABLE jobs ADD COLUMN material_profile_id INTEGER', + 'ALTER TABLE jobs ADD COLUMN pricing_profile_id INTEGER', + 'ALTER TABLE jobs ADD COLUMN cout_fixe REAL', + 'ALTER TABLE jobs ADD COLUMN total_marge REAL', + 'ALTER TABLE jobs ADD COLUMN cotisations_amount REAL', + 'ALTER TABLE jobs ADD COLUMN vfl_amount REAL', + 'ALTER TABLE jobs ADD COLUMN tva_amount REAL', + ] + for sql in migrations: + try: + conn.execute(sql) + except Exception: + pass # colonne deja existante + conn.commit(); conn.close() def get_settings(): @@ -218,7 +237,11 @@ def calc(weight_g, print_time_s, design_mult, gross_margin_pct, discount_pct, 'material_cost': round(mat, 4), 'material_margin': round(mat_margin, 4), 'wear_cost': round(wear, 4), + 'printer_wear': round(printer_w, 4), + 'nozzle_wear': round(nozzle_w, 4), + 'plate_wear': round(plate_w, 4), 'electricity_cost': round(elec, 4), + 'kwh_used': round(s['printer_power_kw'] * (print_time_s / 3600), 4), 'cout_fixe': round(cout_fixe, 4), 'handling_cost': round(handling, 4), 'design_cost': round(design, 4), @@ -235,10 +258,14 @@ def calc(weight_g, print_time_s, design_mult, gross_margin_pct, discount_pct, # Compat 'tax_amount': round(cot_amount + vfl_amount, 4), 'final_price': round(final, 2), - # Taux appliqués (pour affichage) - '_cot_pct': round(cot_rate * 100, 2), - '_vfl_pct': round(vfl_rate * 100, 2), - '_tva_pct': round(tva_rate * 100, 2), + # Taux et paramètres appliqués (pour affichage) + '_cot_pct': round(cot_rate * 100, 2), + '_vfl_pct': round(vfl_rate * 100, 2), + '_tva_pct': round(tva_rate * 100, 2), + '_material_margin_pct': s['material_margin_pct'], + '_handling_rate': s['handling_rate_per_hour'], + '_handling_minutes': s['handling_minutes_per_plate'], + '_elec_price': s['electricity_price_kwh'], } def fmt_time(s): @@ -284,7 +311,7 @@ def new_client(): conn = get_db() conn.execute('INSERT INTO clients(name,email,design_multiplier,notes) VALUES(?,?,?,?)', (request.form['name'], request.form.get('email',''), - float(request.form['design_multiplier']), request.form.get('notes',''))) + float(request.form.get('design_multiplier', 1.80)), request.form.get('notes',''))) conn.commit(); conn.close() return redirect(url_for('clients')) return render_template('client_form.html', client=None) @@ -296,7 +323,7 @@ def edit_client(id): if request.method == 'POST': conn.execute('UPDATE clients SET name=?,email=?,design_multiplier=?,notes=? WHERE id=?', (request.form['name'], request.form.get('email',''), - float(request.form['design_multiplier']), request.form.get('notes',''), id)) + float(request.form.get('design_multiplier', client['design_multiplier'])), request.form.get('notes',''), id)) conn.commit(); conn.close() return redirect(url_for('clients')) conn.close() diff --git a/templates/client_form.html b/templates/client_form.html index e52a8f9..5be5bed 100644 --- a/templates/client_form.html +++ b/templates/client_form.html @@ -24,20 +24,6 @@ -
- -
- - -
- -
0.80 = client qui fournit ses STL. 1.80 = vous faites tout le design.
-
@@ -55,10 +41,4 @@
{% endblock %} -{% block scripts %} - -{% endblock %} +{% block scripts %}{% endblock %} diff --git a/templates/new_job.html b/templates/new_job.html index a129c54..7c905a1 100644 --- a/templates/new_job.html +++ b/templates/new_job.html @@ -61,7 +61,8 @@ {% for m in materials %} @@ -367,33 +368,48 @@ function fmt2(n) { return parseFloat(n).toFixed(2) + ' €'; } function renderBreakdown(d, body) { const dm = parseFloat(body.design_multiplier).toFixed(2); const mgn = parseFloat(body.gross_margin_pct).toFixed(1); + + // Nom du materiau selectionne + const matSel = document.getElementById('materialSelect'); + const matOpt = matSel.options[matSel.selectedIndex]; + const matName = matOpt.value ? (matOpt.dataset.name || matOpt.text.split('—')[0].trim()) : 'global'; + + // Remise const dis = body.discount_pct > 0 - ? `
Remise (${body.discount_pct}%)-${fmt2(d.final_price / (1 - body.discount_pct/100) * (body.discount_pct/100))}
` : ''; - const tvaRow = d._tva_pct > 0 - ? `
TVA (${d._tva_pct}%)${fmt2(d.tva_amount)}
` : ''; + ? `
Remise (${body.discount_pct}%)-${fmt2(d.prix_ttc * body.discount_pct / 100)}
` : ''; + + // TVA — toujours affichee + const tvaLabel = d._tva_pct > 0 + ? `TVA ${d._tva_pct}% — ${fmt2(d.tva_amount)}` + : `TVA — franchise en base`; + const tvaClass = d._tva_pct > 0 ? '' : 'text-muted fst-italic'; + + // VFL const vflRow = d._vfl_pct > 0 - ? `
VFL impot (${d._vfl_pct}%)${fmt2(d.vfl_amount)}
` : ''; + ? `
VFL impot (${d._vfl_pct}%)${fmt2(d.vfl_amount)}
` : ''; document.getElementById('breakdown').innerHTML = `
Cout fixe
-
Matiere${fmt(d.material_cost)}
-
Marge matiere${fmt(d.material_margin)}
-
Usure machine${fmt(d.wear_cost)}
-
Electricite${fmt(d.electricity_cost)}
+
Matiere ${matName}${fmt(d.material_cost)}
+
Marge matiere (${d._material_margin_pct}%)${fmt(d.material_margin)}
+
Usure — imprimante${fmt(d.printer_wear)}
+
Usure — buse${fmt(d.nozzle_wear)}
+
Usure — plateau${fmt(d.plate_wear)}
+
Electricite ${parseFloat(d.kwh_used).toFixed(3)} kWh × ${d._elec_price} €${fmt(d.electricity_cost)}
Total cout fixe${fmt2(d.cout_fixe)}
Partie variable
-
Manutention${fmt(d.handling_cost)}
+
Manutention ${d._handling_minutes} min × ${d._handling_rate} €/h${fmt(d.handling_cost)}
Design (x${dm})${fmt(d.design_cost)}
Marge brute (${mgn}%)${fmt2(d.margin_amount)}
Total marge${fmt2(d.total_marge)}
Fiscal
-
Cotisations (${d._cot_pct}%)${fmt2(d.cotisations_amount)}
+
Cotisations BIC vente (${d._cot_pct}%)${fmt2(d.cotisations_amount)}
${vflRow} - ${tvaRow} +
${tvaLabel}
${dis} -
PRIX FINAL${fmt2(d.final_price)}
`; +
PRIX FINAL TTC${fmt2(d.final_price)}
`; } // Init diff --git a/templates/pricing_profile_form.html b/templates/pricing_profile_form.html index 9a5f741..6700e18 100644 --- a/templates/pricing_profile_form.html +++ b/templates/pricing_profile_form.html @@ -35,14 +35,20 @@
+
+ + + + +
-
20%35%
+
0%100%
@@ -66,8 +72,26 @@ function setDM(val) { document.getElementById('design_multiplier').value = val; } -document.getElementById('gross_margin_pct').addEventListener('input', function() { - document.getElementById('marginDisplay').textContent = this.value + ' %'; -}); + +function setMargin(val) { + document.getElementById('gross_margin_pct').value = val; + updateMarginDisplay(val); +} + +function updateMarginDisplay(val) { + val = parseFloat(val); + document.getElementById('marginDisplay').textContent = val.toFixed(1) + ' %'; + [20, 25, 30, 35].forEach(function(v) { + const btn = document.querySelector('#marginButtons button[onclick="setMargin(' + v + ')"]'); + if (btn) btn.className = 'btn btn-sm ' + (Math.abs(val - v) < 0.01 ? 'btn-secondary' : 'btn-outline-secondary'); + }); +} + +const slider = document.getElementById('gross_margin_pct'); +slider.addEventListener('input', function() { updateMarginDisplay(this.value); }); +slider.addEventListener('change', function() { updateMarginDisplay(this.value); }); + +// Init +updateMarginDisplay(slider.value); {% endblock %} diff --git a/templates/settings.html b/templates/settings.html index 6883370..e828fc6 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -116,15 +116,18 @@ -
12.3% pour prestation de services (2024). Calculees sur le CA HT.
+
+ 12.3% — micro-entrepreneur BIC vente (fabrication/vente de marchandises, 2024). + Calculees sur le CA HT. +
- 1.7% pour prestation de services (option VFL). Mettre 0 si vous n'etes pas au VFL - (impot calcule separement sur declaration classique). + 1% — BIC vente (si option VFL activee). + Mettre 0 si vous n'avez pas opte pour le VFL (impot sur declaration classique).

@@ -133,18 +136,17 @@
- 0 si vous etes en franchise en base de TVA (CA < seuil). - 20 si vous avez depasse le seuil et devez facturer la TVA. - La TVA est affichee separement et s'ajoute au prix HT. + 20% — taux normal applicable a la vente de biens imprimes 3D. + La TVA s'ajoute au prix HT et est collectee pour l'Etat (non conservee).
{% set total_charges = settings.cotisations_rate_pct + settings.vfl_rate_pct %}
- Charges totales sur CA : {{ total_charges }} % + Charges sur CA HT : {{ total_charges }} % (cotisations {{ settings.cotisations_rate_pct }}% + VFL {{ settings.vfl_rate_pct }}%) {% if settings.tva_rate_pct > 0 %} - + TVA {{ settings.tva_rate_pct }}% ajoutee au prix HT + — TVA {{ settings.tva_rate_pct }}% collectee et reversee a l'Etat {% else %} — franchise TVA active {% endif %}