feat: pop-field에 json_extract_lookup valueSource 추가

cart_items.row_data에서 코드값(partner_id)을 추출한 후
참조 테이블(customer_mng)에서 표시값(customer_name)을 조회하는
json_extract_lookup 기능을 추가한다.
화면 4579(출고 확정)에서 거래처명이 표시되지 않는 문제를 해결한다.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
SeongHyun Kim 2026-03-24 19:14:34 +09:00
parent cbe3242f3a
commit 9afe98ec60
2 changed files with 46 additions and 1 deletions

View File

@ -95,6 +95,7 @@ export function PopFieldComponent({
const row = res.data[0] as Record<string, unknown>;
const extracted: Record<string, unknown> = {};
const lookupQueue: { fieldId: string; codeValue: string; table: string; codeCol: string; displayCol: string }[] = [];
for (const mapping of readSource.fieldMappings || []) {
if (mapping.valueSource === "json_extract" && mapping.columnName && mapping.jsonKey) {
const raw = row[mapping.columnName];
@ -105,11 +106,48 @@ export function PopFieldComponent({
parsed = raw as Record<string, unknown>;
}
extracted[mapping.fieldId] = parsed[mapping.jsonKey] ?? "";
} else if (mapping.valueSource === "json_extract_lookup" && mapping.columnName && mapping.jsonKey && mapping.lookupTable && mapping.lookupCodeColumn && mapping.lookupDisplayColumn) {
const raw = row[mapping.columnName];
let parsed: Record<string, unknown> = {};
if (typeof raw === "string") {
try { parsed = JSON.parse(raw); } catch { /* ignore */ }
} else if (typeof raw === "object" && raw !== null) {
parsed = raw as Record<string, unknown>;
}
const codeValue = String(parsed[mapping.jsonKey] ?? "");
if (codeValue) {
lookupQueue.push({ fieldId: mapping.fieldId, codeValue, table: mapping.lookupTable, codeCol: mapping.lookupCodeColumn, displayCol: mapping.lookupDisplayColumn });
} else {
extracted[mapping.fieldId] = "";
}
} else if (mapping.valueSource === "db_column" && mapping.columnName) {
extracted[mapping.fieldId] = row[mapping.columnName] ?? "";
}
}
// json_extract_lookup: 코드 값으로 참조 테이블 조회하여 표시명 획득
if (lookupQueue.length > 0) {
const lookupResults = await Promise.allSettled(
lookupQueue.map(async (lq) => {
const lookupRes = await dataApi.getTableData(lq.table, {
page: 1,
size: 1,
filters: { [lq.codeCol]: lq.codeValue },
});
if (Array.isArray(lookupRes.data) && lookupRes.data.length > 0) {
const lookupRow = lookupRes.data[0] as Record<string, unknown>;
return { fieldId: lq.fieldId, value: lookupRow[lq.displayCol] ?? lq.codeValue };
}
return { fieldId: lq.fieldId, value: lq.codeValue };
}),
);
for (const result of lookupResults) {
if (result.status === "fulfilled") {
extracted[result.value.fieldId] = result.value.value;
}
}
}
const allFieldsInConfig = cfg.sections.flatMap((s) => s.fields || []);
const valuesUpdate: Record<string, unknown> = {};
for (const [fieldId, val] of Object.entries(extracted)) {

View File

@ -110,12 +110,13 @@ export interface PopFieldSection {
// ===== 저장 설정: 값 소스 타입 =====
export type FieldValueSource = "direct" | "json_extract" | "db_column";
export type FieldValueSource = "direct" | "json_extract" | "db_column" | "json_extract_lookup";
export const FIELD_VALUE_SOURCE_LABELS: Record<FieldValueSource, string> = {
direct: "직접 입력",
json_extract: "JSON 추출",
db_column: "DB 컬럼",
json_extract_lookup: "JSON 추출 + 조회",
};
// ===== 저장 설정: 필드-컬럼 매핑 =====
@ -170,6 +171,12 @@ export interface PopFieldReadMapping {
valueSource: FieldValueSource;
columnName: string;
jsonKey?: string;
/** json_extract_lookup 전용: 조회할 테이블명 */
lookupTable?: string;
/** json_extract_lookup 전용: JSON에서 추출한 코드 값과 매칭할 컬럼 */
lookupCodeColumn?: string;
/** json_extract_lookup 전용: 화면에 표시할 컬럼 */
lookupDisplayColumn?: string;
}
export interface PopFieldReadSource {