@@ -0,0 +1,363 @@
""" 184-2 B09 설계내역서 자유 편집 — 셈 · 저장(`user.bill` v2 덮개 · 계약 = `Calc_Bill.py` 머리).
- 덮개 없음 · 굳힘(보이는 줄 키 · 부모 · 차례만) = 기본 표 그대로 ·
번호 자동(1 · 1.1 · 관급 없음)
- 자동 줄 칸 덮기(이름 · 규격 · 단위 · 수량 · 연결) = 그 값 + auto_ {칸} · null = 빈칸 ·
안 고친 칸 = B08 따라감
- gone = 안 살아남(「연결 없음」에도 없음) · 저장에 없는 자동 줄 = 기본 부모 끝 「새 자동 줄」 ·
원천이 안 낸 키 = 안 보임
- 새 1단 공종 = 직접비(sums) · 관급 자재 줄 = 관급자재대 밖 못 감 · 조달수수료 = 관급자재대 끝 ·
깊이 5 · 돎 · 옛 꼴 = 같은 표의 v2 · 구조물 블록 키 · 자동 줄 로직 연결 → sg_hand · 거울 · 다듬기
"""
import copy
import json
import re
import subprocess
import sys
from pathlib import Path
ROOT = Path ( __file__ ) . resolve ( ) . parents [ 2 ]
if str ( ROOT ) not in sys . path :
sys . path . insert ( 0 , str ( ROOT ) )
from B09_Estimation import B09_Estimation_Sangeun as sg # noqa: E402
from B09_Estimation import B09_Estimation_Store as store # noqa: E402
from B09_Estimation . B09_Estimation_Calc_Bill import compute_estimation # noqa: E402
IMPORTS = re . compile ( r " ^import[^;]*; \ n " , re . MULTILINE )
ITEMS = [
{ " key " : " earth:1 " , " section " : " 1.1 " , " name " : " 규준틀 " , " unit " : " 개소 " , " qty " : 14 ,
" ref " : { " tab " : " dg_list " , " key " : " B00194 " } } ,
{ " key " : " earth:4 " , " section " : " 1.2 " , " name " : " 절토(토사) " , " spec " : " 기계 " , " unit " : " ㎥ " ,
" qty " : 10 , " ref " : { " tab " : " sg_list " , " key " : " D01341 " } } ,
{ " key " : " earth:5 " , " section " : " 1.2 " , " name " : " 절토(연암) " , " unit " : " ㎥ " , " qty " : 9 , " ref " : None ,
" why " : " 조합 밖 토공 산근 — 연결 없음 " } ,
{ " key " : " haul:1 " , " section " : " 3 " , " name " : " 운반 " , " unit " : " ㎥ " , " qty " : 2 ,
" ref " : { " tab " : " sg_list " , " key " : " D01341 " } } ,
] # fmt: skip
HOPYO = {
" B00194 " : { " labor " : 21936 , " material " : 3885 , " expense " : 0 } ,
" D01341 " : { " labor " : 1116 , " material " : 360 , " expense " : 463 } ,
}
MATERIALS = [
{ " key " : " b08:pipe_800 " , " name " : " 파형강관 " , " spec " : " Φ800 " , " unit " : " M " , " origin " : " B08 " ,
" prices " : { " 관급 " : 157000 } , " qty " : 212 } ,
{ " key " : " b08:sand " , " name " : " 골재 " , " spec " : " 모래 " , " unit " : " ㎥ " , " origin " : " B08 " ,
" prices " : { " 물가정보 " : 30000 } , " qty " : 16 } ,
] # fmt: skip
INPUTS = { " materials " : MATERIALS , " bill " : { " items " : ITEMS } , " hopyo " : HOPYO }
BASE = {
" materials " : { " b08:pipe_800 " : { " supply " : " 관급 " } , " b08:sand " : { " supply " : " 별도 " } } ,
" estimate " : { " procurement_fee_pct " : 0.54 } ,
}
BOOKS = {
" daega " : [ { " no " : 3 , " key " : " DG:a " , " labor " : 1000 , " material " : 200 , " expense " : 30 ,
" sum " : 1230 } ] ,
" sg_list " : [ { " no " : 2 , " key " : " SG:new " , " labor " : 10 , " material " : 1 , " expense " : 0 , " sum " : 11 } ] ,
" sg_hand " : { " earth:5 " : " SG:new " } ,
} # fmt: skip
DG = { " tab " : " dg " , " key " : " DG:a " }
MAT = " mat:b08:pipe_800 "
def _calc ( bill = None , inputs = INPUTS , price_of = None ) :
user = { * * BASE , * * ( { " bill " : bill } if bill is not None else { } ) }
return compute_estimation ( inputs , user , price_of , BOOKS )
def _rows ( sheets ) :
return { row [ " key " ] : row for row in sheets [ " bill " ] [ " rows " ] }
def _keys ( sheets ) :
return [ row [ " key " ] for row in sheets [ " bill " ] [ " rows " ] ]
def _freeze ( sheets , * * more ) :
""" 화면 첫 손질 굳힘 — 보이는 줄의 키 · 부모 · 차례(새 줄은 모든 칸) · fee 뺌. """
rows = [ ]
for r in sheets [ " bill " ] [ " rows " ] :
if r [ " key " ] == " fee " :
continue
row = { " key " : r [ " key " ] , " parent " : r [ " parent " ] }
if r . get ( " hand " ) :
row . update ( { k : r [ k ] for k in ( " name " , " spec " , " unit " , " qty " , " ref " ) } )
row . update ( { " kind " : " group " } if r [ " kind " ] == " group " else { } )
rows . append ( row )
return { " v " : 2 , " rows " : rows , " gone " : [ ] , * * more }
def _put ( bill , key , * * cover ) :
""" 굳힌 덮개의 한 줄 칸 고침 · 부모 바꿈. """
out = copy . deepcopy ( bill )
next ( r for r in out [ " rows " ] if r [ " key " ] == key ) . update ( cover )
return out
def test_덮개_없음_빈_굳힘_기본_표_번호 ( ) :
plain = _calc ( )
assert _calc ( { } ) [ " bill " ] == plain [ " bill " ] # [초기화] = bill 지움(빈 v2 는 다듬기가 버림)
assert _calc ( _freeze ( plain ) ) [ " bill " ] == plain [ " bill " ] # 굳혀도 표 · 합 · 연결 없음 그대로
rows = _rows ( plain )
got = [ ( r [ " key " ] , r [ " no " ] , r [ " name " ] , r [ " level " ] , r [ " parent " ] ) for r in plain [ " bill " ] [ " rows " ]
if r [ " kind " ] == " title " ] [ : 3 ] # fmt: skip
assert got == [ ( " sec:1 " , " 1 " , " 토공사 " , 1 , None ) , ( " sec:1.1 " , " 1.1 " , " 준비공 " , 2 , " sec:1 " ) ,
( " sec:1.2 " , " 1.2 " , " 절토 " , 2 , " sec:1 " ) ] # fmt: skip
assert ( rows [ " sec:4 " ] [ " no " ] , rows [ " sec:G " ] [ " no " ] , rows [ " fee " ] [ " no " ] ) == ( " 4 " , " " , " " )
assert ( rows [ " earth:4 " ] [ " auto " ] , rows [ " earth:4 " ] [ " parent " ] , rows [ " earth:4 " ] [ " cost " ] ) == (
True , " sec:1.2 " , " direct " ) # fmt: skip
assert ( rows [ MAT ] [ " cost " ] , rows [ " fee " ] [ " cost " ] , _keys ( plain ) [ - 1 ] ) == ( " supply " , " supply " , " fee " )
assert not any ( k . startswith ( " auto_ " ) for r in rows . values ( ) for k in r )
def test_자동_줄_칸_덮기_자동값_남김 ( ) :
bill = _put (
_freeze ( _calc ( ) ) , " earth:4 " , name = " 절토 고침 " , spec = None , unit = " m3 " , qty = 100 , ref = DG
)
row = _rows ( _calc ( bill ) ) [ " earth:4 " ]
assert ( row [ " name " ] , row [ " spec " ] , row [ " unit " ] , row [ " qty " ] ) == ( " 절토 고침 " , " " , " m3 " , 100 )
assert ( row [ " auto_name " ] , row [ " auto_spec " ] , row [ " auto_unit " ] , row [ " auto_qty " ] ) == (
" 절토(토사) " , " 기계 " , " ㎥ " , 10 ) # fmt: skip
assert ( row [ " ref " ] , row [ " auto_ref " ] , row [ " note " ] ) == ( DG , { " tab " : " sg_list " , " key " : " D01341 " } ,
" 대가3 " ) # fmt: skip
assert ( row [ " labor " ] , row [ " sum " ] ) == ( 100000 , 123000 ) # 대가3 1,230 × 100
# 제목 이름 덮개 · 제목 = 이름만(수량 덮개 안 받음)
title = _rows ( _calc ( _put ( bill , " sec:1.2 " , name = " 절토공 " , qty = 5 ) ) ) [ " sec:1.2 " ]
assert ( title [ " name " ] , title [ " auto_name " ] , title [ " no " ] , " auto_qty " in title ) == (
" 절토공 " , " 절토 " , " 1.2 " , False ) # fmt: skip
def test_B08_바뀜_안_고친_칸_따라감_고친_칸_지킴_null_빈칸 ( ) :
bill = _put ( _freeze ( _calc ( ) ) , " earth:4 " , qty = 100 )
bill = _put ( bill , " earth:1 " , qty = None )
changed = copy . deepcopy ( INPUTS )
for item in changed [ " bill " ] [ " items " ] :
item [ " qty " ] = item [ " qty " ] * 2
item [ " name " ] = item [ " name " ] + " * "
sheets = _calc ( bill , changed )
rows = _rows ( sheets )
assert ( rows [ " earth:4 " ] [ " qty " ] , rows [ " earth:4 " ] [ " auto_qty " ] , rows [ " earth:4 " ] [ " name " ] ) == (
100 , 20 , " 절토(토사)* " ) # fmt: skip
assert ( rows [ " earth:5 " ] [ " qty " ] , rows [ " haul:1 " ] [ " qty " ] ) == ( 18 , 4 ) # 안 고친 줄 = 따라감
assert rows [ " earth:1 " ] [ " qty " ] is None and rows [ " earth:1 " ] [ " sum " ] is None # 일부러 빈칸
assert ( " earth:1 " , " 수량 연결 없음 " ) in { ( g [ " key " ] , g [ " why " ] ) for g in sheets [ " gaps " ] }
def test_gone_안_살아남_새_자동_줄_기본_부모_끝_원천_사라짐_안_보임 ( ) :
bill = _freeze ( _calc ( ) , gone = [ " earth:5 " , " sec:G " , MAT ] ) # sec:G · 자재 줄 = 못 지움
bill [ " rows " ] . append ( { " key " : " earth:99 " , " parent " : " sec:1.2 " , " qty " : 3 } ) # 원천 없음
more = copy . deepcopy ( INPUTS )
more [ " bill " ] [ " items " ] + = [
{ " key " : " earth:5 " , " section " : " 1.2 " , " name " : " 되살아남? " , " unit " : " ㎥ " , " qty " : 1 } ,
{ " key " : " earth:6 " , " section " : " 1.2 " , " name " : " 암발파 " , " unit " : " ㎥ " , " qty " : 4 , " ref " : None } ,
]
sheets = _calc ( bill , more )
keys = _keys ( sheets )
assert " earth:5 " not in keys and " earth:99 " not in keys
assert { " sec:G " , MAT } < = set ( keys )
assert " earth:5 " not in { g [ " key " ] for g in sheets [ " gaps " ] } # 지운 줄 = 연결 없음에도 없음
at = keys . index ( " earth:6 " )
assert keys [ at - 1 ] == " earth:4 " and keys [ at + 1 ] == " sec:1.3 " # 절토 끝
assert _rows ( sheets ) [ " earth:6 " ] [ " note " ] == " 새 자동 줄 "
# 제목을 지웠으면 새 자동 줄 = 표 끝 맨 위
gone = _calc ( _freeze ( _calc ( ) , gone = [ " sec:1.2 " , " earth:4 " , " earth:5 " ] ) , more )
assert ( _keys ( gone ) [ - 1 ] , _rows ( gone ) [ " earth:6 " ] [ " parent " ] ) == ( " earth:6 " , None )
def test_새_1단_공종_직접비_번호_옮김_들여_내어 ( ) :
plain = _calc ( )
bill = _freeze ( plain )
keys = [ r [ " key " ] for r in bill [ " rows " ] ]
at = keys . index ( " sec:G " ) # 4 자재대 뒤 · 관급자재대 앞에 새 1단 공종
bill [ " rows " ] [ at : at ] = [
{ " key " : " hand:g " , " kind " : " group " , " cost " : " direct " , " name " : " 부대공 " , " spec " : " " ,
" unit " : " " , " qty " : None , " ref " : None } ,
{ " key " : " hand:a " , " parent " : " hand:g " , " name " : " a " , " spec " : " " , " unit " : " ㎡ " , " qty " : 10 ,
" ref " : DG } ,
{ " key " : " hand:s " , " parent " : " hand:g " , " kind " : " group " , " name " : " 소공종 " , " spec " : " " ,
" unit " : " " , " qty " : None , " ref " : None } ,
] # fmt: skip
sheets = _calc ( bill )
rows = _rows ( sheets )
g = rows [ " hand:g " ]
assert ( g [ " no " ] , g [ " level " ] , g [ " cost " ] , g [ " sum " ] , g [ " section " ] ) == ( " 5 " , 1 , " direct " , 12300 ,
None ) # fmt: skip
assert ( rows [ " hand:s " ] [ " no " ] , rows [ " hand:a " ] [ " no " ] ) == ( " 5.1 " , " " ) # 레벨 2 묶음만 번호
totals = sheets [ " bill " ] [ " totals " ] [ " direct " ]
assert totals [ " labor " ] - plain [ " bill " ] [ " totals " ] [ " direct " ] [ " labor " ] == 10000
# 형제 차례 바꿈(위로 ↑) = 번호 따라감 · 들여(다른 묶음 아래) · 공종 제목도 옮김
up = copy . deepcopy ( bill )
keys = [ r [ " key " ] for r in up [ " rows " ] ]
up [ " rows " ] . insert ( keys . index ( " sec:1.1 " ) , up [ " rows " ] . pop ( keys . index ( " sec:1.2 " ) ) )
rows = _rows ( _calc ( up ) )
assert ( rows [ " sec:1.2 " ] [ " no " ] , rows [ " sec:1.1 " ] [ " no " ] ) == ( " 1.1 " , " 1.2 " )
moved = _put ( _put ( bill , " earth:4 " , parent = " sec:1.1 " ) , " sec:3 " , parent = " hand:g " )
rows = _rows ( _calc ( moved ) )
assert ( rows [ " earth:4 " ] [ " parent " ] , rows [ " earth:4 " ] [ " level " ] , rows [ " earth:4 " ] [ " section " ] ) == (
" sec:1.1 " , 3 , " 1.1 " ) # fmt: skip
assert ( rows [ " sec:3 " ] [ " level " ] , rows [ " sec:3 " ] [ " no " ] , rows [ " hand:s " ] [ " no " ] ) == ( 2 , " 4.1 " , " 4.2 " )
assert ( rows [ " sec:4 " ] [ " no " ] , rows [ " hand:g " ] [ " no " ] ) == ( " 3 " , " 4 " )
assert rows [ " sec:1.1 " ] [ " sum " ] == _rows ( plain ) [ " sec:1.1 " ] [ " sum " ] + _rows ( plain ) [ " earth:4 " ] [ " sum " ]
assert _calc ( moved ) [ " bill " ] [ " sums " ] == sheets [ " bill " ] [ " sums " ] # 옮겨도 직접비 합 같음
def test_관급_줄_관급자재대_밖_못_감_수수료_끝 ( ) :
plain = _calc ( )
bill = _put ( _freeze ( plain ) , MAT , parent = " sec:1 " )
bill [ " rows " ] . append ( { " key " : " hand:k " , " parent " : " sec:G " , " name " : " 관급 손 " , " spec " : " " ,
" unit " : " 개 " , " qty " : 10 , " ref " : DG } ) # fmt: skip
sheets = _calc ( bill )
rows = _rows ( sheets )
assert ( rows [ MAT ] [ " parent " ] , rows [ MAT ] [ " cost " ] ) == ( " sec:G " , " supply " )
assert _keys ( sheets ) [ - 3 : ] == [ MAT , " hand:k " , " fee " ] # 조달수수료 = 관급자재대 끝
net = 212 * 157000 + 2000 # + 손 줄 재료비 200 × 10
assert sheets [ " bill " ] [ " sums " ] [ " supply_net " ] == net
assert sheets [ " bill " ] [ " sums " ] [ " labor " ] == plain [ " bill " ] [ " sums " ] [ " labor " ] # 관급 = 직접비 밖
assert rows [ " fee " ] [ " material " ] == int ( net * 0.54 / 100 )
def test_깊이_5_돎_부모_바로잡기 ( ) :
bill = _freeze ( _calc ( ) )
chain = [ ( " hand:g1 " , " sec:3 " ) , ( " hand:g2 " , " hand:g1 " ) , ( " hand:g3 " , " hand:g2 " ) ,
( " hand:g4 " , " hand:g3 " ) , ( " hand:g5 " , " hand:g4 " ) , ( " hand:g6 " , " hand:g5 " ) ] # fmt: skip
for key , parent in chain :
bill [ " rows " ] . append ( { " key " : key , " parent " : parent , " kind " : " group " , " name " : key } )
bill [ " rows " ] . append ( { " key " : " hand:i " , " parent " : " hand:g6 " , " name " : " i " , " qty " : 1 , " ref " : DG } )
bill [ " rows " ] + = [
{ " key " : " hand:p " , " parent " : " hand:q " , " kind " : " group " , " name " : " p " } ,
{ " key " : " hand:q " , " parent " : " hand:p " , " kind " : " group " , " name " : " q " } ,
]
bill = _put ( _put ( bill , " sec:1 " , parent = " earth:4 " ) , " sec:G " , parent = " sec:1 " )
rows = _rows ( _calc ( bill ) )
got = [ ( k , rows [ k ] [ " level " ] , rows [ k ] [ " parent " ] ) for k in ( " hand:g4 " , " hand:g5 " , " hand:g6 " ,
" hand:i " ) ] # fmt: skip
assert got == [ ( " hand:g4 " , 5 , " hand:g3 " ) , ( " hand:g5 " , 5 , " hand:g3 " ) ,
( " hand:g6 " , 5 , " hand:g3 " ) , ( " hand:i " , 5 , " hand:g3 " ) ] # fmt: skip
assert rows [ " hand:g1 " ] [ " sum " ] == 1230 and rows [ " sec:3 " ] [ " sum " ] == rows [ " haul:1 " ] [ " sum " ] + 1230
assert ( rows [ " hand:p " ] [ " parent " ] , rows [ " hand:q " ] [ " parent " ] ) == ( None , " hand:p " ) # 돎 = 맨 위
assert ( rows [ " sec:1 " ] [ " parent " ] , rows [ " sec:G " ] [ " parent " ] ) == ( None , None ) # 항목 부모 · G 고정
#: 옛 꼴(166-2 수량 · 182 손 줄 after · parent)
OLD = {
" qty " : { " earth:4 " : 100 } ,
" rows " : [
{ " key " : " hand:g1 " , " section " : " 1.2 " , " after " : " earth:4 " , " kind " : " group " , " name " : " 묶음 " } ,
{ " key " : " hand:a " , " section " : " 1.2 " , " after " : " hand:g1 " , " parent " : " hand:g1 " , " name " : " a " ,
" unit " : " ㎡ " , " qty " : 10 , " ref " : DG } ,
{ " key " : " hand:b " , " section " : " 3 " , " after " : " sec:3 " , " name " : " b " , " qty " : 2 , " ref " : None } ,
] ,
} # fmt: skip
def test_옛_꼴_그대로_읽음_굳히면_같은_표 ( ) :
old = _calc ( OLD )
rows = _rows ( old )
keys = _keys ( old )
assert keys [ keys . index ( " sec:1.2 " ) : ] [ : 5 ] == [ " sec:1.2 " , " earth:4 " , " hand:g1 " , " hand:a " ,
" earth:5 " ] # fmt: skip
assert ( rows [ " earth:4 " ] [ " qty " ] , rows [ " earth:4 " ] [ " auto_qty " ] ) == ( 100 , 10 )
assert ( rows [ " hand:a " ] [ " parent " ] , rows [ " hand:b " ] [ " parent " ] ) == ( " hand:g1 " , " sec:3 " )
v2 = _put ( _freeze ( old ) , " earth:4 " , qty = 100 ) # 화면 첫 손질 = v2 로 굳힘
assert _calc ( v2 ) [ " bill " ] == old [ " bill " ]
REVET = { " key " : " st:r " , " section " : " 2.1 " , " name " : " 흙막이 " , " unit " : " m " , " qty " : 30 , " note " : " " ,
" ref " : { " tab " : " dg_list " , " key " : " r " } , " owners " : { " o1 " : 10 , " o2 " : 20 } } # fmt: skip
def test_구조물_블록_키_대가_번호_밀려도_덮개_같은_줄 ( ) :
inputs = { * * INPUTS , " bill " : { " items " : [ REVET ] } }
first = { " no " : " 대가17 " , " key " : " blk:a " , " labor " : 100 , " material " : 0 , " expense " : 0 }
shifted = { * * first , " no " : " 대가18 " } # 앞에 블록이 끼어 번호만 밀림
bill = _put ( _freeze ( _calc ( { } , inputs , lambda o : first ) ) , " st:r#blk:a " , qty = 7 )
row = _rows ( _calc ( bill , inputs , lambda o : shifted ) ) [ " st:r#blk:a " ]
assert ( row [ " qty " ] , row [ " auto_qty " ] , row [ " note " ] , row [ " labor " ] ) == ( 7 , 30 , " 대가18 " , 700 )
assert row [ " ref " ] == { " tab " : " dg " , " key " : " blk:a " }
def test_자동_줄_로직_연결_새_산근_쓰는_곳 ( ) :
logic = { " tab " : " logic " , " code " : " GF000219 " , " name " : " 돌쌓기 " , " given " : { } }
bill = _put ( _freeze ( _calc ( ) ) , " earth:5 " , ref = logic )
user = { * * BASE , " bill " : store . clean_bill ( bill ) }
assert [ ( k , u ) for k , u , _s in sg . hand_sources ( user ) ] == [ ( " earth:5 " , " 내역 줄 돌쌓기 " ) ]
row = _rows ( compute_estimation ( INPUTS , user , None , BOOKS ) ) [ " earth:5 " ]
assert ( row [ " note " ] , row [ " ref " ] , row [ " sum " ] ) == (
" 산근 2호표 " ,
{ " tab " : " sg " , " key " : " SG:new " } ,
99 ,
)
assert row [ " auto_ref " ] is None # 원래 연결 없음
def test_저장_다듬기_v2_왕복 ( tmp_path ) :
raw = {
" v " : 2 ,
" rows " : [
{ " key " : " sec:1 " , " name " : None , " qty " : 3 , " junk " : 1 } ,
{ " key " : " earth:4 " , " parent " : " sec:1.1 " , " qty " : " x " , " unit " : None , " ref " : { " tab " : " zz " } } ,
{ " key " : " earth:5 " , " qty " : None , " ref " : None , " name " : 12 } ,
{ " key " : " earth:4 " , " qty " : 1 } , # 겹친 키
{ " key " : " fee " , " qty " : 9 } , # 조달수수료 = 덮개 없음
{ " key " : 3 } ,
{ " key " : " hand:g " , " kind " : " group " , " cost " : " direct " , " qty " : 5 , " ref " : DG } ,
{ " key " : " hand:a " , " parent " : " hand:g " , " kind " : " zz " , " cost " : " direct " , " qty " : " 1 " } ,
] ,
" gone " : [ " earth:1 " , " earth:1 " , " hand:a " , 3 , " " ] ,
}
clean = store . write_user ( tmp_path , { " bill " : raw } ) [ " bill " ]
assert store . read_user ( tmp_path ) [ " bill " ] == clean
assert clean [ " gone " ] == [ " earth:1 " ]
assert clean [ " rows " ] == [
{ " key " : " sec:1 " , " name " : None , " qty " : 3 } ,
{ " key " : " earth:4 " , " parent " : " sec:1.1 " , " unit " : None } ,
{ " key " : " earth:5 " , " name " : " 12 " , " qty " : None , " ref " : None } ,
{ " key " : " hand:g " , " kind " : " group " , " cost " : " direct " , " name " : " " , " spec " : " " , " unit " : " " ,
" qty " : None , " ref " : None } ,
{ " key " : " hand:a " , " parent " : " hand:g " , " name " : " " , " spec " : " " , " unit " : " " , " qty " : None ,
" ref " : None } ,
] # fmt: skip
assert " bill " not in store . clean_user ( { " bill " : { " v " : 2 , " rows " : [ ] , " gone " : [ ] } } )
back = store . read_user ( tmp_path )
rows = _rows ( compute_estimation ( INPUTS , { * * BASE , * * back } , None , BOOKS ) )
assert " earth:1 " not in rows and rows [ " earth:4 " ] [ " parent " ] == " sec:1.1 "
assert ( rows [ " sec:1 " ] [ " name " ] , rows [ " earth:5 " ] [ " qty " ] ) == ( " " , None )
def _node ( source : str ) - > str :
result = subprocess . run (
[ " node " , " --experimental-strip-types " , " --no-warnings " ,
" --input-type=module-typescript " ] ,
input = source , capture_output = True , text = True , encoding = " utf-8 " , timeout = 60 ,
) # fmt: skip
assert result . returncode == 0 , result . stderr
return result . stdout
def test_거울_TS_가_같은_값 ( ) :
calc = " " . join (
IMPORTS . sub ( " " , ( ROOT / " B09_Estimation " / f " B09_Estimation_ { n } .ts " ) . read_text ( " utf-8 " ) )
for n in ( " Calc_Base " , " Calc_Bill " )
)
frozen = _freeze ( _calc ( ) )
bills = [
None ,
OLD ,
frozen ,
_put ( _put ( frozen , " earth:4 " , name = None , qty = 3 , ref = DG ) , MAT , parent = " sec:1 " ) ,
{ * * frozen , " gone " : [ " earth:5 " , " sec:1.1 " ] , " rows " : frozen [ " rows " ] [ 3 : ] } ,
{ " v " : 2 , " rows " : [ { " key " : " hand:g " , " kind " : " group " , " name " : " g " } ,
{ " key " : " hand:a " , " parent " : " hand:g " , " qty " : 1 , " ref " : DG } ,
{ " key " : " sec:1 " , " parent " : " hand:a " } ] , " gone " : [ ] } ,
] # fmt: skip
users = [ { * * BASE , * * ( { " bill " : b } if b else { } ) } for b in bills ]
body = (
f " \n const i = { json . dumps ( INPUTS , ensure_ascii = False ) } ; "
f " \n const us = { json . dumps ( users , ensure_ascii = False ) } ; "
f " \n const b = { json . dumps ( BOOKS , ensure_ascii = False ) } ; "
" \n console.log(JSON.stringify(us.map((u) => computeEstimation(i, u, null, b)))); "
)
got = json . loads ( _node ( calc + body ) )
assert got == [ compute_estimation ( INPUTS , u , None , BOOKS ) for u in users ]