feat(est-test): Excel 가져오기 셀부호 밀기·당기기와 설계일자 선택
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -132,3 +132,19 @@ def test_total_price_without_split_is_rejected_and_replace_mode():
|
||||
assert result["length"] is True
|
||||
assert result["first"] == "토공사"
|
||||
assert result["net"] == 54
|
||||
|
||||
|
||||
def test_shift_column_letters_like_original():
|
||||
out = run_js(
|
||||
r"""(() => {
|
||||
const keys = EstExcelMap.fields.map(([k]) => k);
|
||||
const right = EstExcelMap.shift({ Code: 'A', Name: 'Q' }, 1);
|
||||
const left = EstExcelMap.shift({ Code: 'C' }, -1);
|
||||
let low = ''; try { EstExcelMap.shift({ Code: 'A' }, -1); } catch (e) { low = e.message; }
|
||||
return { right: keys.map((k) => right[k]).slice(0, 4), last: right[keys.at(-1)], left: left.Code, low };
|
||||
})()"""
|
||||
)
|
||||
assert out["right"] == ["B", "C", "D", "E"]
|
||||
assert out["last"] == "P"
|
||||
assert out["left"] == "B"
|
||||
assert out["low"] == '시작 부호는 "A" 이하로는 할수 없습니다.'
|
||||
|
||||
@@ -487,6 +487,9 @@ ative-standard.js에 표준시장단가 원천(SilJukDat)과 내역 행(EstMainD
|
||||
- 남음: 구성비·요율 전환(CalcBase), 약어 표시(SName), 제비율 기준 문서 보기(원본 한글 파일).
|
||||
- [x] 수량산출서 검색·전체보기(원본 TFRMMULLANG btnSerch·btnAllDisplay — 빈칸·|·괄호 무시 포함 검색) — 고르기 줄을 `native-quantity-sheets.js` 로 옮겨 700줄 제한 유지.
|
||||
- 검증완료: `test_est_quantity_sheets.py` 검색 시험 포함 수량 시험 22개 통과. ORCA 브라우저에서 「집수」 검색 → 항목에 집수정이 있는 「배수」만·선택 이동, 전체보기 → 3개 복귀, 샘플 복구.
|
||||
- [x] Excel 가져오기 셀부호 밀기·당기기(원본 TFRMEXCELTOEST popCellLeft·popupCellRight) — 첫 필드 열만 보고 모든 필드 열을 한 칸 오른쪽(왼쪽)부터 차례로 다시 매김, A 아래는 원본 문구로 거부(웹은 AA 등 두 글자 열도 이어 매김).
|
||||
- [x] 설계일자 선택(원본 TfrmMonthDate) — 갑지 「날짜 선택」 → 「{년}년 {월}월 일 설계」(일은 빈칸), 견적서 「견적일자 선택」 → 「{년}년 {월}월 {일}일」.
|
||||
- 검증완료: `test_est_excel_map.py` 4개(밀기 A→B…P, 당기기 C→B, A 거부)·견적서·문서·바인딩 시험 통과. ORCA 브라우저에서 갑지 날짜 2026-03-05 → 「2026년 3월 일 설계」, 저장하지 않고 닫아 복구.
|
||||
- [x] 연차 차수 중간 삽입(원본 TFRMESTMULTIEDIT popInsert) — 차수 줄의 「위에 삽입」: 고른 차수 앞에 새 차수([기준]) 넣기.
|
||||
- 검증완료: 바인딩 시험 통과. ORCA 브라우저에서 1차·2차 → 2번째 위 삽입 → 1차·3차·2차, 차수 비워 복구.
|
||||
- [x] 블럭 파일로 저장하기·블럭 파일에서 붙여넣기(원본 mnuBlockSaveToFile·mnuLoadFromFile) — 복사·잘라낸 행 묶음을 `.estblock.json`(종류 est-web-block-1, 표 이름·행)으로 내려받고, 파일을 읽어 같은 종류 화면에 붙여넣음(다른 공사로 옮기기).
|
||||
|
||||
@@ -604,7 +604,7 @@ const EstBusinessActions = (() => {
|
||||
(typeof EstFind !== "undefined" && EstFind.handle(name, state)) ||
|
||||
(typeof EstBlank !== "undefined" && EstBlank.handle(name, state)) ||
|
||||
(typeof EstQuantitySheets !== "undefined" && EstQuantitySheets.handle(name, state, node)) ||
|
||||
(typeof EstExcelMap !== "undefined" && EstExcelMap.handle(name, state)) ||
|
||||
(typeof EstExcelMap !== "undefined" && EstExcelMap.handle(name, state, node)) ||
|
||||
(typeof EstTransfer !== "undefined" && EstTransfer.handle(name, state)) ||
|
||||
(typeof EstBid !== "undefined" && EstBid.handle(name, state)) ||
|
||||
(typeof EstFormsLibrary !== "undefined" && EstFormsLibrary.handle(name, state, node)) ||
|
||||
|
||||
@@ -130,5 +130,22 @@ const EstDocForms = (() => {
|
||||
run(name, state, node).catch((error) => panel(EstApp.esc(error.message)));
|
||||
return true;
|
||||
}
|
||||
return { tools, fill, handle };
|
||||
// 설계일자 선택(TfrmMonthDate 0xda6438): 갑지 「{년}년 {월}월 일 설계」(일은 빈칸) · 견적서 「{년}년 {월}월 {일}일」
|
||||
function dateText(value, format) {
|
||||
const [y, m, d] = String(value).split("-").map(Number);
|
||||
if (!y || !m) return "";
|
||||
return format === "estimate" ? `${y}년 ${m}월 ${d}일` : `${y}년 ${m}월 일 설계`;
|
||||
}
|
||||
if (typeof document !== "undefined" && document.addEventListener)
|
||||
document.addEventListener("change", (event) => {
|
||||
const t = event.target;
|
||||
if (t.dataset?.dateTarget === undefined || !t.value) return;
|
||||
const target = document.querySelector(`#dialog-content [name="${t.dataset.dateTarget}"]`);
|
||||
if (!target) return;
|
||||
target.value = dateText(t.value, t.dataset.dateFormat);
|
||||
target.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
target.dispatchEvent(new Event("change", { bubbles: true }));
|
||||
});
|
||||
|
||||
return { tools, fill, dateText, handle };
|
||||
})();
|
||||
|
||||
@@ -137,6 +137,7 @@ const EstDocs = (() => {
|
||||
input("Position", "공사위치", d.Position) +
|
||||
input("CompanyName", "발주처", d.CompanyName) +
|
||||
input("Date", "설계일자", d.Date) +
|
||||
`<label>날짜 선택<input type="date" data-date-target="doc-Date" data-date-format="design"></label>` +
|
||||
pos(d.CompanyPos) +
|
||||
area("Explan", "공사개요", d.Explan) +
|
||||
area("Cost", "공사금액", d.Cost, 3) +
|
||||
|
||||
@@ -171,7 +171,7 @@ const EstEstimatePrint = (() => {
|
||||
`<label><input name="ep-${k}" type="checkbox" ${s[k] ? "checked" : ""}>${label}</label>`;
|
||||
EstApp.showDialog(
|
||||
"견적서 작성",
|
||||
`<div class="form-fields">${input("Title_Name", "제목")}${input("Project_Name", "공사명(| 줄바꿈)")}${input("Order_name", "발주처")}${input("Esti_Date", "견적일자")}${input("Level", "설계내역 레벨표시(0~9)", "number")}${input("F_PageCount", "첫 페이지 줄수", "number")}${input("L_PageCount", "나머지 페이지 줄수", "number")}<label>품명·규격 정렬<select name="ep-Aligment"><option value="0" ${num(s.Aligment) ? "" : "selected"}>왼쪽</option><option value="1" ${num(s.Aligment) ? "selected" : ""}>가운데</option></select></label>${check("Bigo_Show", "비고란 보기")}${check("Company_Show", "공급자 정보 인쇄")}</div><h4>공급자</h4><div class="form-fields">${input("Reg_Num", "등록번호")}${input("ComPany_Name", "상호")}${input("Ceo_Name", "대표자")}${input("Addr", "사업장주소")}${input("Uptae", "업태")}${input("Jongmog", "종목")}${input("Tel", "전화,(FAX)")}</div><button data-action="estimate-print-preview">미리보기</button> <button data-action="estimate-print-print">인쇄</button> <button data-action="estimate-print-save">공급자정보 저장하기(.einf)</button> <button data-action="estimate-print-load">공급자정보 불러오기</button><iframe id="estimate-print-frame" style="width:100%;height:420px;border:1px solid #ccc;margin-top:8px"></iframe>`,
|
||||
`<div class="form-fields">${input("Title_Name", "제목")}${input("Project_Name", "공사명(| 줄바꿈)")}${input("Order_name", "발주처")}${input("Esti_Date", "견적일자")}<label>견적일자 선택<input type="date" data-date-target="ep-Esti_Date" data-date-format="estimate"></label>${input("Level", "설계내역 레벨표시(0~9)", "number")}${input("F_PageCount", "첫 페이지 줄수", "number")}${input("L_PageCount", "나머지 페이지 줄수", "number")}<label>품명·규격 정렬<select name="ep-Aligment"><option value="0" ${num(s.Aligment) ? "" : "selected"}>왼쪽</option><option value="1" ${num(s.Aligment) ? "selected" : ""}>가운데</option></select></label>${check("Bigo_Show", "비고란 보기")}${check("Company_Show", "공급자 정보 인쇄")}</div><h4>공급자</h4><div class="form-fields">${input("Reg_Num", "등록번호")}${input("ComPany_Name", "상호")}${input("Ceo_Name", "대표자")}${input("Addr", "사업장주소")}${input("Uptae", "업태")}${input("Jongmog", "종목")}${input("Tel", "전화,(FAX)")}</div><button data-action="estimate-print-preview">미리보기</button> <button data-action="estimate-print-print">인쇄</button> <button data-action="estimate-print-save">공급자정보 저장하기(.einf)</button> <button data-action="estimate-print-load">공급자정보 불러오기</button><iframe id="estimate-print-frame" style="width:100%;height:420px;border:1px solid #ccc;margin-top:8px"></iframe>`,
|
||||
);
|
||||
}
|
||||
function read(state) {
|
||||
|
||||
@@ -205,7 +205,7 @@ const EstExcelMap = (() => {
|
||||
`<option value="${value}" ${map.mode === value ? "selected" : ""}>${label}</option>`;
|
||||
EstApp.showDialog(
|
||||
"Excel 내역 열 맞춰 가져오기",
|
||||
`<div class="form-fields"><label>시트<select name="xm-sheet">${sheets}</select></label><label>시작행<input name="xm-start" type="number" value="${map.start}"></label><label>끝행<input name="xm-end" type="number" value="${map.end}"></label><label>가져오기<select name="xm-mode">${mode("append", "순공사비 위에 추가")}${mode("replace", "순공사비 위 행을 이것으로 바꾸기")}</select></label></div><p>각 항목이 있는 Excel 열 문자(A, B …)를 적으세요. 비우면 가져오지 않습니다. 금액은 단가×수량으로 다시 계산합니다.</p><div class="form-fields">${fields.map(([key, label]) => `<label>${label}<input name="xm-${key}" value="${esc(map.columns[key] || "")}" size="3"></label>`).join("")}</div><button data-action="excel-map-preview">미리보기 새로고침</button> <button data-action="excel-map-apply">가져오기</button><div id="excel-map-preview">${preview(state)}</div>`,
|
||||
`<div class="form-fields"><label>시트<select name="xm-sheet">${sheets}</select></label><label>시작행<input name="xm-start" type="number" value="${map.start}"></label><label>끝행<input name="xm-end" type="number" value="${map.end}"></label><label>가져오기<select name="xm-mode">${mode("append", "순공사비 위에 추가")}${mode("replace", "순공사비 위 행을 이것으로 바꾸기")}</select></label></div><p>각 항목이 있는 Excel 열 문자(A, B …)를 적으세요. 비우면 가져오지 않습니다. 금액은 단가×수량으로 다시 계산합니다.</p><div class="form-fields">${fields.map(([key, label]) => `<label>${label}<input name="xm-${key}" value="${esc(map.columns[key] || "")}" size="3"></label>`).join("")}</div><button data-action="excel-map-shift" data-step="1">셀부호 우로밀기</button><button data-action="excel-map-shift" data-step="-1">셀부호 좌로 당기기</button> <button data-action="excel-map-preview">미리보기 새로고침</button> <button data-action="excel-map-apply">가져오기</button><div id="excel-map-preview">${preview(state)}</div>`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -273,7 +273,23 @@ const EstExcelMap = (() => {
|
||||
state.notice = `Excel에서 ${built.length}행을 가져왔습니다. 단가 고르기로 기초자료에 연결할 수 있습니다.`;
|
||||
}
|
||||
|
||||
function handle(name, state) {
|
||||
// 셀부호 밀기·당기기(원본 popCellLeft·popupCellRight 0x109ed40·0x109ed70): 첫 필드 열만 보고
|
||||
// 모든 필드를 그 다음(앞) 열부터 차례로 다시 매긴다(손으로 고친 열은 사라짐).
|
||||
function shift(columns, step) {
|
||||
const first = columnIndex(columns[fields[0][0]] || "A");
|
||||
if (step < 0 && first <= 0) throw Error('시작 부호는 "A" 이하로는 할수 없습니다.');
|
||||
const start = first + step;
|
||||
fields.forEach(([key], i) => (columns[key] = columnName(start + i)));
|
||||
return columns;
|
||||
}
|
||||
|
||||
function handle(name, state, node) {
|
||||
if (name === "excel-map-shift") {
|
||||
read(state);
|
||||
shift(state.excelMap.columns, Number(node.dataset.step));
|
||||
form(state);
|
||||
return true;
|
||||
}
|
||||
if (name === "excel-map-open") open(state);
|
||||
else if (name === "excel-map-preview") {
|
||||
read(state);
|
||||
@@ -283,5 +299,5 @@ const EstExcelMap = (() => {
|
||||
return true;
|
||||
}
|
||||
|
||||
return { fields, columnIndex, columnName, records, rows, insert, load, handle };
|
||||
return { fields, columnIndex, columnName, records, rows, insert, load, shift, handle };
|
||||
})();
|
||||
|
||||
Reference in New Issue
Block a user