128 lines
5.2 KiB
Python
128 lines
5.2 KiB
Python
from test_est_rea_parity import run
|
|
|
|
|
|
def test_review_summary_updates_the_print_document_and_active_settings():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const handlers={},p=EstNative.empty();p.printSettings={form:'173',notes:'old'};
|
|
globalThis.document={addEventListener:(name,fn)=>handlers[name]=fn};
|
|
globalThis.EstApp={state:{project:p},change:fn=>fn(),render:()=>{}};
|
|
EstReview.install();handlers.change({target:{dataset:{reviewSummary:''},value:'review summary'}});
|
|
return {document:p.documents['173'],notes:p.printSettings.notes};
|
|
})()""",
|
|
)
|
|
assert result == {"document": "review summary", "notes": "review summary"}
|
|
|
|
|
|
def test_review_rejects_unallocated_fixed_amounts_and_ambiguous_targets():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.tables.EstMainDat=[
|
|
{Name:'fixed',PkID:1,GN:1,TC:100,CalcIndex:1},
|
|
{Name:'first',Code:'A',GN:1,GU:10},{Name:'second',Code:'A',GN:1,GU:20}];
|
|
p.contractReview={edits:{'row:A':{GU:999}}};
|
|
const out=EstReview.calculate(p);let rejected=false;
|
|
try{EstReview.copy(p)}catch{rejected=true}
|
|
return {errors:out.errors,rejected,units:out.reviewed.tables.EstMainDat.slice(1).map(row=>row.GU)};
|
|
})()""",
|
|
)
|
|
assert len(result["errors"]) == 2 and result["rejected"]
|
|
assert result["units"] == [10, 20]
|
|
|
|
|
|
def test_review_recalculates_user_inputs_and_opens_independent_copy():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.name='contract';p.id='123456789012345678901234';
|
|
p.options.SourceRefresh=false;p.tables.EstMainDat=[
|
|
{PkID:1,Code:'',Name:'normal',GN:10,GU:100},
|
|
{PkID:2,Code:'',Name:'fixed',GN:1,GC:100,TC:100,CalcIndex:1},
|
|
{LinkIndex:54}];
|
|
p.tables.Wonga=[{Gubun:'D',BaseField:'TC'},
|
|
{Gubun:'V',VSusic:'D*0.1'},{Gubun:'T',LinkIndex:55,VSusic:'D+V'}];
|
|
const q=EstNative.calculate(p);q.contractReview={edits:{'row:1':{GN:2,GU:80,Reason:'checked'},'row:2':{GC:20}}};
|
|
const before=JSON.stringify(q),review=EstReview.calculate(q),copy=EstReview.copy(q);
|
|
const same=JSON.stringify(q)===before;copy.tables.EstMainDat[0].GN=99;
|
|
return {review,same,original:q.tables.EstMainDat[0].GN,copy};
|
|
})()""",
|
|
)
|
|
assert result["same"] and result["original"] == 10
|
|
assert result["review"]["errors"] == []
|
|
assert result["review"]["before"] == 1210
|
|
assert result["review"]["after"] == 198
|
|
assert result["review"]["reviewed"]["tables"]["EstMainDat"][1]["TC"] == 20
|
|
assert "id" not in result["copy"]
|
|
assert "contractReview" not in result["copy"]
|
|
|
|
|
|
def test_review_rejects_invalid_and_stale_inputs():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.tables.EstMainDat=[{PkID:1,Code:'A',GN:1,GU:10}];
|
|
const invalid=[];for(const edit of [{GN:'bad'},{GN:Infinity},{unrelated:1}]){
|
|
p.contractReview={edits:{'row:1':edit}};
|
|
try{EstModel.validate(p);invalid.push(false)}catch{invalid.push(true)}
|
|
}
|
|
p.contractReview={edits:{'row:missing':{GN:2}}};
|
|
let rejected=false;try{EstReview.copy(p)}catch{rejected=true}
|
|
return {invalid,rejected};
|
|
})()""",
|
|
)
|
|
assert result["invalid"] == [True, True, True]
|
|
assert result["rejected"]
|
|
|
|
|
|
def test_review_summary_print_contains_totals_and_item_differences():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.tables.EstMainDat=[{PkID:1,Code:'',Name:'item',GN:2,GU:100}];
|
|
p.contractReview={edits:{'row:1':{GN:1,GU:80,Reason:'quantity reviewed'}}};return EstForms.data(171,p);
|
|
})()""",
|
|
)
|
|
assert result["errors"] == []
|
|
assert [result["rows"][0][key] for key in ["originalTC", "TC", "difference"]] == [
|
|
200,
|
|
80,
|
|
-120,
|
|
]
|
|
assert result["rows"][1]["Name"] == "item"
|
|
assert result["rows"][1]["difference"] == -120
|
|
assert result["rows"][1]["Reason"] == "quantity reviewed"
|
|
|
|
|
|
def test_review_reset_one_row_keeps_other_inputs():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const handlers={},p=EstNative.empty();
|
|
p.contractReview={edits:{'row:1':{GU:80,Reason:'first'},'row:2':{GN:3,Reason:'second'}}};
|
|
globalThis.document={addEventListener:(name,fn)=>handlers[name]=fn};
|
|
globalThis.EstApp={state:{project:p},change:fn=>fn(),render:()=>{}};
|
|
EstReview.install();
|
|
const click=key=>handlers.click({target:{closest:s=>s==='[data-review-reset]'?{dataset:{reviewReset:key}}:null}});
|
|
click('row:1');const after=structuredClone(p.contractReview);click('row:2');
|
|
return {after,removed:!Object.hasOwn(p,'contractReview')};
|
|
})()""",
|
|
)
|
|
assert result["after"]["edits"] == {"row:2": {"GN": 3, "Reason": "second"}}
|
|
assert result["removed"]
|
|
|
|
|
|
def test_fixed_review_preserves_amount_for_reason_or_quantity_only():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.tables.EstMainDat=[{PkID:1,Name:'fixed',GN:1,TC:100,CalcIndex:1}];
|
|
return [{Reason:'checked'},{GN:3},{GC:20}].map(edit=>{
|
|
p.contractReview={edits:{'row:1':edit}};
|
|
return EstReview.calculate(p).reviewed.tables.EstMainDat[0].TC;
|
|
});
|
|
})()""",
|
|
)
|
|
assert result == [100, 100, 20]
|