Files
cbp-calculator/test_scenarios.js
T
Marty Bostick 3e35eb10ef Add 'Already joined' toggle + post-join PIF message template
- New checkbox: 'Already joined (skip signup language)' toggles the plan generator
- Already-joined mode strips signup prompts, says 'I went back and funded your level'
- New template: templates/post-join-pif-message.md for the manual message scenario
- Skill updated with reference to the new template
2026-07-11 12:42:29 +00:00

105 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const LEVELS = [
{level:1, act:1, camp:13, total:14, payout:17.17, netProfit:4.17},
{level:2, act:7, camp:77, total:84, payout:118.91, netProfit:34.91},
{level:3, act:14, camp:163, total:177, payout:211.57, netProfit:48.57},
{level:4, act:36, camp:310, total:346, payout:388.80, netProfit:78.80},
{level:5, act:72, camp:620, total:692, payout:777.60, netProfit:157.60},
{level:6, act:120, camp:1200, total:1320, payout:1555.20,netProfit:355.20},
{level:7, act:240, camp:2400, total:2640, payout:3240.00,netProfit:840.00},
];
const HYBRIDS = {
'L1-only': { label: 'L1 Only', reinvest: 13, payout: 17.17, profit: 4.17, cycles: 9, months: 3.0, daysPer: 19 },
'L2+L1': { label: 'L2 + L1', reinvest: 90, payout: 118.91, profit: 28.91, cycles: 4, months: 2.5, daysPer: 19 },
'L3+L1': { label: 'L3 + L1', reinvest: 163, payout: 211.57, profit: 48.57, cycles: 4, months: 2.5, daysPer: 19 },
'L4+L3': { label: 'L4 + L3', reinvest: 450, payout: 583.20, profit: 133.20,cycles: 5, months: 3.0, daysPer: 19 },
'L5+L4': { label: 'L5 + L4', reinvest: 900, payout: 1166.40,profit: 266.40,cycles: 4, months: 2.0, daysPer: 19 },
'L6': { label: 'L6', reinvest: 1200, payout: 1555.20,profit: 355.20,cycles: 4, months: 2.0, daysPer: 19 },
'L7': { label: 'Single L7', reinvest: 2400, payout: 3240.00,profit: 840.00,cycles: 7, months: 3.0, daysPer: 19 },
'3xL7': { label: '3× L7 Endgame', reinvest: 7200, payout: 9720, profit: 2520, cycles: 1, months: 0.63, daysPer: 19 },
};
function getLevelCost(upTo) {
if (upTo <= 0) return 0;
return LEVELS.slice(0, upTo).reduce((s, l) => s + l.total, 0);
}
function getEffectiveStart(gift, selfF) {
return Math.max(gift, selfF);
}
function getPhaseSequence(effectiveStart) {
if (effectiveStart >= 5) return ['L5+L4','L6','L7','3xL7'];
if (effectiveStart >= 4) return ['L4+L3','L5+L4','L6','L7','3xL7'];
if (effectiveStart >= 3) return ['L3+L1','L4+L3','L5+L4','L6','L7','3xL7'];
if (effectiveStart >= 2) return ['L2+L1','L3+L1','L4+L3','L5+L4','L6','L7','3xL7'];
return ['L1-only','L2+L1','L3+L1','L4+L3','L5+L4','L6','L7','3xL7'];
}
function estimateMonths(phases) {
let total = 0;
for (const k of phases) {
if (k === '3xL7') break;
total += HYBRIDS[k].months;
}
return total;
}
function estimateYear1Cum(phases, commPct, giftLevel) {
let cum = 0;
let months = 0;
for (const k of phases) {
if (k === '3xL7') break;
const p = HYBRIDS[k];
const yourCut = p.payout * (commPct / 100);
const cyclesInYear1 = Math.min(p.cycles, Math.max(0, (12 - months) / (p.months / p.cycles)));
const actual = Math.floor(cyclesInYear1);
for (let i = 0; i < actual; i++) cum += yourCut;
months += p.months;
if (months >= 12) break;
}
return Math.round(cum);
}
function buildSCENARIOS() {
const levels = [
{ giftLvl: 1, selfLvl: 0, id: 'gift1', label: 'L1 Gift ($14)', yourCost: 14 },
{ giftLvl: 0, selfLvl: 1, id: 'self1', label: 'Self L1 ($14)', yourCost: 0 },
{ giftLvl: 2, selfLvl: 0, id: 'gift2', label: 'L1-L2 Gift ($98)', yourCost: 98 },
{ giftLvl: 0, selfLvl: 2, id: 'self2', label: 'Self L2 ($98)', yourCost: 0 },
{ giftLvl: 3, selfLvl: 0, id: 'gift3', label: 'L1-L3 Gift ($263)', yourCost: 263},
{ giftLvl: 0, selfLvl: 3, id: 'self3', label: 'Self L3 ($263)', yourCost: 0 },
{ giftLvl: 4, selfLvl: 0, id: 'gift4', label: 'L1-L4 Gift ($593)', yourCost: 593},
{ giftLvl: 0, selfLvl: 4, id: 'self4', label: 'Self L4 ($593)', yourCost: 0 },
{ giftLvl: 5, selfLvl: 0, id: 'gift5', label: 'L1-L5 Gift ($1,253)', yourCost:1253},
{ giftLvl: 0, selfLvl: 5, id: 'self5', label: 'Self L5 ($1,253)', yourCost: 0 },
];
return levels.map(function(s) {
const eff = Math.max(s.giftLvl, s.selfLvl);
const phases = getPhaseSequence(eff);
const t = Math.round(estimateMonths(phases));
const y = estimateYear1Cum(phases, 10, s.giftLvl);
const eg = phases.filter(function(k) { return k !== '3xL7'; })
.reduce(function(sum, k) { return sum + HYBRIDS[k].payout * 0.10 * HYBRIDS[k].cycles; }, 0);
return { id: s.id, label: s.label, yourCost: s.yourCost, time: t, yr1: Math.round(y), totalEG: Math.round(eg), monthly: 1860 };
});
}
const SCENARIOS = buildSCENARIOS();
console.log("=== SCENARIOS ===");
for (var i = 0; i < SCENARIOS.length; i++) {
var s = SCENARIOS[i];
console.log(s.id + ": time=" + s.time + "mo, yr1=$" + s.yr1 + ", totalEG=$" + s.totalEG);
}
// Verify consistency: rebuild should give same result
var r = buildSCENARIOS();
var ok = true;
for (var i = 0; i < SCENARIOS.length; i++) {
if (SCENARIOS[i].time !== r[i].time || SCENARIOS[i].yr1 !== r[i].yr1) {
console.log("MISMATCH at " + SCENARIOS[i].id);
ok = false;
}
}
if (ok) console.log("=== ALL CONSISTENT ===");