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 @@
-
-
Coefficient design par défaut
-
-
- ×0.80 — STL fourni
-
-
- ×1.80 — Création complète
-
-
-
-
0.80 = client qui fournit ses STL. 1.80 = vous faites tout le design.
-
Notes
@@ -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 @@
Prix global (parametres)
{% for m in materials %}
+ data-stock="{{ m.stock_g }}" data-threshold="{{ m.low_stock_threshold_g }}"
+ data-name="{{ m.name }} ({{ m.type }})">
{{ m.name }} ({{ m.type }}) — {{ m.price_per_kg }} €/kg
{% if m.stock_g <= 0 %}[RUPTURE]{% elif m.stock_g <= m.low_stock_threshold_g %}[stock bas]{% endif %}
@@ -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 = `
- 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)}
- 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)}
- 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 @@
- Marge brute
+ Marge brute
{{ profile.gross_margin_pct if profile else 27.5 }} %
+
+ 20%
+ 25%
+ 30%
+ 35%
+
-
20% 35%
+
0% 100%
Notes
@@ -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 @@
Cotisations sociales (%)
-
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.
+
@@ -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 %}