from test_est_rea_parity import run def test_escalation_distinguishes_repeated_codes_without_row_ids(): result = run( "math", """(()=>{ const p=EstNative.empty();p.options.SourceRefresh=false;p.options.EscDesignTotal=1000; p.tables.EstMainDat=[{Code:'A',Name:'first',GN:10,GU:80}, {Code:'A',Name:'second',GN:20,GU:50},{LinkIndex:54}]; const q=EstBusiness.baseline(EstNative.calculate(p)); Object.assign(q.tables.EstMainDat[0],{AGU:100,GU:120,EscActual:2}); Object.assign(q.tables.EstMainDat[1],{AGU:100,GU:120,EscActual:5}); return EstEscalation.calculate(q); })()""", ) assert [row["EscApplied"] for row in result["rows"][:2]] == [8, 15] assert [row["EGU"] for row in result["rows"][:2]] == [16, 10] assert [row["ContractGU"] for row in result["rows"][:2]] == [80, 50] assert result["excludedTotal"] == 410 def test_escalation_matches_reordered_duplicate_codes_to_original_rows(): result = run( "math", """(()=>{ const p=EstNative.empty();p.options.SourceRefresh=false;p.options.EscDesignTotal=1000; p.tables.EstMainDat=[{Code:'A',Name:'first',GN:10,GU:80}, {Code:'A',Name:'second',GN:20,GU:50},{LinkIndex:54}]; const q=EstBusiness.baseline(EstNative.calculate(p)); [q.tables.EstMainDat[0],q.tables.EstMainDat[1]]=[q.tables.EstMainDat[1],q.tables.EstMainDat[0]]; Object.assign(q.tables.EstMainDat[0],{AGU:100,GU:120,EscActual:5}); Object.assign(q.tables.EstMainDat[1],{AGU:100,GU:120,EscActual:2}); return EstEscalation.calculate(JSON.parse(JSON.stringify(q))); })()""", ) assert [row["ContractGU"] for row in result["rows"][:2]] == [50, 80] assert [row["EscApplied"] for row in result["rows"][:2]] == [15, 8] assert result["excludedTotal"] == 410 def test_progress_exclusions_preserve_new_rows_and_reject_ambiguous_keys(): result = run( "math", """(()=>{ const p=EstNative.empty();p.tables.EstMainDat=[{PkID:1,Code:'A',EscProgress:9}, {PkID:2,Code:'B',EscProgress:7}]; const before=JSON.stringify(p), saved={rows:[{PkID:1,Code:'A',TotalGN:3}]}; const updates=EstBusiness.progressExclusions(p,saved);let blocked=0; try{EstBusiness.progressExclusions(p,{rows:[{Code:'A',TotalGN:1},{Code:'A',TotalGN:2}]})}catch{blocked++} const q=structuredClone(p);q.tables.EstMainDat=[{Code:'A'},{Code:'A'}]; try{EstBusiness.progressExclusions(q,{rows:[{Code:'A',TotalGN:1}]})}catch{blocked++} return {updates,blocked,same:before===JSON.stringify(p)}; })()""", ) assert result == {"updates": [{"index": 0, "value": 3}], "blocked": 2, "same": True} def test_escalation_preserves_explicit_zero_total_and_falls_back_only_without_wonga(): result = run( "math", """(()=>{ const p=EstNative.empty();p.options.SourceRefresh=false;p.options.EscDesignTotal=1000; p.tables.EstMainDat=[{PkID:1,Code:'R',GN:10,GU:100,AGU:100,EscActual:3},{LinkIndex:54}]; p.tables.Wonga=[{Gubun:'D',BaseField:'TC'},{Gubun:'T',LinkIndex:55,VSusic:'0'}]; const zero=EstBusiness.escalation(p);p.tables.Wonga=[]; return {zero,absent:EstBusiness.escalation(p)}; })()""", ) assert result["zero"]["errors"] == [] assert result["zero"]["contractTotal"] == 0 assert result["zero"]["adjustedTotal"] == 0 assert result["zero"]["excludedTotal"] == 0 assert result["absent"]["contractTotal"] == 1000 assert result["absent"]["excludedTotal"] == 300 def test_escalation_uses_design_denominator_and_all_price_branches(): result = run( "math", """(()=>{ const p=EstNative.empty();p.options.SourceRefresh=false; p.tables.EstMainDat=[{PkID:1,Code:'R',GN:10,GU:80},{LinkIndex:54}]; p.tables.Wonga=[{Gubun:'G',Name:'direct',BaseField:'GC'}, {Gubun:'T',Name:'total',LinkIndex:55,VSusic:'G'}]; const q=EstBusiness.baseline(EstNative.calculate(p)); Object.assign(q.tables.EstMainDat[0],{AGU:100,GU:120,EscPlanned:2,EscActual:3,EscProgress:1}); const before=JSON.stringify(q),output=EstBusiness.escalation(q); const cases=[[100,80,120],[80,100,120],[100,80,90],[100,80,60]].map(([a,c,b])=>{ const x=structuredClone(q);x.tables.EstMainDat[0].AGU=a;x.tables.EstMainDat[0].GU=b; x.baseline.tables.EstMainDat[0].GU=c;return EstBusiness.escalation(x).rows[0]; }); return {output,cases,same:before===JSON.stringify(q)}; })()""", ) assert result["same"] output = result["output"] assert output["errors"] == [] assert output["designTotal"] == 1000 assert output["contractTotal"] == 800 assert output["adjustedTotal"] == 960 assert output["excludedTotal"] == 240 assert output["applied"] == 560 assert output["rate"] == 16 assert output["adjustment"] == 89 assert [row["EGU"] for row in result["cases"]] == [16, 20, 0, 0] def test_native_contract_columns_and_manual_exclusions_and_percent_units(): result = run( "math", """(()=>{ const p=EstNative.empty();p.options.SourceRefresh=false; p.tables.EstMainDat=[{PkID:1,Code:'R',GN:50,GN_:50,Unite:'%',GU:120,GU_:80,AGU:100, EscAuto:false,EscManualQuantity:10,EscPlanned:40},{LinkIndex:54}]; return EstBusiness.escalation(p); })()""", ) assert result["errors"] == [] assert result["rows"][0]["EscExcluded"] == 10 assert result["rows"][0]["EscApplied"] == 40 assert result["rows"][0]["GC"] == 48 assert result["contractTotal"] == 40 assert result["excludedTotal"] == 8 assert result["designTotal"] == 50 def test_fixed_contract_amount_excludes_only_the_selected_quantity(): result = run( "math", """(()=>{ const p=EstNative.empty();p.options.SourceRefresh=false; p.tables.EstMainDat=[{PkID:1,Code:'R',GN:10,GC:1000,TC:1000,CalcIndex:1,EscActual:3}, {LinkIndex:54}];p.options.EscDesignTotal=1200; return EstBusiness.escalation(p); })()""", ) assert result["errors"] == [] assert result["contractTotal"] == 1000 assert result["excludedTotal"] == 300 assert result["applied"] == 700 assert result["rate"] == 0 def test_contract_and_bid_file_import_follow_native_record_order_and_preserve_working_file(): result = run( "math", """(()=>{ const p=EstNative.empty();p.id='123456789012345678901234';p.options.SourceRefresh=false; p.tables.EstMainDat=[{PkID:7,Code:'R',GN:10,GU:120},{PkID:8,LinkIndex:54}]; const incoming=structuredClone(p);incoming.name='contract'; incoming.tables.EstMainDat[0].PkID=1;incoming.tables.EstMainDat[0].GU=80; const before=JSON.stringify(p),q=EstBusiness.importContract(p,incoming); incoming.tables.EstMainDat[0].GU=100; const r=EstBusiness.importBid(q,incoming); const output=EstBusiness.escalation(r); incoming.tables.EstMainDat[0].Code='different';let rejected=false; try{EstBusiness.importContract(p,incoming);}catch{rejected=true;} return {r,output,rejected,same:before===JSON.stringify(p)}; })()""", ) assert result["same"] and result["rejected"] assert result["r"]["id"] == "123456789012345678901234" assert result["r"]["tables"]["EstMainDat"][0]["GU"] == 120 assert result["r"]["baseline"]["tables"]["EstMainDat"][0]["PkID"] == 7 assert result["output"]["contractTotal"] == 800 assert result["output"]["designTotal"] == 1000 assert result["output"]["rate"] == 16