Quick Tools

Welcome to my online toolkit, where you’ll find a selection of finance, intralogistics and supply chain tools.

Finance

Break-Even, Payback, ROI → quick first impressionIRR & NPV → core financial decision tools (both use discounting)WACC & Fisher Rate → inputs used by NPV/IRRLoan Amortisation & Leverage → financing choices that impact WACC and ROIRisk Tools (Scenario, Sensitivity) → test how robust the NPV/IRR results areProgram Selector → uses NPV results to pick the optimal project combinationBaldwin Rate → alternative to IRR, especially for comparing projects with different lifetimesCompound Interest → long-term wealth view, unrelated to project appraisal but useful for personal finance

Intralogistics

Conveyor Throughput → quick estimate of conveyor line capacity based on speed and product pitchAS/RS Cycle Time → estimates stacker-crane cycles/hour to size storage aislesShuttle System Throughput → calculates tote-per-hour output for shuttle levels and liftsPallet Conveyor Accumulation → checks how many pallets fit on a conveyor bufferBottleneck Flow Calculator → identifies which conveyor segment limits total throughputPick Station Throughput → calculates realistic picks/hour based on operator touch timesContainer Tipping Point Calculator → determines the maximum safe tilt angle before a container flips based on footprint and centre of gravityIncline Conveyor Calculator → estimates walking distance and time per order in manual zonesStorage Capacity (Bins/Slots) → computes the missing value (belt length, height, or incline angle) for designing incline conveyors

Supply Chain

Safety Stock & ROP → calculates service-level-based safety stock and reorder pointEOQ & Inventory Cost → finds optimal order size balancing ordering vs. holding costLanded Cost → full import cost per unit including freight, duties and local chargesPallet / Container Optimizer → estimates how many cartons fit per layer and per stackABC/XYZ Classification → classifies items by value (ABC) and demand variability (XYZ)Transport Mode & Cost Optimizer → compares cost vs. transit time across truck/rail/sea/air


Disclaimer

Finance Tools

Basic

Break-Even Calculator

Enter your total fixed costs (e.g. rent, salaries, overhead).

Cost per unit that scales with volume (materials, direct labour, etc.).

Selling price per unit.

