|
|
|
|
@@ -17,6 +17,7 @@ interface AutoGenMappingInfo {
|
|
|
|
|
numberingRuleId: string;
|
|
|
|
|
targetColumn: string;
|
|
|
|
|
showResultModal?: boolean;
|
|
|
|
|
shareAcrossItems?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface HiddenMappingInfo {
|
|
|
|
|
@@ -182,6 +183,31 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
throw new Error(`유효하지 않은 테이블명: ${cardMapping.targetTable}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const allAutoGen = [
|
|
|
|
|
...(fieldMapping?.autoGenMappings ?? []),
|
|
|
|
|
...(cardMapping?.autoGenMappings ?? []),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 일괄 채번: shareAcrossItems=true인 매핑은 루프 전 1회만 채번
|
|
|
|
|
const sharedCodes: Record<string, string> = {};
|
|
|
|
|
for (const ag of allAutoGen) {
|
|
|
|
|
if (!ag.shareAcrossItems) continue;
|
|
|
|
|
if (!ag.numberingRuleId || !ag.targetColumn) continue;
|
|
|
|
|
if (!isSafeIdentifier(ag.targetColumn)) continue;
|
|
|
|
|
try {
|
|
|
|
|
const code = await numberingRuleService.allocateCode(
|
|
|
|
|
ag.numberingRuleId, companyCode, { ...fieldValues, ...(items[0] ?? {}) },
|
|
|
|
|
);
|
|
|
|
|
sharedCodes[ag.targetColumn] = code;
|
|
|
|
|
generatedCodes.push({ targetColumn: ag.targetColumn, code, showResultModal: ag.showResultModal ?? false });
|
|
|
|
|
logger.info("[pop/execute-action] 일괄 채번 완료", {
|
|
|
|
|
ruleId: ag.numberingRuleId, targetColumn: ag.targetColumn, code,
|
|
|
|
|
});
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
logger.error("[pop/execute-action] 일괄 채번 실패", { ruleId: ag.numberingRuleId, error: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const item of items) {
|
|
|
|
|
const columns: string[] = ["company_code"];
|
|
|
|
|
const values: unknown[] = [companyCode];
|
|
|
|
|
@@ -225,26 +251,41 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
values.push(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const allAutoGen = [
|
|
|
|
|
...(fieldMapping?.autoGenMappings ?? []),
|
|
|
|
|
...(cardMapping?.autoGenMappings ?? []),
|
|
|
|
|
];
|
|
|
|
|
for (const ag of allAutoGen) {
|
|
|
|
|
if (!ag.numberingRuleId || !ag.targetColumn) continue;
|
|
|
|
|
if (!isSafeIdentifier(ag.targetColumn)) continue;
|
|
|
|
|
if (columns.includes(`"${ag.targetColumn}"`)) continue;
|
|
|
|
|
try {
|
|
|
|
|
const generatedCode = await numberingRuleService.allocateCode(
|
|
|
|
|
ag.numberingRuleId, companyCode, { ...fieldValues, ...item },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (ag.shareAcrossItems && sharedCodes[ag.targetColumn]) {
|
|
|
|
|
columns.push(`"${ag.targetColumn}"`);
|
|
|
|
|
values.push(generatedCode);
|
|
|
|
|
generatedCodes.push({ targetColumn: ag.targetColumn, code: generatedCode, showResultModal: ag.showResultModal ?? false });
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
logger.error("[pop/execute-action] 채번 실패", { ruleId: ag.numberingRuleId, error: err.message });
|
|
|
|
|
values.push(sharedCodes[ag.targetColumn]);
|
|
|
|
|
} else if (!ag.shareAcrossItems) {
|
|
|
|
|
try {
|
|
|
|
|
const generatedCode = await numberingRuleService.allocateCode(
|
|
|
|
|
ag.numberingRuleId, companyCode, { ...fieldValues, ...item },
|
|
|
|
|
);
|
|
|
|
|
columns.push(`"${ag.targetColumn}"`);
|
|
|
|
|
values.push(generatedCode);
|
|
|
|
|
generatedCodes.push({ targetColumn: ag.targetColumn, code: generatedCode, showResultModal: ag.showResultModal ?? false });
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
logger.error("[pop/execute-action] 채번 실패", { ruleId: ag.numberingRuleId, error: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!columns.includes('"created_date"')) {
|
|
|
|
|
columns.push('"created_date"');
|
|
|
|
|
values.push(new Date().toISOString());
|
|
|
|
|
}
|
|
|
|
|
if (!columns.includes('"updated_date"')) {
|
|
|
|
|
columns.push('"updated_date"');
|
|
|
|
|
values.push(new Date().toISOString());
|
|
|
|
|
}
|
|
|
|
|
if (!columns.includes('"writer"') && userId) {
|
|
|
|
|
columns.push('"writer"');
|
|
|
|
|
values.push(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (columns.length > 1) {
|
|
|
|
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
|
|
|
|
await client.query(
|
|
|
|
|
@@ -292,8 +333,9 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
for (let i = 0; i < lookupValues.length; i++) {
|
|
|
|
|
const item = items[i] ?? {};
|
|
|
|
|
const resolved = resolveStatusValue("conditional", task.fixedValue ?? "", task.conditionalValue, item);
|
|
|
|
|
const autoUpdated = task.targetColumn !== "updated_date" ? `, "updated_date" = NOW()` : "";
|
|
|
|
|
await client.query(
|
|
|
|
|
`UPDATE "${task.targetTable}" SET "${task.targetColumn}" = $1 WHERE company_code = $2 AND "${pkColumn}" = $3`,
|
|
|
|
|
`UPDATE "${task.targetTable}" SET "${task.targetColumn}" = $1${autoUpdated} WHERE company_code = $2 AND "${pkColumn}" = $3`,
|
|
|
|
|
[resolved, companyCode, lookupValues[i]],
|
|
|
|
|
);
|
|
|
|
|
processedCount++;
|
|
|
|
|
@@ -311,9 +353,10 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
|
|
|
|
|
const caseSql = `CASE WHEN COALESCE("${task.compareColumn}"::numeric, 0) ${op} COALESCE("${task.compareWith}"::numeric, 0) THEN $1 ELSE $2 END`;
|
|
|
|
|
|
|
|
|
|
const autoUpdatedDb = task.targetColumn !== "updated_date" ? `, "updated_date" = NOW()` : "";
|
|
|
|
|
const placeholders = lookupValues.map((_, i) => `$${i + 4}`).join(", ");
|
|
|
|
|
await client.query(
|
|
|
|
|
`UPDATE "${task.targetTable}" SET "${task.targetColumn}" = ${caseSql} WHERE company_code = $3 AND "${pkColumn}" IN (${placeholders})`,
|
|
|
|
|
`UPDATE "${task.targetTable}" SET "${task.targetColumn}" = ${caseSql}${autoUpdatedDb} WHERE company_code = $3 AND "${pkColumn}" IN (${placeholders})`,
|
|
|
|
|
[thenVal, elseVal, companyCode, ...lookupValues],
|
|
|
|
|
);
|
|
|
|
|
processedCount += lookupValues.length;
|
|
|
|
|
@@ -325,7 +368,14 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
if (valSource === "linked") {
|
|
|
|
|
value = item[task.sourceField ?? ""] ?? null;
|
|
|
|
|
} else {
|
|
|
|
|
value = task.fixedValue ?? "";
|
|
|
|
|
const raw = task.fixedValue ?? "";
|
|
|
|
|
if (raw === "__CURRENT_USER__") {
|
|
|
|
|
value = userId;
|
|
|
|
|
} else if (raw === "__CURRENT_TIME__") {
|
|
|
|
|
value = new Date().toISOString();
|
|
|
|
|
} else {
|
|
|
|
|
value = raw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let setSql: string;
|
|
|
|
|
@@ -341,8 +391,9 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
setSql = `"${task.targetColumn}" = $1`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const autoUpdatedDate = task.targetColumn !== "updated_date" ? `, "updated_date" = NOW()` : "";
|
|
|
|
|
await client.query(
|
|
|
|
|
`UPDATE "${task.targetTable}" SET ${setSql} WHERE company_code = $2 AND "${pkColumn}" = $3`,
|
|
|
|
|
`UPDATE "${task.targetTable}" SET ${setSql}${autoUpdatedDate} WHERE company_code = $2 AND "${pkColumn}" = $3`,
|
|
|
|
|
[value, companyCode, lookupValues[i]],
|
|
|
|
|
);
|
|
|
|
|
processedCount++;
|
|
|
|
|
@@ -448,6 +499,31 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
throw new Error(`유효하지 않은 테이블명: ${cardMapping.targetTable}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const allAutoGen = [
|
|
|
|
|
...(fieldMapping?.autoGenMappings ?? []),
|
|
|
|
|
...(cardMapping?.autoGenMappings ?? []),
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
// 일괄 채번: shareAcrossItems=true인 매핑은 루프 전 1회만 채번
|
|
|
|
|
const sharedCodes: Record<string, string> = {};
|
|
|
|
|
for (const ag of allAutoGen) {
|
|
|
|
|
if (!ag.shareAcrossItems) continue;
|
|
|
|
|
if (!ag.numberingRuleId || !ag.targetColumn) continue;
|
|
|
|
|
if (!isSafeIdentifier(ag.targetColumn)) continue;
|
|
|
|
|
try {
|
|
|
|
|
const code = await numberingRuleService.allocateCode(
|
|
|
|
|
ag.numberingRuleId, companyCode, { ...fieldValues, ...(items[0] ?? {}) },
|
|
|
|
|
);
|
|
|
|
|
sharedCodes[ag.targetColumn] = code;
|
|
|
|
|
generatedCodes.push({ targetColumn: ag.targetColumn, code, showResultModal: ag.showResultModal ?? false });
|
|
|
|
|
logger.info("[pop/execute-action] 일괄 채번 완료", {
|
|
|
|
|
ruleId: ag.numberingRuleId, targetColumn: ag.targetColumn, code,
|
|
|
|
|
});
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
logger.error("[pop/execute-action] 일괄 채번 실패", { ruleId: ag.numberingRuleId, error: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const item of items) {
|
|
|
|
|
const columns: string[] = ["company_code"];
|
|
|
|
|
const values: unknown[] = [companyCode];
|
|
|
|
|
@@ -467,7 +543,6 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 숨은 필드 매핑 처리 (고정값 / JSON추출 / DB컬럼)
|
|
|
|
|
const allHidden = [
|
|
|
|
|
...(fieldMapping?.hiddenMappings ?? []),
|
|
|
|
|
...(cardMapping?.hiddenMappings ?? []),
|
|
|
|
|
@@ -494,37 +569,44 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
values.push(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 채번 규칙 실행: field + cardList의 autoGenMappings에서 코드 발급
|
|
|
|
|
const allAutoGen = [
|
|
|
|
|
...(fieldMapping?.autoGenMappings ?? []),
|
|
|
|
|
...(cardMapping?.autoGenMappings ?? []),
|
|
|
|
|
];
|
|
|
|
|
for (const ag of allAutoGen) {
|
|
|
|
|
if (!ag.numberingRuleId || !ag.targetColumn) continue;
|
|
|
|
|
if (!isSafeIdentifier(ag.targetColumn)) continue;
|
|
|
|
|
if (columns.includes(`"${ag.targetColumn}"`)) continue;
|
|
|
|
|
try {
|
|
|
|
|
const generatedCode = await numberingRuleService.allocateCode(
|
|
|
|
|
ag.numberingRuleId,
|
|
|
|
|
companyCode,
|
|
|
|
|
{ ...fieldValues, ...item },
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (ag.shareAcrossItems && sharedCodes[ag.targetColumn]) {
|
|
|
|
|
columns.push(`"${ag.targetColumn}"`);
|
|
|
|
|
values.push(generatedCode);
|
|
|
|
|
generatedCodes.push({ targetColumn: ag.targetColumn, code: generatedCode, showResultModal: ag.showResultModal ?? false });
|
|
|
|
|
logger.info("[pop/execute-action] 채번 완료", {
|
|
|
|
|
ruleId: ag.numberingRuleId,
|
|
|
|
|
targetColumn: ag.targetColumn,
|
|
|
|
|
generatedCode,
|
|
|
|
|
});
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
logger.error("[pop/execute-action] 채번 실패", {
|
|
|
|
|
ruleId: ag.numberingRuleId,
|
|
|
|
|
error: err.message,
|
|
|
|
|
});
|
|
|
|
|
values.push(sharedCodes[ag.targetColumn]);
|
|
|
|
|
} else if (!ag.shareAcrossItems) {
|
|
|
|
|
try {
|
|
|
|
|
const generatedCode = await numberingRuleService.allocateCode(
|
|
|
|
|
ag.numberingRuleId, companyCode, { ...fieldValues, ...item },
|
|
|
|
|
);
|
|
|
|
|
columns.push(`"${ag.targetColumn}"`);
|
|
|
|
|
values.push(generatedCode);
|
|
|
|
|
generatedCodes.push({ targetColumn: ag.targetColumn, code: generatedCode, showResultModal: ag.showResultModal ?? false });
|
|
|
|
|
logger.info("[pop/execute-action] 채번 완료", {
|
|
|
|
|
ruleId: ag.numberingRuleId, targetColumn: ag.targetColumn, generatedCode,
|
|
|
|
|
});
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
logger.error("[pop/execute-action] 채번 실패", { ruleId: ag.numberingRuleId, error: err.message });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!columns.includes('"created_date"')) {
|
|
|
|
|
columns.push('"created_date"');
|
|
|
|
|
values.push(new Date().toISOString());
|
|
|
|
|
}
|
|
|
|
|
if (!columns.includes('"updated_date"')) {
|
|
|
|
|
columns.push('"updated_date"');
|
|
|
|
|
values.push(new Date().toISOString());
|
|
|
|
|
}
|
|
|
|
|
if (!columns.includes('"writer"') && userId) {
|
|
|
|
|
columns.push('"writer"');
|
|
|
|
|
values.push(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (columns.length > 1) {
|
|
|
|
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
|
|
|
|
const sql = `INSERT INTO "${cardMapping.targetTable}" (${columns.join(", ")}) VALUES (${placeholders})`;
|
|
|
|
|
@@ -558,6 +640,19 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
values.push(fieldValues[sourceField] ?? null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!columns.includes('"created_date"')) {
|
|
|
|
|
columns.push('"created_date"');
|
|
|
|
|
values.push(new Date().toISOString());
|
|
|
|
|
}
|
|
|
|
|
if (!columns.includes('"updated_date"')) {
|
|
|
|
|
columns.push('"updated_date"');
|
|
|
|
|
values.push(new Date().toISOString());
|
|
|
|
|
}
|
|
|
|
|
if (!columns.includes('"writer"') && userId) {
|
|
|
|
|
columns.push('"writer"');
|
|
|
|
|
values.push(userId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (columns.length > 1) {
|
|
|
|
|
const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
|
|
|
|
|
const sql = `INSERT INTO "${fieldMapping.targetTable}" (${columns.join(", ")}) VALUES (${placeholders})`;
|
|
|
|
|
@@ -609,16 +704,18 @@ router.post("/execute-action", authenticateToken, async (req: Request, res: Resp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (valueType === "fixed") {
|
|
|
|
|
const autoUpd = rule.targetColumn !== "updated_date" ? `, "updated_date" = NOW()` : "";
|
|
|
|
|
const placeholders = lookupValues.map((_, i) => `$${i + 3}`).join(", ");
|
|
|
|
|
const sql = `UPDATE "${rule.targetTable}" SET "${rule.targetColumn}" = $1 WHERE company_code = $2 AND "${pkColumn}" IN (${placeholders})`;
|
|
|
|
|
const sql = `UPDATE "${rule.targetTable}" SET "${rule.targetColumn}" = $1${autoUpd} WHERE company_code = $2 AND "${pkColumn}" IN (${placeholders})`;
|
|
|
|
|
await client.query(sql, [fixedValue, companyCode, ...lookupValues]);
|
|
|
|
|
processedCount += lookupValues.length;
|
|
|
|
|
} else {
|
|
|
|
|
for (let i = 0; i < lookupValues.length; i++) {
|
|
|
|
|
const item = items[i] ?? {};
|
|
|
|
|
const resolvedValue = resolveStatusValue(valueType, fixedValue, rule.conditionalValue, item);
|
|
|
|
|
const autoUpd2 = rule.targetColumn !== "updated_date" ? `, "updated_date" = NOW()` : "";
|
|
|
|
|
await client.query(
|
|
|
|
|
`UPDATE "${rule.targetTable}" SET "${rule.targetColumn}" = $1 WHERE company_code = $2 AND "${pkColumn}" = $3`,
|
|
|
|
|
`UPDATE "${rule.targetTable}" SET "${rule.targetColumn}" = $1${autoUpd2} WHERE company_code = $2 AND "${pkColumn}" = $3`,
|
|
|
|
|
[resolvedValue, companyCode, lookupValues[i]]
|
|
|
|
|
);
|
|
|
|
|
processedCount++;
|
|
|
|
|
|