68 lines
3.3 KiB
Python
68 lines
3.3 KiB
Python
from pathlib import Path
|
|
from lxml import etree
|
|
from test_est_rea_parity import run
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SCHEMA = next((ROOT / "resources/knowledge").rglob("조달청_공사원가호환규정.xsd"))
|
|
|
|
|
|
def test_c3r_export_validates_against_the_supplied_schema_and_preserves_prices():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.name='C3R test';p.options.SourceRefresh=false;
|
|
p.tables.StuffcDat=[{PkID:1,Code:'M1',Name:'material',TC:100,GC:100}];
|
|
p.tables.LaborcDat=[{PkID:1,Code:'L1',Name:'labor',TC:50,NC:50}];
|
|
p.tables.EstMainDat=[{PkID:1,Code:'M1',LinkIndex:5,Name:'material',GN:2,GU:100},{PkID:2,Code:'L1',LinkIndex:6,Name:'labor',GN:3,NU:50},{PkID:3,LinkIndex:54}];
|
|
p.tables.Wonga=[{Gubun:'G',Name:'material',BaseField:'GC'}, {Gubun:'N',Name:'labor',BaseField:'NC'},{Gubun:'T',Name:'total',VSusic:'G+N'}];
|
|
return EstC3r.output(EstNative.calculate(p),{company:'test',kind:'토목공사',date:'2026-11-06'});
|
|
})()""",
|
|
)
|
|
schema = etree.XMLSchema(etree.parse(str(SCHEMA)))
|
|
root = etree.fromstring(result["xml"].encode("utf-8"))
|
|
assert schema.validate(root), str(schema.error_log)
|
|
assert root.findtext(".//세부공종/재료비") == "200"
|
|
assert root.findtext(".//세부공종/수량") == "2"
|
|
assert root.findtext(".//작성정보/파일검증여부") == "false"
|
|
assert result["warnings"] == []
|
|
|
|
|
|
def test_xml_excluded_rows_do_not_inflate_group_totals_and_invalid_codes_are_rejected():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.name='test';p.tables.StuffcDat=[{Code:'M1',Name:'material',TC:100}];p.tables.EstMainDat=[
|
|
{Code:'M1',Name:'normal',LinkIndex:5,GN:2,GU:100,GC:200,TC:200},
|
|
{Code:'X1',Name:'excluded',GN:1,GC:999,TC:999,CalcIndex:3},{LinkIndex:54}];
|
|
const meta={company:'test',kind:'토목공사',date:'2026-11-06'};
|
|
const result=EstC3r.output(p,meta);let blocked=false;
|
|
p.tables.EstMainDat[0].Code='bad code';try{EstC3r.output(p,meta)}catch{blocked=true}
|
|
return {...result,blocked};
|
|
})()""",
|
|
)
|
|
root = etree.fromstring(result["xml"].encode("utf-8"))
|
|
assert root.findtext(".//내역서/재료비") == "200"
|
|
assert root.findall(".//세부공종")[1].findtext("계산제외") == "true"
|
|
assert result["blocked"]
|
|
|
|
|
|
def test_xml_keeps_parent_and_child_groups_instead_of_dropping_empty_parent_headers():
|
|
result = run(
|
|
"math",
|
|
"""(()=>{
|
|
const p=EstNative.empty();p.name='test';p.tables.EstMainDat=[
|
|
{Code:'ROOT',Name:'parent',Level:3,GC:200,TC:200},
|
|
{Code:'CHILD',Name:'child',Level:1,GC:200,TC:200},
|
|
{Code:'FIX',Name:'fixed',GN:1,GC:200,TC:200,CalcIndex:1},{LinkIndex:54}];
|
|
return EstC3r.output(p,{company:'test',kind:'토목공사',date:'2026-11-06'});
|
|
})()""",
|
|
)
|
|
root = etree.fromstring(result["xml"].encode("utf-8"))
|
|
schema = etree.XMLSchema(etree.parse(str(SCHEMA)))
|
|
assert schema.validate(root), str(schema.error_log)
|
|
groups = root.findall(".//내역서")
|
|
assert [group.findtext("내역서번호") for group in groups] == ["01", "0101"]
|
|
assert [group.findtext("재료비") for group in groups] == ["200", "200"]
|
|
assert len(groups[0].findall("세부공종")) == 0
|
|
assert len(groups[1].findall("세부공종")) == 1
|