Break-even units = Fixed costs / (Price − Variable cost per unit)
(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("be_btn"); if (btn) { btn.addEventListener("click", function () { const fixed = num("be_fixed"); const vc = num("be_vc"); const price = num("be_price"); const res = document.getElementById("be_result"); if (fixed === null || vc === null || price === null) { res.textContent = "Please enter fixed costs, variable cost per unit and price per unit."; return; } if (price <= vc) { res.textContent = "Price per unit must be greater than variable cost per unit."; return; } const margin = price - vc; const unitsExact = fixed / margin; const units = Math.ceil(unitsExact); const revenue = units * price; res.innerHTML = "Contribution margin per unit: " + margin.toFixed(2) + "
Break-even units (exact): " + unitsExact.toFixed(2) + "
Break-even units (rounded up): " + units + "
Break-even revenue: " + revenue.toFixed(2); }); } })();

Basic

Payback Period Calculator

Upfront investment amount (use a positive number).

Expected constant annual net cash inflow.

Payback period = Initial investment / Annual cash flow.
(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("pb_btn"); if (btn) { btn.addEventListener("click", function () { const I0 = num("pb_invest"); const cf = num("pb_cf"); const res = document.getElementById("pb_result"); if (I0 === null || cf === null) { res.textContent = "Please enter initial investment and annual cash flow."; return; } if (cf <= 0) { res.textContent = "Annual cash flow must be greater than 0."; return; } const yearsExact = I0 / cf; const fullYears = Math.floor(yearsExact); const fractional = yearsExact - fullYears; const months = Math.round(fractional * 12); res.innerHTML = "Payback period (exact): " + yearsExact.toFixed(2) + " years" + "
Approx.: " + fullYears + " years and " + months + " months"; }); } })();

Basic

ROI Calculator

Upfront investment amount (capital you put in).

Final value or amount received (including payback of principal).

ROI = (Final value − Initial investment) / Initial investment.
(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("roi_btn"); if (btn) { btn.addEventListener("click", function () { const I0 = num("roi_initial"); const F = num("roi_final"); const res = document.getElementById("roi_result"); if (I0 === null || F === null) { res.textContent = "Please enter initial investment and final value."; return; } if (I0 === 0) { res.textContent = "Initial investment must not be 0."; return; } const profit = F - I0; const roi = profit / I0 * 100; res.innerHTML = "Profit: " + profit.toFixed(2) + "
ROI: " + roi.toFixed(2) + " %"; }); } })();

Basic

IRR Calculator

Enter an initial investment at t=0 and up to five annual cash flows. The initial investment will be treated as an outflow (negative).

IRR is the discount rate r such that NPV(r) = 0. Simple bisection search between -90% and +100%.
(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } function npv(rate, cfs) { let npv = 0; for (let t = 0; t < cfs.length; t++) { npv += cfs[t] / Math.pow(1 + rate, t); } return npv; } const btn = document.getElementById("irr_btn"); if (btn) { btn.addEventListener("click", function () { const res = document.getElementById("irr_result"); let c0 = num("irr_c0"); if (c0 === null) { res.textContent = "Please enter initial investment (t=0)."; return; } // treat as outflow if (c0 > 0) c0 = -Math.abs(c0); const c1 = num("irr_c1"); const c2 = num("irr_c2"); const c3 = num("irr_c3"); const c4 = num("irr_c4"); const c5 = num("irr_c5"); const cfs = [c0]; [c1, c2, c3, c4, c5].forEach(v => { if (v !== null) cfs.push(v); }); const allSameSign = cfs.every(v => v >= 0) || cfs.every(v => v <= 0); if (allSameSign) { res.textContent = "IRR cannot be computed: cash flows do not change sign."; return; } let low = -0.9; // -90% let high = 1.0; // +100% let fLow = npv(low, cfs); let fHigh = npv(high, cfs); if (fLow * fHigh > 0) { res.textContent = "Could not bracket IRR between -90% and +100%. Try adjusting inputs."; return; } for (let i = 0; i < 60; i++) { const mid = (low + high) / 2; const fMid = npv(mid, cfs); if (Math.abs(fMid) < 1e-6) { low = high = mid; break; } if (fLow * fMid <= 0) { high = mid; fHigh = fMid; } else { low = mid; fLow = fMid; } } const irr = ((low + high) / 2) * 100; res.innerHTML = "Estimated IRR: " + irr.toFixed(2) + " %"; }); } })();

Basic

NPV Calculator

Enter the discount rate used to discount future cash flows.

How much you invest today (enter as a positive number).

Expected annual net cash inflow generated by the investment.

Number of years until the investment begins generating cash flows.

Total economic lifetime of the investment (in years).

This calculator supports NPV, equivalent annual value, useful-life decisions, and timing of commissioning.
(function () { function getNumNPV(id) { var el = document.getElementById(id); if (!el) return null; var v = el.value.replace(",", ".").trim(); if (!v) return null; var num = parseFloat(v); return isNaN(num) ? null : num; } var btn = document.getElementById("npv_btn"); if (btn) { btn.addEventListener("click", function () { var r = getNumNPV("npv_rate"); var I0 = getNumNPV("npv_I0"); var cf = getNumNPV("npv_cf"); var start = getNumNPV("npv_start"); var years = getNumNPV("npv_years"); var res = document.getElementById("npv_result"); if (r === null || I0 === null || cf === null || years === null) { res.textContent = "Please enter discount rate, initial investment, annual cash flow and life."; return; } var rDec = r / 100; var startInt = Math.max(0, Math.round(start || 0)); var yearsInt = Math.max(1, Math.round(years)); var npv = -I0; for (var t = 0; t < yearsInt; t++) { var n = startInt + t + 1; npv += cf / Math.pow(1 + rDec, n); } var annuity; if (rDec === 0) { annuity = npv / yearsInt; } else { annuity = npv * (rDec * Math.pow(1 + rDec, yearsInt)) / (Math.pow(1 + rDec, yearsInt) - 1); } res.innerHTML = "Net Present Value (NPV): " + npv.toFixed(2) + "
Equivalent Annual Value: " + annuity.toFixed(2) + " / year"; }); } })();

Intermediate

Compound Interest Calculator

Estimate how your investment grows with compound interest and regular contributions.

Uses monthly compounding. Regular contributions are assumed monthly at the end of each period.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",",".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("ci_btn"); if(btn){ btn.addEventListener("click", function(){ const res = document.getElementById("ci_result"); const P = num("ci_principal"); // initial principal const r = num("ci_rate"); // annual rate in % const Y = num("ci_years"); // years let C = num("ci_contrib"); // monthly contribution (optional) if(P === null || r === null || Y === null){ res.textContent = "Please enter principal, interest rate and horizon in years."; return; } if(P < 0 || r < 0 || Y <= 0){ res.textContent = "Use non-negative principal and rate, and a positive horizon."; return; } if(C === null || C < 0){ C = 0; } const periodsPerYear = 12; const i = (r/100) / periodsPerYear; // rate per month const N = Math.round(Y * periodsPerYear); // total months // Future value of principal const fvPrincipal = i === 0 ? P : P * Math.pow(1 + i, N); // Future value of contributions (annuity) let fvContrib = 0; if(C > 0){ if(i === 0){ fvContrib = C * N; } else { fvContrib = C * (Math.pow(1 + i, N) - 1) / i; } } const finalValue = fvPrincipal + fvContrib; const totalContrib = P + C * N; const interestEarned = finalValue - totalContrib; function fmt(x){ return finalValue >= 1000 ? x.toFixed(0) : x.toFixed(2); } res.innerHTML = "Final portfolio value: " + fmt(finalValue) + "
Total contributions: " + fmt(totalContrib) + "
Interest earned: " + fmt(interestEarned) + "

Assumptions: monthly compounding at " + r.toFixed(2) + " % p.a. over " + Y.toFixed(1) + " years."; }); } })();

Intermediate

Loan Amortisation Calculator

Total loan amount (principal borrowed).

Annual interest rate on the loan.

Loan term in years (used if no monthly principal is entered).

Optional: fixed monthly principal repayment amount.

(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } function fmt(x){ return x.toFixed(2); } const btn = document.getElementById("loan_btn"); if (btn) { btn.addEventListener("click", function () { const amount = num("loan_amount"); const rate = num("loan_rate"); const years = num("loan_years"); let monthlyPrincipal = num("loan_principal"); const res = document.getElementById("loan_result"); if (amount === null || rate === null) { res.textContent = "Please enter loan amount and interest rate."; return; } if (amount <= 0) { res.textContent = "Loan amount must be greater than 0."; return; } let usePrincipalMode = false; if (monthlyPrincipal !== null) { if (monthlyPrincipal <= 0) { res.textContent = "Monthly principal repayment must be greater than 0 if provided."; return; } usePrincipalMode = true; } if (!usePrincipalMode && (years === null || years <= 0)) { res.textContent = "Please enter a positive term in years (or provide a monthly principal repayment)."; return; } const rMonth = rate / 100 / 12; // monthly interest rate let html = ""; let totalInterest = 0; let totalPayment = 0; let summaryText = ""; let monthlyPaymentDisplay = 0; let months = 0; // ---- Mode 1: Fixed monthly principal repayment ---- if (usePrincipalMode) { let balance = amount; if (rMonth > 0) { const firstInterest = balance * rMonth; if (monthlyPrincipal <= firstInterest) { res.textContent = "Monthly principal repayment is too low – it does not even cover the first month's interest (" + fmt(firstInterest) + "). Please increase the principal repayment or adjust the interest rate."; return; } } const maxMonths = 1200; // safety cap (~100 years) while (balance > 0.01 && months < maxMonths) { months++; const interest = rMonth > 0 ? balance * rMonth : 0; let principal = Math.min(monthlyPrincipal, balance); const payment = interest + principal; balance -= principal; totalInterest += interest; totalPayment += payment; if (months === 1) { monthlyPaymentDisplay = payment; // first month's payment as reference } html += "" + "" + "" + "" + ""; } if (months === 0 || months === 1200) { res.textContent = "The given monthly principal repayment is too low to repay this loan in a reasonable time."; return; } const yearsEff = months / 12; const totalRepaid = totalPayment; const interestShare = (totalInterest / totalRepaid) * 100; summaryText = "Mode: fixed monthly principal repayment." + "
Monthly principal repayment: " + fmt(monthlyPrincipal) + "
Approximate first monthly payment (principal + interest): " + fmt(monthlyPaymentDisplay) + "
Effective term: " + months + " months (≈ " + yearsEff.toFixed(1) + " years)" + "
Total amount repaid (principal + interest): " + fmt(totalRepaid) + "
Total interest paid: " + fmt(totalInterest) + " (" + interestShare.toFixed(1) + " % of total repayment)"; // ---- Mode 2: Classic annuity loan with fixed term ---- } else { const n = Math.round(years * 12); // total payments const balance0 = amount; let monthlyPayment; if (rMonth === 0) { monthlyPayment = amount / n; } else { const factor = Math.pow(1 + rMonth, n); monthlyPayment = amount * rMonth * factor / (factor - 1); } let balance = balance0; months = n; for (let k = 1; k <= n; k++) { const interest = balance * rMonth; let principal = monthlyPayment - interest; let paymentThis = monthlyPayment; if (k === n) { principal = balance; paymentThis = principal + interest; } balance -= principal; totalInterest += interest; totalPayment += paymentThis; html += "" + "" + "" + "" + ""; } const totalRepaid = totalPayment; const interestShare = (totalInterest / totalRepaid) * 100; monthlyPaymentDisplay = monthlyPayment; summaryText = "Mode: annuity loan with fixed term." + "
Monthly payment (annuity): " + fmt(monthlyPaymentDisplay) + "
Term: " + months + " months (≈ " + years.toFixed(1) + " years)" + "
Total amount repaid (principal + interest): " + fmt(totalRepaid) + "
Total interest paid: " + fmt(totalInterest) + " (" + interestShare.toFixed(1) + " % of total repayment)"; } html += "
#PaymentInterestPrincipalBalance
" + months + "" + fmt(payment) + "" + fmt(interest) + "" + fmt(principal) + "" + fmt(Math.max(0, balance)) + "
" + k + "" + fmt(paymentThis) + "" + fmt(interest) + "" + fmt(principal) + "" + fmt(Math.max(0, balance)) + "
"; res.innerHTML = summaryText + "

Amortisation schedule:" + html; }); } })();

Intermediate

Leverage Effect

Enter the total return generated by the company’s assets.

Interest rate applied to the company's debt capital.

Amount of equity invested by shareholders.

Total amount of borrowed capital.

Formula: rE = rG + (rG − i) · D/E
(function () { function getNumLev(id) { var el = document.getElementById(id); if (!el) return null; var v = el.value.replace(",", ".").trim(); if (!v) return null; var num = parseFloat(v); return isNaN(num) ? null : num; } var btn = document.getElementById("lev_btn"); if (btn) { btn.addEventListener("click", function () { var rG = getNumLev("lev_rg"); var i = getNumLev("lev_i"); var EK = getNumLev("lev_EK"); var FK = getNumLev("lev_FK"); var res = document.getElementById("lev_result"); if (rG === null || i === null || EK === null || FK === null) { res.textContent = "Please enter r_G, i, equity and debt."; return; } if (EK <= 0) { res.textContent = "Equity capital must be greater than 0."; return; } var rGDec = rG / 100; var iDec = i / 100; var DbyE = FK / EK; var rEDec = rGDec + (rGDec - iDec) * DbyE; res.innerHTML = "Debt-to-equity ratio D/E: " + DbyE.toFixed(2) + "
Return on equity r_E: " + (rEDec * 100).toFixed(2) + " %"; }); } })();

Expert

Fisher Rate Interest Rate

Enter the nominal interest rate before adjusting for inflation.

Enter the inflation rate used to convert nominal to real interest.

Formula: ireal = (1 + inom) / (1 + π) − 1
(function () { function getNumFisher(id) { var el = document.getElementById(id); if (!el) return null; var v = el.value.replace(",", ".").trim(); if (!v) return null; var num = parseFloat(v); return isNaN(num) ? null : num; } var btn = document.getElementById("fisher_btn"); if (btn) { btn.addEventListener("click", function () { var iNom = getNumFisher("fisher_nominal"); var pi = getNumFisher("fisher_inflation"); var res = document.getElementById("fisher_result"); if (iNom === null || pi === null) { res.textContent = "Please enter both nominal interest and inflation rate."; return; } var iNomDec = iNom / 100; var piDec = pi / 100; var iReal = (1 + iNomDec) / (1 + piDec) - 1; res.innerHTML = "Real interest rate i_real: " + (iReal * 100).toFixed(2) + " % p.a."; }); } })();

Expert

Interest Rate Sensitivity of NPV

Define the lower bound for the discount rate range.

Define the upper bound for the discount rate range.

Choose how much the rate increases between rows in the table.

Enter the initial investment amount (today, as a positive number).

Expected constant annual net cash inflow.

Number of years until the investment starts generating cash flows.

Total economic lifetime of the investment (in years).

(function () { function getNumSens(id) { var el = document.getElementById(id); if (!el) return null; var v = el.value.replace(",", ".").trim(); if (!v) return null; var num = parseFloat(v); return isNaN(num) ? null : num; } var btn = document.getElementById("sens_btn"); if (btn) { btn.addEventListener("click", function () { var rMin = getNumSens("sens_rmin"); var rMax = getNumSens("sens_rmax"); var step = getNumSens("sens_step"); var I0 = getNumSens("sens_I0"); var cf = getNumSens("sens_cf"); var start = getNumSens("sens_start"); var years = getNumSens("sens_years"); var res = document.getElementById("sens_result"); if ( rMin === null || rMax === null || step === null || I0 === null || cf === null || years === null ) { res.textContent = "Please enter all parameters (rates, step, I0, CF, start, life)."; return; } if (step <= 0 || rMax < rMin) { res.textContent = "Check the rate range and step size."; return; } var startInt = Math.max(0, Math.round(start || 0)); var yearsInt = Math.max(1, Math.round(years)); var maxRows = 50; var numRows = Math.floor((rMax - rMin) / step) + 1; if (numRows > maxRows) { step = (rMax - rMin) / (maxRows - 1); } var html = ''; for (var r = rMin, count = 0; r <= rMax + 1e-9 && count < maxRows; r += step, count++) { var rDec = r / 100; var npv = -I0; for (var t = 0; t < yearsInt; t++) { var n = startInt + t + 1; npv += cf / Math.pow(1 + rDec, n); } html += ""; } html += "
r [%]NPV
" + r.toFixed(2) + "" + npv.toFixed(2) + "
"; res.innerHTML = html; }); } })();

Expert

Investment Risk

Enter up to three scenarios with their NPVs and probabilities to calculate expected NPV and risk metrics.

Best-case scenario with highest expected return.

Scenario 1

Most realistic or average expected outcome.

Scenario 2

Worst-case scenario for downside risk assessment.

Scenario 3
Outputs include expected NPV, standard deviation, and coefficient of variation.
(function () { function getNumRisk(id) { var el = document.getElementById(id); if (!el) return null; var v = el.value.replace(",", ".").trim(); if (!v) return null; var num = parseFloat(v); return isNaN(num) ? null : num; } var btn = document.getElementById("risk_btn"); if (btn) { btn.addEventListener("click", function () { var res = document.getElementById("risk_result"); var npvs = []; var probs = []; var totalP = 0; for (var i = 1; i <= 3; i++) { var n = getNumRisk("risk_npv" + i); var p = getNumRisk("risk_p" + i); if (n !== null && p !== null && p > 0) { npvs.push(n); var w = p / 100; probs.push(w); totalP += w; } } if (npvs.length === 0 || totalP <= 0) { res.textContent = "Please enter at least one scenario with NPV and probability."; return; } var weights = probs.map(function (p) { return p / totalP; }); var E = 0; for (var j = 0; j < npvs.length; j++) { E += weights[j] * npvs[j]; } var variance = 0; for (var k = 0; k < npvs.length; k++) { var diff = npvs[k] - E; variance += weights[k] * diff * diff; } var sigma = Math.sqrt(variance); var cv = E !== 0 ? sigma / Math.abs(E) : null; res.innerHTML = "Expected NPV: " + E.toFixed(2) + "
Standard Deviation (σ): " + sigma.toFixed(2) + (cv !== null ? "
Coefficient of Variation: " + cv.toFixed(3) : "
Coefficient of Variation not defined (E = 0)"); }); } })();

Expert

Investment Programme Selector

Enter your total investment budget and up to four projects. The tool will select the combination with the highest total NPV that stays within the budget.

Maximum amount you are allowed to invest across all projects.

First project you are considering.

Project 1

Second project you are considering.

Project 2

Third project you are considering.

Project 3

Fourth project you are considering.

Project 4
Uses a simple brute-force search over all project combinations (2⁴).
(function () { function getNumProg(id) { var el = document.getElementById(id); if (!el) return null; var v = el.value.replace(",", ".").trim(); if (!v) return null; var num = parseFloat(v); return isNaN(num) ? null : num; } var btn = document.getElementById("prog_btn"); if (btn) { btn.addEventListener("click", function () { var budget = getNumProg("prog_budget"); var res = document.getElementById("prog_result"); if (budget === null || budget <= 0) { res.textContent = "Please enter a budget greater than 0."; return; } var costs = []; var npvs = []; // Only 4 projects for (var i = 1; i <= 4; i++) { var c = getNumProg("prog_cost" + i); var n = getNumProg("prog_npv" + i); costs.push(c || 0); npvs.push(n || 0); } var bestNPV = -Infinity; var bestCost = 0; var bestMask = 0; var nProj = 4; // Check all non-empty combinations of 4 projects (1..2^4-1) for (var mask = 1; mask < (1 << nProj); mask++) { var totalCost = 0; var totalNPV = 0; for (var j = 0; j < nProj; j++) { if (mask & (1 << j)) { totalCost += costs[j]; totalNPV += npvs[j]; } } if (totalCost <= budget && totalNPV > bestNPV) { bestNPV = totalNPV; bestCost = totalCost; bestMask = mask; } } if (bestMask === 0 || bestNPV <= 0) { res.textContent = "Within this budget, there is no combination with a positive NPV that beats doing nothing."; return; } var chosen = []; for (var k = 0; k < nProj; k++) { if (bestMask & (1 << k)) { chosen.push("Project " + (k + 1)); } } res.innerHTML = "Best programme (simple model):
" + "Chosen projects: " + chosen.join(", ") + "
" + "Total investment ≈ " + bestCost.toFixed(2) + "
" + "Total NPV ≈ " + bestNPV.toFixed(2); }); } })();

Expert

Baldwin Interest Rate Calculator

Estimate the Baldwin interest rate as a risk-adjusted comparison rate based on present worth and equivalent annual worth.

Optional: base comparison interest rate (e.g. WACC, discount rate) to show the spread.

Simplified definition: Baldwin interest rate ≈ EAW / PW (per year). Use when PW and EAW already reflect depreciation, replacements, maintenance and salvage effects.
(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("bald_btn"); if (btn) { btn.addEventListener("click", function () { const pw = num("bald_pw"); const eaw = num("bald_eaw"); const base = num("bald_base"); const res = document.getElementById("bald_result"); if (pw === null || eaw === null) { res.textContent = "Please enter both present worth (PW) and equivalent annual worth (EAW)."; return; } if (pw === 0) { res.textContent = "Present worth must be non-zero. Use a positive PW for this simplified Baldwin rate."; return; } // Baldwin rate as simple ratio EAW / PW (per year) const iBald = eaw / pw; // decimal per year const iBaldPct = iBald * 100.0; // % let text = "Baldwin interest rate: " + iBaldPct.toFixed(2) + " % p.a." + "
Ratio EAW / PW: " + iBald.toFixed(4) + " per year."; if (base !== null) { const spread = iBaldPct - base; text += "

Base comparison rate: " + base.toFixed(2) + " % p.a." + "
Excess return over base: " + spread.toFixed(2) + " percentage points."; if (spread > 0) { text += "
This project beats the base rate."; } else if (spread < 0) { text += "
This project falls below the base rate."; } else { text += "
This project matches the base rate."; } } res.innerHTML = text; }); } })();

Expert

WACC Calculator

Compute the weighted average cost of capital (WACC) based on the mix of equity, debt, and tax rate.

Corporate tax rate to adjust the cost of debt (optional, defaults to 0% if left empty).

Formula: WACC = (E / (D + E)) × Re + (D / (D + E)) × Rd × (1 − T).
All rates are per year (% p.a.).
(function () { function num(id) { const el = document.getElementById(id); if (!el) return null; const v = el.value.replace(",", ".").trim(); if (!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("wacc_btn"); if (btn) { btn.addEventListener("click", function () { const E = num("wacc_equity"); const Re = num("wacc_re"); const D = num("wacc_debt"); const Rd = num("wacc_rd"); let Tax = num("wacc_tax"); const res = document.getElementById("wacc_result"); if (E === null || Re === null || D === null || Rd === null) { res.textContent = "Please enter equity value, cost of equity, debt value and cost of debt."; return; } if (E < 0 || D < 0) { res.textContent = "Equity and debt values must be non-negative."; return; } if (E === 0 && D === 0) { res.textContent = "At least one of equity or debt must be greater than 0."; return; } if (Tax === null || Tax < 0) { Tax = 0; } const V = E + D; // total capital const wE = E / V; const wD = D / V; const reDec = Re / 100.0; const rdDec = Rd / 100.0; const tDec = Tax / 100.0; const rdAfterTax = rdDec * (1 - tDec); const waccDec = wE * reDec + wD * rdAfterTax; const waccPct = waccDec * 100.0; let text = "Equity weight (E / (D + E)): " + (wE * 100).toFixed(1) + " %" + "
Debt weight (D / (D + E)): " + (wD * 100).toFixed(1) + " %" + "
After-tax cost of debt: " + (rdAfterTax * 100).toFixed(2) + " % p.a." + "

Weighted average cost of capital (WACC): " + waccPct.toFixed(2) + " % p.a."; res.innerHTML = text; }); } })();

Disclaimer

Intralogistic Tools

Basic

Conveyor Throughput Calculator

Enter the belt speed along the conveying direction.

Length of one carton/tote along the belt.

Minimum gap between products (front-to-front minus length).

Assumes steady flow: throughput = belt speed / (product length + gap).
Product length + gap are automatically converted from mm to meters.
(function(){ function num(id){ const el=document.getElementById(id); if(!el) return null; const v=el.value.replace(",",".").trim(); if(!v) return null; const n=parseFloat(v); return isNaN(n)?null:n; } const btn=document.getElementById("conv_btn"); if(btn){ btn.addEventListener("click",function(){ const v = num("conv_speed"); // m/s const Lmm = num("conv_length"); // mm const gmm = num("conv_gap"); // mm const res = document.getElementById("conv_result"); if(v===null||Lmm===null||gmm===null){ res.textContent="Please enter belt speed, product length and gap."; return; } if(v<=0||Lmm<=0||gmm<0){ res.textContent="Use positive belt speed and product length, and non-negative gap."; return; } // Convert mm → m const L = Lmm / 1000; const g = gmm / 1000; const pitch = L + g; const unitsPerSec = v / pitch; const unitsPerMin = unitsPerSec * 60; const unitsPerHour = unitsPerSec * 3600; const coverage = L / pitch * 100; res.innerHTML = "Pitch (length + gap): " + pitch.toFixed(3) + " m" + "
Conveyor coverage: " + coverage.toFixed(1) + " %" + "
Throughput: " + unitsPerHour.toFixed(0) + " units/h" + " (" + unitsPerMin.toFixed(1) + " units/min)"; }); } })();

Basic

AS/RS Cycle Time Calculator

Total aisle length for the stacker crane.

Maximum horizontal travel speed.

Horizontal acceleration of the crane.

Vertical lift speed of the mast.

Average vertical lift distance per cycle (up + down counted separately).

Simplified model with trapezoidal motion and average travel distances: 1× aisle length (single cycle), 1.5× aisle length (double cycle).
(function(){ function num(id){ const el=document.getElementById(id); if(!el) return null; const v=el.value.replace(",",".").trim(); if(!v) return null; const n=parseFloat(v); return isNaN(n)?null:n; } function moveTime(dist, v, a){ if(dist<=0) return 0; if(v<=0 || a<=0) return dist / Math.max(v,1e-6); const sCrit = v*v / a; if(dist >= sCrit){ return 2*v/a + (dist - sCrit)/v; } else { return 2*Math.sqrt(dist/a); } } const btn=document.getElementById("asrs_btn"); if(btn){ btn.addEventListener("click",function(){ const L = num("asrs_aisle"); const v = num("asrs_speed"); const a = num("asrs_acc"); const vLift = num("asrs_lift"); const liftDistVal = (function(){ const el=document.getElementById("asrs_liftdist"); if(!el) return 0; const v=el.value.replace(",",".").trim(); if(!v) return 0; const n=parseFloat(v); return isNaN(n)?0:n; })(); const res=document.getElementById("asrs_result"); if(L===null||v===null||a===null||vLift===null){ res.textContent="Please enter aisle length, travel speed, acceleration and lift speed."; return; } if(L<=0||v<=0||a<=0||vLift<=0){ res.textContent="All speeds, distances and acceleration must be greater than 0."; return; } const horizSingleDist = L; // approx const horizDoubleDist = 1.5*L; // approx const tHorizSingle = moveTime(horizSingleDist, v, a); const tHorizDouble = moveTime(horizDoubleDist, v, a); const liftDist = Math.max(0, liftDistVal); const tVert = liftDist > 0 ? (liftDist / vLift) : 0; // effective combined vertical motion const tSingle = tHorizSingle + tVert; const tDouble = tHorizDouble + tVert; const cphSingle = tSingle>0 ? 3600/tSingle : 0; const cphDouble = tDouble>0 ? 3600/tDouble : 0; res.innerHTML = "Estimated single-cycle time: " + tSingle.toFixed(2) + " s" + "
Single cycles per hour: " + cphSingle.toFixed(1) + "

Estimated double-cycle time: " + tDouble.toFixed(2) + " s" + "
Double cycles per hour: " + cphDouble.toFixed(1); }); } })();

Basic

Shuttle System Throughput Calculator

Average horizontal travel distance per cycle on one level.

Maximum shuttle travel speed.

Shuttle acceleration.

Lift speed (from level to pick face or conveyor).

Average lift stroke per cycle.

Simplified model: 1 tote per cycle, using trapezoidal motion and average travel distances.
(function(){ function num(id){ const el=document.getElementById(id); if(!el) return null; const v=el.value.replace(",",".").trim(); if(!v) return null; const n=parseFloat(v); return isNaN(n)?null:n; } function moveTime(dist,v,a){ if(dist<=0) return 0; if(v<=0||a<=0) return dist/Math.max(v,1e-6); const sCrit=v*v/a; if(dist>=sCrit){ return 2*v/a+(dist-sCrit)/v; }else{ return 2*Math.sqrt(dist/a); } } const btn=document.getElementById("sh_btn"); if(btn){ btn.addEventListener("click",function(){ const L = num("sh_lane"); const v = num("sh_speed"); const a = num("sh_acc"); const vLift = num("sh_lift"); const liftDist = num("sh_liftdist"); const res=document.getElementById("sh_result"); if(L===null||v===null||a===null||vLift===null||liftDist===null){ res.textContent="Please enter travel distance, speeds, acceleration and lift distance."; return; } if(L<=0||v<=0||a<=0||vLift<=0||liftDist<0){ res.textContent="All distances, speeds and acceleration must be positive (lift distance ≥ 0)."; return; } const tHoriz = moveTime(2*L, v, a); const tVert = liftDist>0 ? (liftDist / vLift) : 0; const tCycle = tHoriz + tVert; const cyclesPerHour = tCycle>0 ? 3600/tCycle : 0; res.innerHTML = "Estimated cycle time per tote: " + tCycle.toFixed(2) + " s" + "
Throughput per level: " + cyclesPerHour.toFixed(1) + " totes/h"; }); } })();

Intermediate

Pallet Conveyor Accumulation Capacity

Total usable conveyor length for accumulation.

Pallet length in conveying direction.

Minimum safety gap between pallets (front-to-front minus length).

Uses simple pitch model: capacity = floor( (L + gap) / (pallet length + gap) ).
(function(){ function num(id){ const el=document.getElementById(id); if(!el) return null; const v=el.value.replace(",",".").trim(); if(!v) return null; const n=parseFloat(v); return isNaN(n)?null:n; } const btn=document.getElementById("pal_btn"); if(btn){ btn.addEventListener("click",function(){ const L = num("pal_len"); const pL= num("pal_plen"); const g = num("pal_gap"); const res=document.getElementById("pal_result"); if(L===null||pL===null||g===null){ res.textContent="Please enter conveyor length, pallet length and safety gap."; return; } if(L<=0||pL<=0||g<0){ res.textContent="Use positive conveyor and pallet length, and non-negative gap."; return; } const pitch = pL + g; const capacity = Math.floor( (L + g) / pitch ); res.innerHTML = "Pitch (pallet + gap): " + pitch.toFixed(3) + " m" + "
Maximum pallets on conveyor: " + capacity; }); } })();

Intermediate

Storage Capacity Calculator (Bins / Slots)

Usable outer dimensions of the rack/shelf block.

Outer dimensions of one tote/bin.

Capacity = floor(width / tote width) · floor(depth / tote depth) · floor(height / tote height).
(function(){ function num(id){ const el=document.getElementById(id); if(!el) return null; const v=el.value.replace(",",".").trim(); if(!v) return null; const n=parseFloat(v); return isNaN(n)?null:n; } const btn=document.getElementById("st_btn"); if(btn){ btn.addEventListener("click",function(){ const rw=num("st_rw"); const rd=num("st_rd"); const rh=num("st_rh"); const tw=num("st_tw"); const td=num("st_td"); const th=num("st_th"); const res=document.getElementById("st_result"); if(rw===null||rd===null||rh===null||tw===null||td===null||th===null){ res.textContent="Please enter rack and tote dimensions."; return; } if(rw<=0||rd<=0||rh<=0||tw<=0||td<=0||th<=0){ res.textContent="All dimensions must be greater than 0."; return; } const nW = Math.floor(rw/tw); const nD = Math.floor(rd/td); const nH = Math.floor(rh/th); const total = nW*nD*nH; res.innerHTML = "Slots across width: " + nW + "
Slots in depth: " + nD + "
Levels in height: " + nH + "

Total storage capacity: " + total + " totes/bins"; }); } })();

Intermediate

Pick Station Throughput Estimator

Time to reach and grab the item (hand to product and back).

Time to scan, confirm and update the system.

Time to place item into carton/tote and arrange it.

Simplified one-piece flow: picks/hour = 3600 / (reach + scan + pack).
(function(){ function num(id){ const el=document.getElementById(id); if(!el) return null; const v=el.value.replace(",",".").trim(); if(!v) return null; const n=parseFloat(v); return isNaN(n)?null:n; } const btn=document.getElementById("pick_btn"); if(btn){ btn.addEventListener("click",function(){ const tReach = num("pick_reach"); const tScan = num("pick_scan"); const tPack = num("pick_pack"); const res=document.getElementById("pick_result"); if(tReach===null||tScan===null||tPack===null){ res.textContent="Please enter reach, scan and packing times."; return; } if(tReach<=0||tScan<0||tPack<=0){ res.textContent="Use positive reach and packing times, scan time ≥ 0."; return; } const cycleTime = tReach + tScan + tPack; const picksPerHour = 3600 / cycleTime; const picksPerMin = picksPerHour / 60; res.innerHTML = "Average cycle time per pick: " + cycleTime.toFixed(2) + " s" + "
Picks per hour (1 operator): " + picksPerHour.toFixed(0) + "
Picks per minute: " + picksPerMin.toFixed(1); }); } })();

Expert

Container Tipping Point Calculator

Calculate the tipping point of a container based on its dimensions and centre of gravity. The calculation is based on overturning moments (tipping), not on sliding.

Tipping moment balance: Fcrit · Hcg = m · g · (b/2).
This gives acrit = g · (b/2) / Hcg and, if mass is known, Fcrit = m · acrit.
Sliding on a slope (downslope force) uses F = m · g · sin(α) and is a different failure mode.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",",".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const g = 9.81; // gravitational acceleration in m/s² const btn = document.getElementById("tip_btn"); if(btn){ btn.addEventListener("click", function(){ const L = num("tip_len"); // [mm] const W = num("tip_width"); // [mm] const H = num("tip_h"); // [mm] const Hcg = num("tip_hcg"); // [mm] const m = num("tip_mass"); // [kg] (optional) const dirEl = document.getElementById("tip_dir"); const dir = (dirEl && dirEl.value === "lat") ? "lat" : "long"; const res = document.getElementById("tip_result"); // Basic validation if (L===null || W===null || H===null || Hcg===null) { res.textContent = "Please enter length, width, height and centre of gravity height."; return; } if (L <= 0 || W <= 0 || H <= 0 || Hcg <= 0) { res.textContent = "All geometric values must be positive."; return; } if (Hcg > H) { res.textContent = "Centre of gravity height cannot be greater than container height."; return; } // Base width in tipping direction (mm) const b = (dir === "long") ? L : W; const baseHalf = b / 2; // mm // Moment balance for tipping: // F_crit * Hcg = m * g * (b/2) // a_crit = F_crit / m = g * (b/2) / Hcg const ratio = baseHalf / Hcg; // dimensionless const aCrit = g * ratio; // m/s² const aCrit_g = aCrit / g; // in g // Equivalent static tilt angle for visualisation: tan(theta) = (b/2) / Hcg const thetaRad = Math.atan(ratio); const thetaDeg = thetaRad * 180 / Math.PI; let text = "Direction: " + (dir === "long" ? "Longitudinal transport" : "Lateral transport") + "
Base width in tipping direction b: " + b.toFixed(1) + " mm" + "
Half base (b/2): " + baseHalf.toFixed(1) + " mm" + "
Container height H: " + H.toFixed(1) + " mm" + "
Centre of gravity height Hcg: " + Hcg.toFixed(1) + " mm" + "

Critical horizontal acceleration acrit: " + aCrit.toFixed(3) + " m/s² (" + aCrit_g.toFixed(3) + " g)" + "
This is the horizontal acceleration at which the container will start to tip (ignoring friction and sliding)." + "

Equivalent static tilt angle: " + thetaDeg.toFixed(2) + "°"; if (m !== null && m > 0) { const Fcrit = m * aCrit; // N text += "
Critical horizontal force Fcrit: " + Fcrit.toFixed(1) + " N"; } else { text += "
(Enter mass m to also calculate the critical horizontal force Fcrit.)"; } res.innerHTML = text; }); } })();

Expert

Incline Conveyor Calculator

Enter any two values (belt length L, height H, angle α). All lengths in millimetres.

Enter exactly two values. Recommended maximum incline angle for longitudinal transport is 15° and for lateral transport
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",",".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("inc_btn"); btn.addEventListener("click", function(){ let L = num("inc_L"); // belt length (mm) let H = num("inc_H"); // height (mm) let A = num("inc_A"); // angle (deg) const res = document.getElementById("inc_result"); const filled = [L,H,A].filter(v => v !== null).length; if (filled !== 2) { res.textContent = "Please enter exactly two values."; return; } const toRad = x => x * Math.PI / 180; const toDeg = x => x * 180 / Math.PI; try { // Case 1: L + H → compute angle if (L !== null && H !== null) { if (H >= L) throw "Invalid geometry"; A = toDeg(Math.asin(H / L)); } // Case 2: L + A → compute height if (L !== null && A !== null) { const Ar = toRad(A); if (A <= 0 || A >= 90) throw "Invalid angle"; H = L * Math.sin(Ar); } // Case 3: H + A → compute belt length if (H !== null && A !== null) { const Ar = toRad(A); if (A <= 0 || A >= 90) throw "Invalid angle"; L = H / Math.sin(Ar); } res.innerHTML = "Belt length L = " + L.toFixed(2) + " mm" + "
Vertical height H = " + H.toFixed(2) + " mm" + "
Incline angle α = " + A.toFixed(2) + "°"; } catch(e){ res.textContent = "Invalid combination or angle. Please check values."; } }); })();

Expert

Bottleneck Identification – Simple Flow Calculator

Enter the maximum throughput per conveyor segment.

Identifies the bottleneck, effective line throughput, segment utilisation and line balancing index, and suggests a target upgrade.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",",".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("bn_btn"); if(btn){ btn.addEventListener("click", function(){ const res = document.getElementById("bn_result"); const caps = []; for(let i=1;i<=5;i++){ const c = num("bn_s"+i); if(c !== null && c > 0){ caps.push({idx:i, cap:c}); } } if(caps.length === 0){ res.textContent = "Please enter at least one segment capacity > 0."; return; } // Sort by capacity to find bottleneck and next limiting segment const sorted = caps.slice().sort((a,b)=>a.cap-b.cap); const bottleneck = sorted[0]; const second = sorted.length > 1 ? sorted[1] : null; const n = caps.length; const minCap = bottleneck.cap; const maxCap = sorted[sorted.length-1].cap; const sumCap = caps.reduce((sum,c)=>sum + c.cap, 0); // Line Balancing Index (LBI) const LBI = sumCap / (maxCap * n); // 0–1 let lbiText; if(LBI >= 0.90){ lbiText = "Well balanced line (LBI ≥ 0.90)."; }else if(LBI >= 0.75){ lbiText = "Moderately balanced line (LBI 0.75–0.90)."; }else if(LBI >= 0.60){ lbiText = "Noticeable imbalance – worth investigating (LBI 0.60–0.75)."; }else{ lbiText = "Strongly imbalanced line – redesign recommended (LBI < 0.60)."; } // Utilisation at bottleneck throughput let utilLines = ""; caps.forEach(function(seg){ const util = (minCap / seg.cap) * 100; utilLines += "Segment #" + seg.idx + ": " + util.toFixed(1) + " % utilisation
"; }); // Suggested upgrade and potential new throughput let suggested = minCap * 1.2; let newThru = minCap; if(second){ suggested = Math.max(suggested, second.cap); newThru = second.cap; // new bottleneck after upgrading the worst one }else{ newThru = suggested; } const gain = newThru > minCap ? ((newThru - minCap) / minCap) * 100 : 0; res.innerHTML = "Bottleneck segment: #" + bottleneck.idx + " (capacity ≈ " + minCap.toFixed(0) + " units/h)" + (second ? "
Next limiting segment: #" + second.idx + " (≈ " + second.cap.toFixed(0) + " units/h)" : "") + "

Effective line throughput (current bottleneck): ≈ " + minCap.toFixed(0) + " units/h" + "
Line balancing index (LBI): " + (LBI*100).toFixed(1) + " %
" + lbiText + "" + "

Segment utilisation at bottleneck flow:
" + "" + utilLines + "" + "
Suggested upgrade target for segment #" + bottleneck.idx + ": ≥ " + suggested.toFixed(0) + " units/h" + "
New theoretical throughput after upgrade: ≈ " + newThru.toFixed(0) + " units/h" + (gain > 0 ? " (≈ " + gain.toFixed(1) + " % increase)" : ""); }); } })();

Disclaimer

Supply Chain Tools

Basic

Safety Stock & Reorder Point Calculator

Daily demand and lead time based safety stock and reorder point.

Safety stock ≈ Z × σLT, where σLT = σdaily × √(lead time). ROP ≈ average demand × lead time + safety stock.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",", ".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } function zFromService(service){ const p = service / 100; if(p >= 0.999) return 3.09; if(p >= 0.995) return 2.58; if(p >= 0.99) return 2.33; if(p >= 0.975) return 1.96; if(p >= 0.95) return 1.65; if(p >= 0.90) return 1.28; if(p >= 0.80) return 0.84; return 1.00; } const btn = document.getElementById("ss_btn"); if(btn){ btn.addEventListener("click", function(){ const D = num("ss_demand"); const sd = num("ss_sigma"); const L = num("ss_leadtime"); const S = num("ss_service"); const res = document.getElementById("ss_result"); if(D===null || sd===null || L===null || S===null){ res.textContent = "Please enter demand, standard deviation, lead time and service level."; return; } if(D<0 || sd<0 || L<=0 || S<=0){ res.textContent = "Use non-negative demand and standard deviation, positive lead time and service level."; return; } const Z = zFromService(S); const sigmaLT = sd * Math.sqrt(L); const safetyStock = Z * sigmaLT; const rop = D * L + safetyStock; res.innerHTML = "Z-value (approx.): " + Z.toFixed(2) + "
Standard deviation of demand during lead time: " + sigmaLT.toFixed(1) + " units" + "
Safety stock: " + safetyStock.toFixed(0) + " units" + "
Reorder point (ROP): " + rop.toFixed(0) + " units"; }); } })();

Intermediate

EOQ & Inventory Cost Calculator

Economic Order Quantity with annual ordering and holding cost breakdown.

EOQ = √(2DS / H). Annual total cost ≈ ordering cost + holding cost + purchase cost.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",", ".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("eoq_btn"); if(btn){ btn.addEventListener("click", function(){ const D = num("eoq_demand"); const S = num("eoq_ordercost"); const H = num("eoq_holdcost"); let C = num("eoq_unitcost"); const res = document.getElementById("eoq_result"); if(D===null || S===null || H===null){ res.textContent = "Please enter annual demand, order cost and holding cost."; return; } if(D<=0 || S<=0 || H<=0){ res.textContent = "Demand, order cost and holding cost must be greater than 0."; return; } if(C===null || C<0) C = 0; const EOQ = Math.sqrt(2*D*S/H); const ordersPerYear = D / EOQ; const cycleTimeDays = 365 / ordersPerYear; const annualOrdering = ordersPerYear * S; const annualHolding = EOQ/2 * H; const purchaseCost = C > 0 ? D * C : 0; const totalCost = annualOrdering + annualHolding + purchaseCost; res.innerHTML = "EOQ (optimal order quantity): " + EOQ.toFixed(0) + " units" + "
Orders per year: " + ordersPerYear.toFixed(1) + "
Average cycle time: " + cycleTimeDays.toFixed(1) + " days" + "

Annual ordering cost: " + annualOrdering.toFixed(2) + "
Annual holding cost: " + annualHolding.toFixed(2) + (C>0 ? "
Annual purchase cost: " + purchaseCost.toFixed(2) : "") + (C>0 ? "
Total annual cost (approx.): " + totalCost.toFixed(2) : ""); }); } })();

Intermediate

Landed Cost Calculator

Estimate total landed cost per unit including freight, insurance, duties and import fees.

Simplified model: customs value ≈ product value + international freight + insurance. Duties, fees and inland freight are added on top to get total landed cost.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return 0; const v = el.value.replace(",", ".").trim(); if(!v) return 0; const n = parseFloat(v); return isNaN(n) ? 0 : n; } const btn = document.getElementById("lc_btn"); if(btn){ btn.addEventListener("click", function(){ const unit = num("lc_unit_cost"); const qty = num("lc_qty"); const freight = num("lc_freight"); const insurance = num("lc_insurance"); const dutyRate = num("lc_duty_rate"); const fees = num("lc_fees"); const inland = num("lc_inland"); const res = document.getElementById("lc_result"); if(unit <= 0 || qty <= 0){ res.textContent = "Please enter a positive unit cost and quantity."; return; } const goodsValue = unit * qty; const customsValue = goodsValue + freight + insurance; const dutyAmount = customsValue * (dutyRate / 100); const totalLanded = goodsValue + freight + insurance + dutyAmount + fees + inland; const costPerUnit = totalLanded / qty; res.innerHTML = "Goods value: " + goodsValue.toFixed(2) + "
Customs value (goods + freight + insurance): " + customsValue.toFixed(2) + "
Duty amount: " + dutyAmount.toFixed(2) + "
Other fees + inland freight: " + (fees + inland).toFixed(2) + "

Total landed cost: " + totalLanded.toFixed(2) + "
Landed cost per unit: " + costPerUnit.toFixed(2); }); } })();

Intermediate

Pallet / Container Space Optimizer

Estimate how many cartons fit into a pallet or container based on dimensions.

Uses simple block stacking, checks two orientations per layer (L×W and W×L) and full layers in height.
(function(){ function num(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",", ".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("pc_btn"); if(btn){ btn.addEventListener("click", function(){ const L = num("pc_len"); const W = num("pc_wid"); const H = num("pc_hei"); const cL = num("pc_clen"); const cW = num("pc_cwid"); const cH = num("pc_chei"); const res = document.getElementById("pc_result"); if(L===null||W===null||H===null||cL===null||cW===null||cH===null){ res.textContent = "Please enter all pallet/container and carton dimensions."; return; } if(L<=0||W<=0||H<=0||cL<=0||cW<=0||cH<=0){ res.textContent = "All dimensions must be greater than 0."; return; } const perLayer1 = Math.floor(L/cL) * Math.floor(W/cW); const perLayer2 = Math.floor(L/cW) * Math.floor(W/cL); let perLayer = perLayer1; let orientation = "Carton length along pallet length."; if(perLayer2 > perLayer1){ perLayer = perLayer2; orientation = "Carton width along pallet length (rotated 90°)."; } const layers = Math.floor(H / cH); const total = perLayer * layers; const palletArea = L * W; const cartonArea = cL * cW; const layerUtil = perLayer > 0 ? (perLayer * cartonArea / palletArea) * 100 : 0; const heightUtil = (layers * cH / H) * 100; res.innerHTML = "Best orientation: " + orientation + "
Cartons per layer: " + perLayer + "
Number of full layers: " + layers + "
Total cartons per pallet/container: " + total + "
Floor area utilization per layer: " + layerUtil.toFixed(1) + " %" + "
Height utilization: " + heightUtil.toFixed(1) + " %"; }); } })();

Expert

ABC / XYZ Classification Tool

Paste items as:
SKU; annual consumption value; coefficient of variation
One item per line (semicolon or comma separated).

ABC thresholds (by cumulative value): A ≤ 80%, B ≤ 95%, C > 95%.
XYZ based on coefficient of variation (CV): X ≤ 0.5, Y ≤ 1.0, Z > 1.0.
(function(){ const btn = document.getElementById("abc_btn"); if(btn){ btn.addEventListener("click", function(){ const res = document.getElementById("abc_result"); const raw = document.getElementById("abc_input").value; const lines = raw.split(/\r?\n/); const items = []; for(const line of lines){ const trimmed = line.trim(); if(!trimmed) continue; const parts = trimmed.split(/[;,]/).map(p => p.trim()); if(parts.length < 2) continue; const name = parts[0] || "Item"; const val = parseFloat(parts[1].replace(",", ".")); const cv = parts.length >= 3 ? parseFloat(parts[2].replace(",", ".")) : NaN; if(isNaN(val)) continue; items.push({name, val, cv}); } if(items.length === 0){ res.textContent = "Please paste at least one valid line with value."; return; } items.sort((a,b)=>b.val - a.val); const totalVal = items.reduce((sum,x)=>sum + x.val, 0); let cum = 0; items.forEach(it=>{ cum += it.val; const share = totalVal > 0 ? cum / totalVal : 0; let abc; if(share <= 0.80) abc = "A"; else if(share <= 0.95) abc = "B"; else abc = "C"; let xyz = ""; if(!isNaN(it.cv)){ if(it.cv <= 0.5) xyz = "X"; else if(it.cv <= 1.0) xyz = "Y"; else xyz = "Z"; }else{ xyz = "-"; } it.cumShare = share; it.abc = abc; it.xyz = xyz; }); let html = "" + "" + "" + ""; items.forEach(it=>{ const cls = it.abc + (it.xyz !== "-" ? it.xyz : ""); html += "" + "" + "" + "" + "" + "" + "" + "" + ""; }); html += "
ItemValueCum. %ABCCVXYZClass
" + it.name + "" + it.val.toFixed(2) + "" + (it.cumShare*100).toFixed(1) + " %" + it.abc + "" + (isNaN(it.cv) ? "-" : it.cv.toFixed(2)) + "" + it.xyz + "" + cls + "
"; res.innerHTML = html; }); } })();

Expert

Transportation Mode & Cost Optimizer

Compare basic cost and transit time by mode. If you leave rates or speeds empty, typical defaults are used.

Cost per ton-km (optional). Defaults: Truck 0.08, Rail 0.05, Sea 0.02, Air 0.50.

Average speed [km/h] (optional). Defaults: Truck 60, Rail 70, Sea 30, Air 750.

Simplified model for strategic comparison. Does not include handling times, port dwell, customs delays, etc.
(function(){ function numOpt(id){ const el = document.getElementById(id); if(!el) return null; const v = el.value.replace(",", ".").trim(); if(!v) return null; const n = parseFloat(v); return isNaN(n) ? null : n; } const btn = document.getElementById("tm_btn"); if(btn){ btn.addEventListener("click", function(){ const dist = numOpt("tm_dist"); const weight = numOpt("tm_weight"); const res = document.getElementById("tm_result"); if(dist===null || weight===null || dist<=0 || weight<=0){ res.textContent = "Please enter positive distance and shipment weight."; return; } // Rates with defaults if empty let rTruck = numOpt("tm_truck_rate"); if(rTruck===null || rTruck<0) rTruck = 0.08; let rRail = numOpt("tm_rail_rate"); if(rRail===null || rRail<0) rRail = 0.05; let rSea = numOpt("tm_sea_rate"); if(rSea===null || rSea<0) rSea = 0.02; let rAir = numOpt("tm_air_rate"); if(rAir===null || rAir<0) rAir = 0.50; // Speeds with defaults let vTruck = numOpt("tm_truck_speed"); if(vTruck===null || vTruck<=0) vTruck = 60; let vRail = numOpt("tm_rail_speed"); if(vRail===null || vRail<=0) vRail = 70; let vSea = numOpt("tm_sea_speed"); if(vSea===null || vSea<=0) vSea = 30; let vAir = numOpt("tm_air_speed"); if(vAir===null || vAir<=0) vAir = 750; function modeResult(name, rate, speed){ const cost = dist * weight * rate; const hours = dist / speed; const days = hours / 24; return {name, cost, days}; } const modes = [ modeResult("Truck", rTruck, vTruck), modeResult("Rail", rRail, vRail), modeResult("Sea", rSea, vSea), modeResult("Air", rAir, vAir) ]; let minCost = Infinity, minTime = Infinity; modes.forEach(m=>{ if(m.cost < minCost) minCost = m.cost; if(m.days < minTime) minTime = m.days; }); let html = "" + "" + "" + ""; modes.forEach(m=>{ let comment = ""; if(Math.abs(m.cost - minCost) < 1e-6 && Math.abs(m.days - minTime) < 1e-6){ comment = "Cheapest & fastest"; } else if(Math.abs(m.cost - minCost) < 1e-6){ comment = "Cheapest"; } else if(Math.abs(m.days - minTime) < 1e-6){ comment = "Fastest"; } else { comment = "-"; } html += "" + "" + "" + "" + "" + ""; }); html += "
ModeTotal costTransit time [days]Comment
" + m.name + "" + m.cost.toFixed(2) + "" + m.days.toFixed(2) + "" + comment + "
"; res.innerHTML = html; }); } })();