Initial commit — 3D Pricing app

This commit is contained in:
2026-07-06 11:37:27 +02:00
commit 1f653d8160
16 changed files with 1563 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
{% extends 'base.html' %}
{% block title %}{{ job.name }}{% endblock %}
{% block content %}
<div class="page-header d-flex justify-content-between align-items-center">
<div>
<a href="{{ url_for('jobs') }}" class="text-muted text-decoration-none small">
<i class="bi bi-arrow-left"></i> Commandes
</a>
<h1 class="mt-1">{{ job.name }}</h1>
</div>
<form method="POST" action="{{ url_for('delete_job', id=job.id) }}"
onsubmit="return confirm('Supprimer cette commande ?')">
<button class="btn btn-sm btn-outline-danger"><i class="bi bi-trash"></i> Supprimer</button>
</form>
</div>
<div class="row g-4">
<div class="col-md-5">
<div class="card mb-3">
<div class="card-header py-3">Informations</div>
<div class="card-body">
<table class="table table-sm mb-0">
<tr><th class="text-muted fw-normal" style="width:45%">Client</th><td>{{ job.client_name or '—' }}</td></tr>
<tr><th class="text-muted fw-normal">Matière</th>
<td>
{% if job.material_name %}
<span class="badge bg-secondary">{{ job.material_type }}</span> {{ job.material_name }}
{% else %}—{% endif %}
</td>
</tr>
<tr><th class="text-muted fw-normal">Fichier source</th>
<td class="text-monospace small">{{ job.source_file or '—' }}</td></tr>
<tr><th class="text-muted fw-normal">Date</th><td>{{ job.created_at[:10] }}</td></tr>
<tr><th class="text-muted fw-normal">Poids filament</th><td>{{ job.weight_g }} g</td></tr>
<tr><th class="text-muted fw-normal">Durée impression</th><td>{{ job.print_time_s | fmt_time }}</td></tr>
<tr><th class="text-muted fw-normal">Coeff design</th><td>×{{ job.design_multiplier }}</td></tr>
<tr><th class="text-muted fw-normal">Marge brute</th><td>{{ job.gross_margin_pct }} %</td></tr>
<tr><th class="text-muted fw-normal">Remise</th><td>{{ job.discount_pct }} %</td></tr>
</table>
{% if job.notes %}
<hr>
<small class="text-muted">{{ job.notes }}</small>
{% endif %}
</div>
</div>
</div>
<div class="col-md-7">
<div class="card">
<div class="card-header py-3"><i class="bi bi-receipt me-2"></i>Décomposition du prix</div>
<div class="card-body">
<div class="breakdown-row"><span class="breakdown-muted">Matière</span><span>{{ "%.4f"|format(job.material_cost) }} €</span></div>
<div class="breakdown-row"><span class="breakdown-muted">Marge matière</span><span>{{ "%.4f"|format(job.material_margin) }} €</span></div>
<div class="breakdown-row"><span class="breakdown-muted">Design (×{{ job.design_multiplier }})</span><span>{{ "%.4f"|format(job.design_cost) }} €</span></div>
<div class="breakdown-row"><span class="breakdown-muted">Manutention</span><span>{{ "%.4f"|format(job.handling_cost) }} €</span></div>
<div class="breakdown-row"><span class="breakdown-muted">Usure machine</span><span>{{ "%.4f"|format(job.wear_cost) }} €</span></div>
<div class="breakdown-row"><span class="breakdown-muted">Électricité</span><span>{{ "%.4f"|format(job.electricity_cost) }} €</span></div>
<div class="breakdown-row subtotal">
<span class="fw-semibold">Sous-total coûts</span>
<span class="fw-semibold">{{ "%.2f"|format(job.subtotal) }} €</span>
</div>
<div class="breakdown-row">
<span class="breakdown-muted">Marge brute ({{ job.gross_margin_pct }}%)</span>
<span>{{ "%.2f"|format(job.margin_amount) }} €</span>
</div>
<div class="breakdown-row">
<span class="breakdown-muted">Cotisations micro-ent.</span>
<span>{{ "%.2f"|format(job.tax_amount) }} €</span>
</div>
{% if job.discount_pct > 0 %}
<div class="breakdown-row text-danger">
<span>Remise ({{ job.discount_pct }}%)</span>
<span>{{ "%.2f"|format((job.subtotal + job.margin_amount + job.tax_amount) * job.discount_pct / 100) }} €</span>
</div>
{% endif %}
<div class="breakdown-row total">
<span>PRIX FINAL</span>
<span class="final-price">{{ "%.2f"|format(job.final_price) }} €</span>
</div>
<!-- Barre de composition -->
{% set total = job.final_price %}
{% if total > 0 %}
<div class="mt-4">
<div class="d-flex justify-content-between small text-muted mb-1">
<span>Coûts ({{ (job.subtotal/total*100)|round(1) }}%)</span>
<span>Marge ({{ (job.margin_amount/total*100)|round(1) }}%)</span>
<span>Taxes ({{ (job.tax_amount/total*100)|round(1) }}%)</span>
</div>
<div class="progress" style="height:18px;border-radius:6px">
<div class="progress-bar bg-secondary" style="width:{{ (job.subtotal/total*100)|round(1) }}%"></div>
<div class="progress-bar" style="width:{{ (job.margin_amount/total*100)|round(1) }}%;background:#ff6b35"></div>
<div class="progress-bar bg-warning text-dark" style="width:{{ (job.tax_amount/total*100)|round(1) }}%"></div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% endblock %}