Planning complet : multi-pièces, capacité, Gantt, iCal, horaires, imprimantes
This commit is contained in:
+61
-4
@@ -71,7 +71,7 @@
|
||||
<div id="stockInfo" class="form-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-4">
|
||||
<label class="form-label fw-semibold">Poids filament (g)</label>
|
||||
<input type="number" name="weight_g" id="weight_g" class="form-control"
|
||||
@@ -88,6 +88,20 @@
|
||||
<div class="form-text">Temps total Bambu</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-semibold">Pièces par plateau</label>
|
||||
<input type="number" name="pieces_per_plate" id="pieces_per_plate" class="form-control"
|
||||
min="1" step="1" value="1">
|
||||
<div class="form-text">Combien de pièces tiennent sur un plateau.</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<label class="form-label fw-semibold">Quantité commandée</label>
|
||||
<input type="number" name="order_qty" id="order_qty" class="form-control"
|
||||
min="1" step="1" value="1">
|
||||
<div class="form-text">Nombre total de pièces à produire.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -338,7 +352,7 @@ document.getElementById('materialSelect').addEventListener('change', function()
|
||||
});
|
||||
|
||||
// ── Autres champs → recalc ────────────────────────────────────────────────────
|
||||
['weight_g','hours','minutes','discount_pct'].forEach(id => {
|
||||
['weight_g','hours','minutes','discount_pct','pieces_per_plate','order_qty'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.addEventListener('input', recalc);
|
||||
});
|
||||
@@ -366,6 +380,8 @@ function recalc() {
|
||||
machine_profile_id: document.getElementById('machineProfileSelect').value || null,
|
||||
handling_profile_id: document.getElementById('handlingProfileSelect').value || null,
|
||||
material_profile_id: document.getElementById('materialProfileSelect').value || null,
|
||||
pieces_per_plate: parseInt(document.getElementById('pieces_per_plate').value) || 1,
|
||||
order_qty: parseInt(document.getElementById('order_qty').value) || 1,
|
||||
};
|
||||
|
||||
fetch('/api/calculate', {
|
||||
@@ -407,7 +423,47 @@ function renderBreakdown(d, body) {
|
||||
const disRow = body.discount_pct > 0
|
||||
? `<div class="breakdown-row text-danger"><span class="ps-2">Remise (${body.discount_pct}%)</span><span>-${fmt2(d.prix_ttc * body.discount_pct / 100)}</span></div>` : '';
|
||||
|
||||
document.getElementById('breakdown').innerHTML = `
|
||||
// Multi-piece header
|
||||
const qty = body.order_qty || 1;
|
||||
const ppp = body.pieces_per_plate || 1;
|
||||
const nbPlateaux = Math.ceil(qty / ppp);
|
||||
const lastPlate = qty % ppp;
|
||||
const priceOrder = d.price_order || (d.final_price * qty);
|
||||
let plateauAlert = '';
|
||||
if (lastPlate !== 0) {
|
||||
plateauAlert = `<div class="alert alert-warning py-2 mb-2 small">
|
||||
<i class="bi bi-exclamation-triangle me-1"></i>
|
||||
Dernier plateau incomplet : <strong>${lastPlate}/${ppp} pièces</strong>.
|
||||
Vous pourriez imprimer jusqu'à <strong>${nbPlateaux * ppp}</strong> pièces pour le même coût fixe.
|
||||
</div>`;
|
||||
}
|
||||
|
||||
// Prix header (1 ou 2 colonnes)
|
||||
const multiPriceHeader = qty > 1
|
||||
? `<div class="d-flex justify-content-between align-items-center mb-3">
|
||||
<div class="text-center flex-fill border-end">
|
||||
<div class="small text-muted">Prix / pièce</div>
|
||||
<div class="fw-bold fs-5" style="color:#ff6b35">${fmt2(d.final_price)}</div>
|
||||
</div>
|
||||
<div class="text-center flex-fill">
|
||||
<div class="small text-muted">Prix commande (×${qty})</div>
|
||||
<div class="fw-bold fs-5" style="color:#ff6b35">${fmt2(priceOrder)}</div>
|
||||
</div>
|
||||
</div>`
|
||||
: '';
|
||||
|
||||
// Capacité
|
||||
const cap = d.capacity || {};
|
||||
const totalMin = d.total_print_min || 0;
|
||||
const capBlock = `
|
||||
<div class="breakdown-row section-header mt-1"><span>Capacite de production</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Nb plateaux necessaires</span><span><strong>${nbPlateaux}</strong> plateau${nbPlateaux>1?'x':''}</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Duree totale (impression + cooldown)</span><span>${Math.floor(totalMin/60)}h${String(Math.round(totalMin%60)).padStart(2,'0')}min</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Pieces / jour (${cap.effective_printers||5} machines)</span><span>${cap.pieces_per_day||'—'}</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Pieces / semaine</span><span>${cap.pieces_per_week||'—'}</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Pieces / mois (30j)</span><span>${cap.pieces_per_month||'—'}</span></div>`;
|
||||
|
||||
document.getElementById('breakdown').innerHTML = plateauAlert + multiPriceHeader + `
|
||||
<div class="breakdown-row section-header"><span>Cout fixe</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Matiere <small class="text-secondary">${matName}</small></span><span>${fmt(d.material_cost)}</span></div>
|
||||
<div class="breakdown-row"><span class="breakdown-muted ps-2">Marge matiere (${d._material_margin_pct}%)</span><span>${fmt(d.material_margin)}</span></div>
|
||||
@@ -430,7 +486,8 @@ function renderBreakdown(d, body) {
|
||||
<div class="breakdown-row total" style="border-top:none"><span>Prix HT</span><span class="final-price">${fmt2(d.prix_ht_net)}</span></div>
|
||||
<div class="breakdown-row ${tvaClass}"><span class="ps-2">${tvaLabel}</span><span>${d._tva_pct > 0 ? fmt2(d.tva_amount) : ''}</span></div>
|
||||
${disRow}
|
||||
<div class="breakdown-row total"><span>PRIX FINAL TTC</span><span class="final-price">${fmt2(d.final_price)}</span></div>`;
|
||||
<div class="breakdown-row total"><span>PRIX FINAL TTC</span><span class="final-price">${fmt2(d.final_price)}</span></div>
|
||||
` + capBlock;
|
||||
}
|
||||
|
||||
// Init
|
||||
|
||||
Reference in New Issue
Block a user