- M02_Doc_Match_Note.rate_pairs → (다른 항, 참고) · 「율 값」 다른 항 폐지(EXPLAINED 에서도 뺌) · 띠 참고 요약에 「율 값 다름 N 줄」 - 시험: test_812_2 율 값 = 참고로 고침 · test_812_4 새(리퍼 105 · 275 확정 + 참고 · 율 대상 다름 = 다른 항 · 바꾸기 뒤 M01 율 · 되돌리기) - 전수 2,220: 확정 152 → 163 · 근접 588 → 577 · 없음 1,480 · 확정 다시 셈 다름 0
109 lines
4.6 KiB
TypeScript
109 lines
4.6 KiB
TypeScript
/* =============================================================================
|
|
* M02_Sangeun_Match.ts
|
|
* 가져온 식 ↔ 우리 M01 기초 연결 판정 띠 자료(PLAN 810-4 · 요구 707 · 709 · 703) — 원문 패널 카드 위.
|
|
* SK `가져온.원본.연결후보`(서버 `M02_Doc_Match` 가 적음) → 띠 글 · 다른 항 · 단추 하나:
|
|
* 확정 = [우리 기초 사본으로 바꾸기] · 근접 · 없음 = 단추 없음(703) · 안 찾음 = [연결 찾기] ·
|
|
* 다른 항 = 로직 차이(확정을 막음) · 참고 = 단가 · 끝수 · 율 값 %(값 차이 — 「우리 단가로 셈 ○○ 원」 · 812-2 · 812-4) ·
|
|
* 바꾼 SK(`가져온보관` 있음) = 「우리 기초 사본 ○○」 + [가져온 식으로 되돌리기]
|
|
* 화면 · DOM · fetch 없음
|
|
* ========================================================================== */
|
|
|
|
export type MatchVerdict = "확정" | "근접" | "없음";
|
|
|
|
export interface MatchFound {
|
|
판정?: MatchVerdict;
|
|
키?: string;
|
|
이름?: string;
|
|
옵션?: Record<string, string>;
|
|
다른?: { 항: string; 글: string }[];
|
|
/** 값 차이(단가 · 끝수 · 율 값) — 확정을 안 막음 */
|
|
참고?: { 항: string; 글: string }[];
|
|
금액?: { 가져온?: Record<string, number | null>; 우리?: Record<string, number | null> };
|
|
후보수?: number;
|
|
가까움?: { 키?: string; 이름?: string; 다른?: { 항: string; 글: string }[] };
|
|
}
|
|
|
|
export type MatchAction = "찾기" | "바꾸기" | "되돌리기" | null;
|
|
|
|
export interface MatchBand {
|
|
tone: "success" | "info" | "warning";
|
|
text: string;
|
|
/** 다른 항 글(근접 · 없음의 가까운 후보) */
|
|
details: string[];
|
|
action: MatchAction;
|
|
}
|
|
|
|
interface SkLike {
|
|
바탕?: { 로직?: string } | null;
|
|
입력값?: Record<string, unknown>;
|
|
가져온?: { 로직?: unknown; 원본?: { 연결후보?: MatchFound } } | null;
|
|
가져온보관?: { 가져온?: { 원본?: { 연결후보?: MatchFound } } } | null;
|
|
}
|
|
|
|
const opts = (o?: Record<string, unknown>): string => {
|
|
const list = Object.entries(o ?? {}).map(([k, v]) => `${k} ${String(v)}`);
|
|
return list.length ? `(${list.join(" · ")})` : "(기본 옵션)";
|
|
};
|
|
const lines = (d?: { 항: string; 글: string }[]): string[] =>
|
|
(d ?? []).map((x) => `${x.항} — ${x.글}`);
|
|
|
|
const won = (n?: number | null): string =>
|
|
n == null ? "" : `${Math.round(n).toLocaleString("ko-KR")} 원`;
|
|
/** 참고 요약 — 「참고: 단가 다름 3 줄 · 율 값 다름 1 줄 · 우리 단가로 셈 53,218 원」 · 참고 없음 = "" */
|
|
const noteText = (f: MatchFound): string => {
|
|
const n = f.참고 ?? [];
|
|
if (!n.length) return "";
|
|
const price = n.filter((x) => x.항 === "단가 차이").length;
|
|
const rate = n.filter((x) => x.항 === "율 값").length;
|
|
const bits = [
|
|
price ? `단가 다름 ${price} 줄` : "",
|
|
rate ? `율 값 다름 ${rate} 줄` : "",
|
|
n.some((x) => x.항 === "끝수") ? "끝수 다름" : "",
|
|
].filter(Boolean);
|
|
const ours = won(f.금액?.우리?.계);
|
|
return ` · 참고: ${bits.join(" · ")}${ours ? ` · 우리 단가로 셈 ${ours}` : ""}`;
|
|
};
|
|
|
|
/** SK → 띠 자료 · 가져온 식도 · 바꾼 SK 도 아니면 null */
|
|
export function matchBand(sk: SkLike | null | undefined): MatchBand | null {
|
|
const kept = sk?.가져온보관;
|
|
if (kept && sk?.바탕?.로직) {
|
|
return {
|
|
tone: "info",
|
|
text: `우리 기초 사본 ${sk.바탕.로직} ${opts(sk.입력값)} — 원래 가져온 식은 보관`,
|
|
details: [],
|
|
action: "되돌리기",
|
|
};
|
|
}
|
|
if (!sk?.가져온?.로직) return null;
|
|
const f = sk.가져온.원본?.연결후보;
|
|
if (!f?.판정) {
|
|
return { tone: "info", text: "우리 기초와 연결을 아직 안 찾음", details: [], action: "찾기" };
|
|
}
|
|
const base = `${f.키 ?? ""} ${f.이름 ?? ""} ${opts(f.옵션)}`.trim();
|
|
if (f.판정 === "확정") {
|
|
return {
|
|
tone: "success",
|
|
text: `확정 — 로직 같음 · 우리 기초 ${base}${noteText(f)}`,
|
|
details: lines(f.참고),
|
|
action: "바꾸기",
|
|
};
|
|
}
|
|
if (f.판정 === "근접") {
|
|
const kinds = [...new Set((f.다른 ?? []).map((x) => x.항))].join(" · ");
|
|
return {
|
|
tone: "warning",
|
|
text: `근접 — ${base} · 다른 항: ${kinds}${noteText(f)}`,
|
|
details: [...lines(f.다른), ...lines(f.참고).map((x) => `참고 ${x}`)],
|
|
action: null,
|
|
};
|
|
}
|
|
const near = f.가까움;
|
|
return {
|
|
tone: "info",
|
|
text: `없음 — 우리 기초 후보 ${f.후보수 ?? 0} 개와 맞지 않음`,
|
|
details: near ? [`가장 가까운 ${near.키 ?? ""} ${near.이름 ?? ""}`, ...lines(near.다른)] : [],
|
|
action: null,
|
|
};
|
|
}
|