feat: Meshy.ai cost integration — settings, new job form, price breakdown
Deploy via Portainer / deploy (push) Successful in 0s
Deploy via Portainer / deploy (push) Successful in 0s
This commit is contained in:
+38
-2
@@ -285,6 +285,27 @@
|
||||
<label class="form-label fw-semibold">Notes internes</label>
|
||||
<textarea name="notes" class="form-control" rows="2">{{ prefill.notes if prefill else '' }}</textarea>
|
||||
</div>
|
||||
<div class="mb-3 border rounded p-3" id="meshyBlock" style="background:#faf5ff">
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" name="meshy_enabled" id="meshy_enabled"
|
||||
value="1" onchange="onMeshyToggle()"
|
||||
{% if prefill and prefill.meshy_enabled %}checked{% endif %}>
|
||||
<label class="form-check-label fw-semibold" for="meshy_enabled" style="color:#7c3aed">
|
||||
<i class="bi bi-stars me-1"></i>Génération Meshy.ai
|
||||
</label>
|
||||
</div>
|
||||
<div id="meshyCreditsRow" class="{% if not (prefill and prefill.meshy_enabled) %}d-none{% endif %}">
|
||||
<label class="form-label small fw-semibold text-muted mb-1">Crédits utilisés</label>
|
||||
<div class="input-group input-group-sm" style="max-width:180px">
|
||||
<input type="number" name="meshy_credits_used" id="meshy_credits_used"
|
||||
class="form-control" min="0" step="1"
|
||||
value="{{ prefill.meshy_credits_used if prefill else 0 }}"
|
||||
oninput="recalc()">
|
||||
<span class="input-group-text">crédits</span>
|
||||
</div>
|
||||
<div class="form-text" id="meshyCostHint"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -574,7 +595,7 @@ document.getElementById('materialSelect').addEventListener('change', function()
|
||||
});
|
||||
|
||||
// ── Autres champs → recalc ────────────────────────────────────────────────────
|
||||
['weight_g','hours','minutes','discount_pct','pieces_per_plate','order_qty'].forEach(id => {
|
||||
['weight_g','hours','minutes','discount_pct','pieces_per_plate','order_qty','meshy_credits_used'].forEach(id => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.addEventListener('input', recalc);
|
||||
});
|
||||
@@ -604,6 +625,8 @@ function recalc() {
|
||||
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,
|
||||
meshy_enabled: document.getElementById('meshy_enabled').checked,
|
||||
meshy_credits_used: parseInt(document.getElementById('meshy_credits_used').value) || 0,
|
||||
};
|
||||
|
||||
fetch('/api/calculate', {
|
||||
@@ -612,7 +635,13 @@ function recalc() {
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(d => renderBreakdown(d, body))
|
||||
.then(d => {
|
||||
renderBreakdown(d, body);
|
||||
if (d.meshy_unit_cost) {
|
||||
document.getElementById('meshyCostHint').innerHTML =
|
||||
`<span class="text-muted">Coût unitaire : ${d.meshy_unit_cost.toFixed(4)} €/crédit</span>`;
|
||||
}
|
||||
})
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
@@ -620,6 +649,12 @@ function recalc() {
|
||||
function fmt(n) { return parseFloat(n).toFixed(4) + ' €'; }
|
||||
function fmt2(n) { return parseFloat(n).toFixed(2) + ' €'; }
|
||||
|
||||
function onMeshyToggle() {
|
||||
const checked = document.getElementById('meshy_enabled').checked;
|
||||
document.getElementById('meshyCreditsRow').classList.toggle('d-none', !checked);
|
||||
recalc();
|
||||
}
|
||||
|
||||
function renderBreakdown(d, body) {
|
||||
const dm = parseFloat(body.design_multiplier).toFixed(2);
|
||||
const mgn = parseFloat(body.gross_margin_pct).toFixed(1);
|
||||
@@ -729,6 +764,7 @@ function renderBreakdown(d, body) {
|
||||
<div class="breakdown-row section-header"><span>Partie variable</span></div>
|
||||
${row(`<span class="breakdown-muted ps-2">Manutention <small class="text-secondary">${d._handling_minutes} min × ${d._handling_rate} €/h</small></span>`, d.handling_cost, '', true)}
|
||||
${row(`<span class="breakdown-muted ps-2">Design (x${dm})</span>`, d.design_cost, '', true)}
|
||||
${body.meshy_enabled && d.meshy_cost > 0 ? row(`<span class="breakdown-muted ps-2" style="color:#7c3aed"><i class="bi bi-stars me-1"></i>Meshy.ai (${body.meshy_credits_used} crédits)</span>`, d.meshy_cost, '', true) : ''}
|
||||
${row(`<span class="breakdown-muted ps-2">Marge brute (${mgn}%)</span>`, d.margin_amount)}
|
||||
${row(`<span class="fw-semibold">Total marge <small class="text-muted fw-normal">(${d.marge_pct_on_ht}% du HT)</small></span>`, d.total_marge, 'subtotal')}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user