feat: MVP 3D-Druck Kostenkalkulator
- Single-Page HTML-App mit allen 18 Eingabefeldern - 12 Berechnungen live (calc.js, reine Funktionen) - LocalStorage-Persistenz, Mehrfach-Projekte via Sidebar - Excel Im-/Export ueber SheetJS (vendored, MIT) - Drag&Drop + File-Picker-Import - Apple-Swiss-Styling, responsive - Vorlagen-Excel mit 3 Reitern (Eingabe/Kalkulation/Angebot), Formeln referenzieren Eingabe - openpyxl-Script fuer reproduzierbaren Template-Build - 5 Test-Szenarien validiert Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
68
assets/calc.js
Normal file
68
assets/calc.js
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Berechnungslogik — 12 Formeln laut Spec */
|
||||
/* global window */
|
||||
|
||||
/**
|
||||
* @typedef {Object} Inputs
|
||||
* @property {number} materialCostPerKg
|
||||
* @property {number} materialUsageG
|
||||
* @property {number} printTimeH
|
||||
* @property {number} machineRate
|
||||
* @property {number} powerKwh
|
||||
* @property {number} powerPrice
|
||||
* @property {number} postMin
|
||||
* @property {number} postRate
|
||||
* @property {number} packagingCost
|
||||
* @property {number} shippingCost
|
||||
* @property {number} setupCost
|
||||
* @property {number} scrapPct
|
||||
* @property {number} marginPct
|
||||
* @property {number} quantity
|
||||
* @property {number} individualAdjustment
|
||||
* @property {number} vatPct
|
||||
*/
|
||||
|
||||
const num = (v) => {
|
||||
const n = parseFloat(v);
|
||||
return Number.isFinite(n) ? n : 0;
|
||||
};
|
||||
|
||||
const round2 = (v) => Math.round(v * 100) / 100;
|
||||
|
||||
/**
|
||||
* Alle 12 Berechnungen.
|
||||
* @param {Object} s State-Objekt
|
||||
* @returns {Object} Ergebnisse
|
||||
*/
|
||||
const calculate = (s) => {
|
||||
const materialCost = num(s.materialUsageG) * (num(s.materialCostPerKg) / 1000);
|
||||
const machineCost = num(s.printTimeH) * num(s.machineRate);
|
||||
const energyCost = num(s.printTimeH) * num(s.powerKwh) * num(s.powerPrice);
|
||||
const postCost = (num(s.postMin) / 60) * num(s.postRate);
|
||||
const totalProduction = materialCost + machineCost + energyCost + postCost
|
||||
+ num(s.setupCost) + num(s.packagingCost) + num(s.shippingCost);
|
||||
const scrapSurcharge = totalProduction * (num(s.scrapPct) / 100);
|
||||
const subtotalNet = totalProduction + scrapSurcharge;
|
||||
const margin = subtotalNet * (num(s.marginPct) / 100);
|
||||
const customerNet = subtotalNet + margin + num(s.individualAdjustment);
|
||||
const qty = Math.max(1, num(s.quantity) || 1);
|
||||
const unitNet = customerNet / qty;
|
||||
const unitGross = unitNet * (1 + num(s.vatPct) / 100);
|
||||
const totalGross = unitGross * qty;
|
||||
|
||||
return {
|
||||
materialCost: round2(materialCost),
|
||||
machineCost: round2(machineCost),
|
||||
energyCost: round2(energyCost),
|
||||
postCost: round2(postCost),
|
||||
totalProduction: round2(totalProduction),
|
||||
scrapSurcharge: round2(scrapSurcharge),
|
||||
subtotalNet: round2(subtotalNet),
|
||||
margin: round2(margin),
|
||||
customerNet: round2(customerNet),
|
||||
unitNet: round2(unitNet),
|
||||
unitGross: round2(unitGross),
|
||||
totalGross: round2(totalGross),
|
||||
};
|
||||
};
|
||||
|
||||
window.Calc = { calculate, round2, num };
|
||||
Reference in New Issue
Block a user