// Mock data for the Rate Repository prototype const TERMINALS = [ { code: "CNSHA", name: "Shanghai (Yangshan)", country: "CN", region: "North Asia", area: "East China", currency: "CNY" }, { code: "CNNGB", name: "Ningbo Zhoushan", country: "CN", region: "North Asia", area: "East China", currency: "CNY" }, { code: "CNTAO", name: "Qingdao Qianwan", country: "CN", region: "North Asia", area: "North China", currency: "CNY" }, { code: "CNTSN", name: "Tianjin Xingang", country: "CN", region: "North Asia", area: "North China", currency: "CNY" }, { code: "HKHKG", name: "Hong Kong (Kwai Tsing)", country: "HK", region: "North Asia", area: "South China", currency: "HKD" }, { code: "CNYTN", name: "Shenzhen Yantian", country: "CN", region: "North Asia", area: "South China", currency: "CNY" }, { code: "KRPUS", name: "Busan New Port", country: "KR", region: "North Asia", area: "Korea", currency: "KRW" }, { code: "JPYOK", name: "Yokohama", country: "JP", region: "North Asia", area: "Japan", currency: "JPY" }, { code: "SGSIN", name: "Singapore (PSA)", country: "SG", region: "Southeast Asia", area: "Singapore", currency: "SGD" }, { code: "MYPKG", name: "Port Klang Westport", country: "MY", region: "Southeast Asia", area: "Malaysia", currency: "MYR" }, { code: "MYTPP", name: "Tanjung Pelepas", country: "MY", region: "Southeast Asia", area: "Malaysia", currency: "MYR" }, { code: "VNSGN", name: "Cat Lai (Ho Chi Minh)", country: "VN", region: "Southeast Asia", area: "Vietnam", currency: "VND" }, { code: "THLCH", name: "Laem Chabang", country: "TH", region: "Southeast Asia", area: "Thailand", currency: "THB" }, { code: "IDJKT", name: "Tanjung Priok", country: "ID", region: "Southeast Asia", area: "Indonesia", currency: "IDR" }, { code: "INNSA", name: "Nhava Sheva (JNPT)", country: "IN", region: "South Asia Sub-Continent", area: "West India", currency: "INR" }, { code: "INMUN", name: "Mundra", country: "IN", region: "South Asia Sub-Continent", area: "West India", currency: "INR" }, { code: "BDCGP", name: "Chittagong", country: "BD", region: "South Asia Sub-Continent", area: "Bangladesh", currency: "BDT" }, { code: "AUSYD", name: "Sydney (Port Botany)", country: "AU", region: "Oceania", area: "Australia East", currency: "AUD" }, { code: "AUMEL", name: "Melbourne (Webb Dock)", country: "AU", region: "Oceania", area: "Australia East", currency: "AUD" }, { code: "NZAKL", name: "Auckland", country: "NZ", region: "Oceania", area: "New Zealand", currency: "NZD" }, ]; const COST_TYPES = [ { code: "CY_HANDLING", name: "CY Handling", category: "CY" }, { code: "STORAGE", name: "Storage", category: "Behavior" }, { code: "REEFER_POWER", name: "Reefer Power", category: "Behavior" }, { code: "REEFER_PLUG", name: "Reefer Plug In/Out", category: "Behavior" }, { code: "EXTRA_YARD", name: "Extra Yard Work", category: "Behavior" }, { code: "SHIFTING", name: "Shifting", category: "Behavior" }, { code: "VGM_WEIGH", name: "VGM Weighing", category: "Behavior" }, { code: "GATE_MOVE", name: "Gate Move", category: "CY" }, ]; const CHARGE_UNITS = [ { code: "PER_TEU", name: "Per TEU", applicable: ["CY_HANDLING","SHIFTING","GATE_MOVE"] }, { code: "PER_FEU", name: "Per FEU", applicable: ["CY_HANDLING","SHIFTING","GATE_MOVE"] }, { code: "PER_BOX", name: "Per Box", applicable: ["CY_HANDLING","VGM_WEIGH","SHIFTING","GATE_MOVE"] }, { code: "PER_DAY", name: "Per Day", applicable: ["STORAGE","REEFER_POWER"] }, { code: "PER_MOVE", name: "Per Move", applicable: ["REEFER_PLUG","EXTRA_YARD","SHIFTING"] }, { code: "PER_KWH", name: "Per kWh", applicable: ["REEFER_POWER"] }, ]; const ROE = { CNY: 7.254, HKD: 7.819, KRW: 1342.1, JPY: 152.4, SGD: 1.346, MYR: 4.682, VND: 25410, THB: 35.8, IDR: 15780, INR: 83.42, BDT: 117.8, AUD: 1.512, NZD: 1.668, USD: 1.0, }; // Build a realistic-sized rate dataset const RATES = (() => { const rows = []; let id = 10000; const dates = ["2025-01-01","2024-07-01","2024-01-01","2023-07-01","2025-03-15"]; // Heavily Active-weighted so the calculator and lists always find live data. // We sprinkle in a few Draft/Superseded for realism. const focals = ["L. Tanaka","M. Chen","R. Singh","P. Wijaya","K. Park","S. Nguyen","A. Patel"]; function emit(t, ct, u, opts = {}) { const eff = opts.eff || dates[id % dates.length]; const status = opts.status || ((id % 23 === 0) ? "Draft" : (id % 37 === 0) ? "Superseded" : "Active"); let base = ({CY_HANDLING:120, STORAGE:8, REEFER_POWER:14, REEFER_PLUG:35, EXTRA_YARD:90, SHIFTING:55, VGM_WEIGH:25, GATE_MOVE:18}[ct.code] || 50); if (u.code === "PER_FEU") base *= 1.7; if (u.code === "PER_KWH") base = base / 8; if (opts.tierMul) base *= opts.tierMul; const rate = +(base * ROE[t.currency] / ROE.USD * (0.85 + ((id*13)%30)/100)).toFixed(2); rows.push({ id: `R-${id++}`, terminal: t.code, terminalName: t.name, region: t.region, area: t.area, costType: ct.code, costTypeName: ct.name, chargeUnit: u.code, chargeUnitName: u.name, rateLocal: rate, currency: t.currency, effective: eff, expiry: "2025-12-31", contractRef: `CTR-APA-2025-${(id%900)+100}`, tier: opts.tier || null, status, modifiedBy: focals[id % focals.length], modifiedAt: "2025-04-" + String((id%28)+1).padStart(2,"0") + " 14:" + String((id%59)).padStart(2,"0"), }); } TERMINALS.forEach(t => { COST_TYPES.forEach(ct => { const units = CHARGE_UNITS.filter(u => u.applicable.includes(ct.code)); if (ct.code === "STORAGE") { // Always emit two ACTIVE storage tier rows (Day 1–3 and Day 4+) const u = units.find(x => x.code === "PER_DAY") || units[0]; emit(t, ct, u, { tier: "Day 1–3", tierMul: 1.0, status: "Active" }); emit(t, ct, u, { tier: "Day 4+", tierMul: 2.2, status: "Active" }); } else { // One Active rate per cost type · primary unit const u = units[0]; if (u) emit(t, ct, u, { status: "Active" }); // Sometimes add a second unit variant (e.g. PER_FEU alongside PER_TEU) if (units[1] && (id % 3 === 0)) emit(t, ct, units[1], { status: "Active" }); } }); }); return rows; })(); const REGIONS = ["North Asia","Southeast Asia","South Asia Sub-Continent","Oceania"]; const PERSONAS = { rate_calculator: { name: "Aiko Tanaka", title: "Ops Coordinator, North Asia", role: "rate_calculator", regions: ["North Asia"], areas: ["East China","North China"], avatar: "AT", color: "#7a8fa6", }, read: { name: "Marcus Chen", title: "Trade Lane Analyst, Intra-Asia", role: "read", regions: ["North Asia","Southeast Asia"], areas: ["—"], avatar: "MC", color: "#3d6e8e", }, edit: { name: "Priya Wijaya", title: "Rate Focal, SE Asia", role: "edit", regions: ["Southeast Asia"], areas: ["Singapore","Malaysia"], avatar: "PW", color: "#1f6f5c", }, fbp: { name: "Ravi Singh", title: "Finance Business Partner, APA", role: "fbp", regions: ["North Asia","Southeast Asia","South Asia Sub-Continent","Oceania"], areas: ["—"], avatar: "RS", color: "#8a4d2e", }, procurement: { name: "Sofia Lindqvist", title: "Procurement Manager, APA", role: "procurement", regions: ["North Asia","Southeast Asia","South Asia Sub-Continent","Oceania"], areas: ["—"], avatar: "SL", color: "#6b3f8a", }, admin: { name: "Daniel Park", title: "System Administrator, Ocean Finance", role: "admin", regions: ["Global"], areas: ["—"], avatar: "DP", color: "#1f3a5c", }, unknown: { name: "Guest User", title: "Pending Access", role: "unknown", regions: [], areas: [], avatar: "?", color: "#6b7280", }, }; const PERMS = { // viewRates rateHealth editRates importRates export aiAssistant rebateMonitor volumeTracker tcoAnalysis roeTable admin accessOnly unknown: { viewRates: false, rateHealth: false, editRates: false, importRates: false, export: false, aiAssistant: false, rebateMonitor: false, volumeTracker: false, tcoAnalysis: false, roeTable: false, admin: false, accessOnly: true }, rate_calculator: { viewRates: false, rateHealth: false, editRates: false, importRates: false, export: false, aiAssistant: false, rebateMonitor: false, volumeTracker: false, tcoAnalysis: false, roeTable: false, admin: false }, read: { viewRates: true, rateHealth: true, editRates: false, importRates: false, export: false, aiAssistant: false, rebateMonitor: false, volumeTracker: false, tcoAnalysis: false, roeTable: false, admin: false }, edit: { viewRates: true, rateHealth: true, editRates: true, importRates: true, export: false, aiAssistant: false, rebateMonitor: false, volumeTracker: true, tcoAnalysis: false, roeTable: true, admin: false }, fbp: { viewRates: true, rateHealth: true, editRates: false, importRates: false, export: true, aiAssistant: true, rebateMonitor: true, volumeTracker: true, tcoAnalysis: true, roeTable: true, admin: false }, procurement: { viewRates: true, rateHealth: true, editRates: false, importRates: true, export: true, aiAssistant: true, rebateMonitor: true, volumeTracker: true, tcoAnalysis: true, roeTable: true, admin: false }, admin: { viewRates: true, rateHealth: true, editRates: true, importRates: true, export: true, aiAssistant: true, rebateMonitor: true, volumeTracker: true, tcoAnalysis: true, roeTable: true, admin: true }, }; const AUDIT = [ { ts: "2025-05-12 16:42", user: "P. Wijaya", event: "Rate Updated", target: "R-10043 · SGSIN · Storage", detail: "180.00 SGD → 195.00 SGD", ip: "10.42.18.7" }, { ts: "2025-05-12 15:08", user: "S. Lindqvist", event: "Contract Uploaded (DIFY)", target: "CTR-APA-2025-217.pdf", detail: "12 rows extracted, 11 imported", ip: "10.42.18.91" }, { ts: "2025-05-12 14:51", user: "R. Singh", event: "Rate Sheet Exported", target: "North Asia · Q2 2025", detail: "1,284 rows · .xlsx", ip: "10.42.18.40" }, { ts: "2025-05-12 12:13", user: "D. Park", event: "Access Approved", target: "marcus.chen@…", detail: "read · North Asia, SE Asia", ip: "10.42.18.2" }, { ts: "2025-05-12 11:02", user: "P. Wijaya", event: "Rate Created", target: "R-10841 · MYPKG · Reefer Power", detail: "14.80 MYR / day", ip: "10.42.18.7" }, { ts: "2025-05-12 10:30", user: "L. Tanaka", event: "Calculator Used", target: "CNSHA · CY Handling × 4,200 TEU", detail: "Result: USD 504,840", ip: "10.42.18.55" }, { ts: "2025-05-12 09:14", user: "D. Park", event: "Metadata Updated", target: "Terminal · CNYTN", detail: "Area: South China → South China", ip: "10.42.18.2" }, { ts: "2025-05-11 17:48", user: "M. Chen", event: "User Login", target: "marcus.chen@…", detail: "SSO · Azure AD", ip: "10.42.18.40" }, { ts: "2025-05-11 16:22", user: "D. Park", event: "ROE Updated", target: "CNY/USD", detail: "0.13751 → 0.13784", ip: "10.42.18.2" }, ]; const ACCESS_REQUESTS = [ { id: "AR-2041", requester: "Hana Watanabe", email: "hana.watanabe@…", role: "read", regions: ["North Asia"], areas: ["Japan"], justification: "Need visibility into JP terminal rates for monthly variance reporting.", submitted: "2025-05-12 09:14", status: "Pending", sla: 1, manager: "K. Park" }, { id: "AR-2040", requester: "Diego Alvarez", email: "diego.alvarez@…", role: "fbp", regions: ["Oceania"], areas: ["—"], justification: "FBP rotation to APA Oceania — analytical access required for FY26 budget cycle.", submitted: "2025-05-09 11:30", status: "Pending", sla: 4, manager: "S. Lindqvist" }, { id: "AR-2039", requester: "Yuki Sato", email: "yuki.sato@…", role: "edit", regions: ["North Asia"], areas: ["Japan"], justification: "Designated Rate Focal for Japan terminals starting May.", submitted: "2025-05-12 08:02", status: "Pending", sla: 1, manager: "K. Park" }, { id: "AR-2038", requester: "Lakshmi Iyer", email: "lakshmi.iyer@…", role: "read", regions: ["South Asia Sub-Continent"], areas: ["West India"], justification: "Trade lane analyst, requires read access for cost modelling.", submitted: "2025-05-08 14:22", status: "Approved", sla: 0, manager: "R. Singh" }, { id: "AR-2037", requester: "Olga Petrov", email: "olga.petrov@…", role: "procurement", regions: ["Southeast Asia"], areas: ["—"], justification: "New procurement hire covering SEA terminal contracts.", submitted: "2025-05-07 10:11", status: "Rejected", sla: 0, manager: "S. Lindqvist" }, ]; const TERMINAL_BY_CODE = Object.fromEntries(TERMINALS.map(t => [t.code, t])); // ============================================================ // v1.1 additions — Equipment, Cargo, Volume, Rebate, MVC, TCO // ============================================================ const EQUIPMENT = ["20GP", "40GP", "40HC", "45HC", "20RF", "40RF"]; const CARGO_TYPES = ["Dry", "Reefer", "Dangerous", "OOG"]; const MOVE_TYPES = ["Import", "Export", "Transship", "Repositioning"]; // Monthly volume (last 12 months) per terminal — aggregated TEU const VOLUME = (() => { const months = []; // 2024-06 → 2025-05 for (let i = 11; i >= 0; i--) { const d = new Date(2025, 4 - i, 1); months.push(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`); } const rows = []; TERMINALS.forEach((t, ti) => { const baseMonthly = 2000 + (ti % 7) * 800 + (ti * 311 % 1500); months.forEach((m, mi) => { // seasonal sine + slight YoY growth + noise const seasonal = 1 + 0.15 * Math.sin((mi / 12) * Math.PI * 2 - 0.5); const trend = 1 + (mi - 6) * 0.005; const noise = 0.92 + ((ti * 13 + mi * 37) % 16) / 100; const teu = Math.round(baseMonthly * seasonal * trend * noise); const moves = Math.round(teu * 0.62); rows.push({ terminal: t.code, terminalName: t.name, region: t.region, period: m, teu, moves }); }); }); return { months, rows }; })(); // MVC (Minimum Volume Commitment) per terminal — only some terminals have it const MVC = { CNSHA: { annual: 120000, penaltyRate: 28, focal: "L. Tanaka" }, CNNGB: { annual: 72000, penaltyRate: 25, focal: "L. Tanaka" }, CNTAO: { annual: 60000, penaltyRate: 30, focal: "M. Chen" }, CNTSN: { annual: 48000, penaltyRate: 26, focal: "M. Chen" }, SGSIN: { annual: 96000, penaltyRate: 38, focal: "P. Wijaya" }, MYPKG: { annual: 54000, penaltyRate: 22, focal: "P. Wijaya" }, INNSA: { annual: 36000, penaltyRate: 18, focal: "R. Singh" }, }; // Year-to-date volume per terminal (Jan–May 2025) const YTD_VOLUME = (() => { const out = {}; TERMINALS.forEach(t => { const ytd = VOLUME.rows.filter(v => v.terminal === t.code && v.period >= "2025-01").reduce((s, v) => s + v.teu, 0); out[t.code] = ytd; }); return out; })(); // Rebate contracts const REBATES = [ { id: "RB-2025-001", terminal: "CNSHA", contractRef: "CTR-APA-2025-104", type: "Tiered Rebate", scope: "CY Handling", period: "Annual", settlement: "Credit Note", deadline: 60, currency: "CNY", effective: "2025-01-01", expiry: "2025-12-31", status: "Active", accruedYTD: 184650, accruedYTDLocal: 1339450, tiers: [ { name: "Tier 1 (Base)", min: 0, max: 19999, rate: 0, type: "Incremental" }, { name: "Tier 2", min: 20000, max: 49999, rate: 1.5, type: "Incremental" }, { name: "Tier 3", min: 50000, max: 99999, rate: 2.5, type: "Retroactive" }, { name: "Tier 4 (Elite)",min: 100000, max: null, rate: 3.5, type: "Retroactive" }, ], currentTier: 3, }, { id: "RB-2025-002", terminal: "SGSIN", contractRef: "CTR-APA-2025-217", type: "Volume Rebate", scope: "All Cost Types", period: "Quarterly", settlement: "Cash", deadline: 45, currency: "SGD", effective: "2025-01-01", expiry: "2026-12-31", status: "Active", accruedYTD: 92480, accruedYTDLocal: 124460, tiers: [ { name: "Tier 1 (Base)", min: 0, max: 14999, rate: 0, type: "Incremental" }, { name: "Tier 2", min: 15000, max: 29999, rate: 1.0, type: "Incremental" }, { name: "Tier 3", min: 30000, max: null, rate: 2.0, type: "Retroactive" }, ], currentTier: 2, }, { id: "RB-2025-003", terminal: "CNNGB", contractRef: "CTR-APA-2025-118", type: "Tiered Rebate", scope: "CY Handling, Storage", period: "Annual", settlement: "Rate Offset", deadline: 30, currency: "CNY", effective: "2025-01-01", expiry: "2025-12-31", status: "Active", accruedYTD: 67200, accruedYTDLocal: 487490, tiers: [ { name: "Tier 1 (Base)", min: 0, max: 24999, rate: 0, type: "Incremental" }, { name: "Tier 2", min: 25000, max: 59999, rate: 1.2, type: "Incremental" }, { name: "Tier 3", min: 60000, max: null, rate: 2.2, type: "Retroactive" }, ], currentTier: 2, }, { id: "RB-2025-004", terminal: "CNYTN", contractRef: "CTR-APA-2025-141", type: "Performance Bonus", scope: "All Cost Types", period: "Annual", settlement: "Cash", deadline: 90, currency: "CNY", effective: "2025-01-01", expiry: "2025-12-31", status: "Active", accruedYTD: 0, accruedYTDLocal: 0, tiers: [ { name: "Bonus threshold", min: 80000, max: null, rate: 1.8, type: "Retroactive" }, ], currentTier: 0, atRisk: true, }, { id: "RB-2025-005", terminal: "KRPUS", contractRef: "CTR-APA-2025-061", type: "Tiered Rebate", scope: "CY Handling", period: "Quarterly", settlement: "Credit Note", deadline: 60, currency: "KRW", effective: "2025-01-01", expiry: "2025-12-31", status: "Active", accruedYTD: 41250, accruedYTDLocal: 55378125, tiers: [ { name: "Tier 1 (Base)", min: 0, max: 9999, rate: 0, type: "Incremental" }, { name: "Tier 2", min: 10000, max: 19999, rate: 1.0, type: "Incremental" }, { name: "Tier 3", min: 20000, max: null, rate: 2.0, type: "Retroactive" }, ], currentTier: 2, }, { id: "RB-2025-006", terminal: "INNSA", contractRef: "CTR-APA-2025-088", type: "Lump Sum", scope: "All Cost Types", period: "Annual", settlement: "Credit Note", deadline: 60, currency: "INR", effective: "2025-01-01", expiry: "2025-12-31", status: "Active", accruedYTD: 18200, accruedYTDLocal: 1518244, tiers: [ { name: "Achievement bonus", min: 30000, max: null, rate: 0.8, type: "Retroactive" }, ], currentTier: 1, }, ]; // Settlements const SETTLEMENTS = [ { id: "SET-2025-031", rebate: "RB-2025-002", period: "Q1 2025", claimed: 24200, accrued: 24850, ccy: "SGD", status: "Settled", claimedDate: "2025-04-15", settledDate: "2025-04-28", ref: "CRN-SG-78114", variance: -2.6 }, { id: "SET-2025-024", rebate: "RB-2025-001", period: "Q1 2025", claimed: 312800, accrued: 312800, ccy: "CNY", status: "Settled", claimedDate: "2025-04-10", settledDate: "2025-04-22", ref: "CRN-CN-91082", variance: 0 }, { id: "SET-2025-038", rebate: "RB-2025-005", period: "Q1 2025", claimed: 14210000, accrued: 14210000, ccy: "KRW", status: "Awaiting Credit", claimedDate: "2025-05-03", settledDate: null, ref: "CL-2025-014", variance: 0 }, { id: "SET-2025-041", rebate: "RB-2025-003", period: "Q1 2025", claimed: 168200, accrued: 178200, ccy: "CNY", status: "In Review", claimedDate: "2025-05-08", settledDate: null, ref: "DRAFT", variance: -5.6 }, { id: "SET-2025-019", rebate: "RB-2025-006", period: "Q4 2024", claimed: 1230000, accrued: 1230000, ccy: "INR", status: "Overdue", claimedDate: "2025-03-15", settledDate: null, ref: "CL-2024-Q4", variance: 0, daysOverdue: 14 }, ]; // Health Dashboard — Completeness Matrix const COMPLETENESS = (() => { const expected = []; // For 5 sample terminals, expand the expected coverage matrix ["CNSHA", "CNNGB", "CNTAO", "CNYTN", "SGSIN"].forEach(tc => { ["CY_HANDLING", "STORAGE", "REEFER_POWER", "REEFER_PLUG", "EXTRA_YARD"].forEach(ct => { ["20GP", "40HC", "40RF", "45HC"].forEach(eq => { const cg = eq === "40RF" ? "Reefer" : eq === "45HC" ? "Dry" : "Dry"; // Simulate coverage status const h = (tc.charCodeAt(2) + ct.charCodeAt(0) + eq.charCodeAt(0)) % 10; let status; if (h < 7) status = "Present"; else if (h < 9) status = "Missing"; else status = "Expiring"; expected.push({ terminal: tc, costType: ct, equipment: eq, cargo: cg, status, lastUpdated: status === "Missing" ? null : "2025-0" + ((h%4)+1) + "-1" + h, expiryDays: status === "Expiring" ? (h * 3 + 7) : null, }); }); }); }); return expected; })(); const COMPLETENESS_SUMMARY = (() => { const out = {}; COMPLETENESS.forEach(r => { if (!out[r.terminal]) out[r.terminal] = { total: 0, present: 0, missing: 0, expiring: 0 }; out[r.terminal].total++; out[r.terminal][r.status.toLowerCase()]++; }); return out; })(); // Expiry Alerts (within 60 days) const EXPIRY_ALERTS = [ { id: "R-10103", terminal: "CNTSN", terminalName: "Tianjin Xingang", costType: "Storage", equipment: "All", cargo: "Dry", rate: 28, ccy: "CNY", expiry: "2025-06-01", days: 18, focal: "Wang Lei" }, { id: "R-10218", terminal: "CNNGB", terminalName: "Ningbo Zhoushan", costType: "Reefer Plug In/Out", equipment: "40RF", cargo: "Reefer", rate: 120, ccy: "CNY", expiry: "2025-06-08", days: 25, focal: "Li Ming" }, { id: "R-10412", terminal: "CNSHA", terminalName: "Shanghai (Yangshan)", costType: "Extra Yard Work", equipment: "45HC", cargo: "Dry", rate: 350, ccy: "CNY", expiry: "2025-06-14", days: 31, focal: "Wang Lei" }, { id: "R-10501", terminal: "HKHKG", terminalName: "Hong Kong (Kwai Tsing)", costType: "CY Handling", equipment: "20GP", cargo: "Dry", rate: 310, ccy: "HKD", expiry: "2025-07-01", days: 48, focal: "Zhang Fang" }, { id: "R-10677", terminal: "SGSIN", terminalName: "Singapore (PSA)", costType: "Reefer Power", equipment: "40RF", cargo: "Reefer", rate: 48, ccy: "SGD", expiry: "2025-05-22", days: 8, focal: "P. Wijaya" }, { id: "R-10822", terminal: "MYPKG", terminalName: "Port Klang Westport", costType: "Storage", equipment: "All", cargo: "Dry", rate: 18, ccy: "MYR", expiry: "2025-06-05", days: 22, focal: "P. Wijaya" }, ]; // Quality Validation findings const VALIDATION_RESULTS = [ { rule: "QV-02", name: "Date Range Overlap", severity: "Error", terminal: "CNTAO", target: "R-10089 / R-10135 · CY Handling · 20GP", detail: "R-10089 effective 2025-01-01→2025-12-31 overlaps R-10135 effective 2025-06-01→2026-05-31" }, { rule: "QV-01", name: "Duplicate Rate", severity: "Error", terminal: "MYPKG", target: "R-10822 / R-10823 · Storage", detail: "Two active records with identical Terminal + Cost Type + Unit" }, { rule: "QV-07", name: "ROE Missing for Currency", severity: "Error", terminal: "IDJKT", target: "IDR/USD ROE", detail: "No active ROE record covers 2025-05-01 → 2025-12-31" }, { rule: "QV-03", name: "Date Gap", severity: "Warning", terminal: "VNSGN", target: "R-10412 · Reefer Power", detail: "Gap between 2025-03-31 expiry and 2025-05-01 successor — no active rate Apr 1–30" }, { rule: "QV-05", name: "Zero / Negative Rate", severity: "Warning", terminal: "BDCGP", target: "R-10918 · VGM Weighing", detail: "Rate value = 0.00 BDT — likely data entry error" }, { rule: "QV-06", name: "Missing Mandatory Tier", severity: "Warning", terminal: "NZAKL", target: "Storage · Day 4+ tier", detail: "Storage tier 'Day 1–3' present but no successor tier defined" }, { rule: "QV-08", name: "Orphan Terminal", severity: "Warning", terminal: "—", target: "R-09988 · references CNXMG", detail: "Terminal code CNXMG was deactivated 2025-02-14; orphan rate exists" }, ]; const VALIDATION_RULES = [ { id: "QV-01", name: "Duplicate Rate", severity: "Error", desc: "Two or more active rate records with identical Terminal + Cost Type + Equipment + Cargo + Unit within overlapping date ranges." }, { id: "QV-02", name: "Date Range Overlap", severity: "Error", desc: "Same combination has two records where one effective date falls within another record's effective–expiry window." }, { id: "QV-03", name: "Date Gap", severity: "Warning", desc: "A gap exists between the expiry of one record and the effective date of its successor for the same combination." }, { id: "QV-04", name: "Inverted Dates", severity: "Error", desc: "Expiry date is earlier than or equal to the effective date on the same record." }, { id: "QV-05", name: "Zero / Negative Rate", severity: "Warning", desc: "Rate value is zero or negative (likely a data entry error)." }, { id: "QV-06", name: "Missing Mandatory Tier", severity: "Warning", desc: "A tiered cost type has a Day 1 tier but is missing subsequent tier definitions." }, { id: "QV-07", name: "ROE Missing for Currency", severity: "Error", desc: "The rate's currency has no active ROE record covering the rate's effective date range." }, { id: "QV-08", name: "Orphan Terminal", severity: "Warning", desc: "Rate record references a terminal code that is no longer active in the terminal metadata." }, ]; // TCO data — per-terminal cost breakdown for current month const TCO = (() => { const out = []; TERMINALS.forEach((t, ti) => { const monthlyTEU = VOLUME.rows.filter(v => v.terminal === t.code && v.period === "2025-05")[0]?.teu || 2000; // Cost type breakdown (% allocation) const allocation = { "CY Handling": 0.62, "Storage": 0.14, "Reefer": 0.09, "Other Behavior": 0.15, }; const baseUsdPerTeu = 88 + ((ti * 47) % 35); const gross = monthlyTEU * baseUsdPerTeu; const reb = REBATES.find(r => r.terminal === t.code); const rebateMonthly = reb ? reb.accruedYTD / 5 : 0; const net = gross - rebateMonthly; const breakdown = Object.fromEntries(Object.entries(allocation).map(([k, v]) => [k, gross * v])); out.push({ terminal: t.code, terminalName: t.name, region: t.region, area: t.area, monthlyTEU, gross, grossPerTEU: gross / monthlyTEU, rebate: rebateMonthly, rebateYield: rebateMonthly ? (rebateMonthly / gross) * 100 : 0, net, netPerTEU: net / monthlyTEU, breakdown, momChange: -1.5 + ((ti * 19) % 50) / 10, }); }); return out.sort((a, b) => a.netPerTEU - b.netPerTEU); })(); Object.assign(window, { TERMINALS, COST_TYPES, CHARGE_UNITS, ROE, RATES, REGIONS, PERSONAS, PERMS, AUDIT, ACCESS_REQUESTS, TERMINAL_BY_CODE, EQUIPMENT, CARGO_TYPES, MOVE_TYPES, VOLUME, MVC, YTD_VOLUME, REBATES, SETTLEMENTS, COMPLETENESS, COMPLETENESS_SUMMARY, EXPIRY_ALERTS, VALIDATION_RESULTS, VALIDATION_RULES, TCO, });