구매관리 입고 3메뉴 + 프로젝트 발주/입고 통계 빈 그리드 채움
- DDL: purchase_order_part(43 cols) + arrival_plan(37 cols) + POM 보충 컬럼 10개 (mail_send_yn/date, form_type, purchase_close_date 등) - 데이터: 운영 sample purchase_order_master 1건 + part 1건 + arrival_plan 1건 - listInbound — wace deliveryMngList_new 매퍼 1:1 (POM + S1 집계, AP × POP) - listInboundByItem — wace deliveryMngPartList 매퍼 1:1 (품목별) - listInboundByDate — wace purchaseCloseList 매퍼 1:1 (입고일별 + 매입마감) - listProjectStatus — PO/DLV 통계 0 → 실데이터 (purchase_order_part + arrival_plan) - INVENTORY_MGMT / INCOMING_INSPECTION 미존재 → 검사/폐기 0 처리 (확정수량=입고수량)
This commit is contained in:
@@ -380,27 +380,336 @@ export async function listProposal(filter: PurchaseListFilter): Promise<ListResu
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 4) 입고관리 (wace purchaseOrder.xml deliveryMngAcceptanceList) ──
|
||||
// purchase_order_master + purchase_order_part(누락) + arrival_plan(누락).
|
||||
// 누락 의존 — purchase_order_master 단독으로 빈 그리드 처리.
|
||||
// ─── 4) 입고관리 (wace purchaseOrder.xml deliveryMngList_new 매퍼 1:1) ──
|
||||
//
|
||||
// 발주서별 1행 (purchase_order_master + S1 집계: PURCHASE_ORDER_PART × ARRIVAL_PLAN).
|
||||
// 매퍼 본문: wace_plm/src/com/pms/mapper/purchaseOrder.xml:4381-4580
|
||||
// 검색: year / customer_cd / project_no / purchase_order_no / part_no / part_name / part_spec /
|
||||
// partner_objid / sales_mng_user_id / delivery_date 범위 / reg_date 범위 / delivery_status
|
||||
// 검사현황(IID_AGG/DEFECT_AGG)은 INVENTORY/INSPECTION 테이블 미존재 → 0 처리.
|
||||
|
||||
export async function listInbound(filter: PurchaseListFilter): Promise<ListResult<any>> {
|
||||
const { page, pageSize } = clampPaging(filter);
|
||||
logger.warn("listInbound: purchase_order_part / arrival_plan 미존재 — 빈 응답");
|
||||
return { rows: [], totalCount: 0, page, pageSize };
|
||||
const pool = getPool();
|
||||
const { limit, offset, page, pageSize } = clampPaging(filter);
|
||||
|
||||
const where: string[] = [
|
||||
`POM.MAIL_SEND_DATE IS NOT NULL`,
|
||||
`POM.STATUS = 'create'`,
|
||||
`(POM.MULTI_MASTER_YN = 'Y' OR COALESCE(POM.MULTI_MASTER_YN, '') <> 'Y' AND COALESCE(POM.MULTI_YN, '') <> 'Y')`,
|
||||
];
|
||||
const params: any[] = [];
|
||||
const addParam = (val: any) => { params.push(val); return `$${params.length}`; };
|
||||
|
||||
if (filter.year) where.push(`TO_CHAR(POM.REGDATE, 'YYYY') = ${addParam(String(filter.year))}`);
|
||||
if (filter.customer_cd) where.push(`CM.CUSTOMER_OBJID = REPLACE(${addParam(filter.customer_cd)}, 'C_', '')`);
|
||||
if (filter.project_no) where.push(`CM.PROJECT_NO ILIKE ${addParam(`%${filter.project_no}%`)}`);
|
||||
if (filter.purchase_order_no) where.push(`POM.PURCHASE_ORDER_NO ILIKE ${addParam(`%${filter.purchase_order_no}%`)}`);
|
||||
if (filter.partner_objid) where.push(`POM.PARTNER_OBJID = REPLACE(${addParam(filter.partner_objid)}, 'C_', '')`);
|
||||
if (filter.sales_mng_user_id) where.push(`POM.WRITER = ${addParam(filter.sales_mng_user_id)}`);
|
||||
if (filter.delivery_start_date) where.push(`POM.DELIVERY_DATE >= ${addParam(filter.delivery_start_date)}`);
|
||||
if (filter.delivery_end_date) where.push(`POM.DELIVERY_DATE <= ${addParam(filter.delivery_end_date)}`);
|
||||
if (filter.reg_start_date) where.push(`TO_CHAR(POM.REGDATE, 'YYYY-MM-DD') >= ${addParam(filter.reg_start_date)}`);
|
||||
if (filter.reg_end_date) where.push(`TO_CHAR(POM.REGDATE, 'YYYY-MM-DD') <= ${addParam(filter.reg_end_date)}`);
|
||||
if (filter.part_no) where.push(`EXISTS (SELECT 1 FROM PURCHASE_ORDER_PART POPX WHERE POPX.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID AND POPX.PART_NO ILIKE ${addParam(`%${filter.part_no}%`)})`);
|
||||
if (filter.part_name) where.push(`EXISTS (SELECT 1 FROM PURCHASE_ORDER_PART POPX WHERE POPX.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID AND POPX.PART_NAME ILIKE ${addParam(`%${filter.part_name}%`)})`);
|
||||
if (filter.part_spec) where.push(`EXISTS (SELECT 1 FROM PURCHASE_ORDER_PART POPX WHERE POPX.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID AND POPX.SPEC ILIKE ${addParam(`%${filter.part_spec}%`)})`);
|
||||
|
||||
const whereSql = `WHERE ${where.join(" AND ")}`;
|
||||
const havingSql =
|
||||
filter.delivery_status
|
||||
? `HAVING (CASE WHEN COALESCE(S1.TOTAL_PO_QTY,0) - COALESCE(S1.TOTAL_DELIVERY_QTY,0) <= 0 THEN '입고완료'
|
||||
WHEN TO_CHAR(NOW(),'YYYY-MM-DD') > POM.DELIVERY_DATE THEN '지연'
|
||||
ELSE '입고중' END) = ${addParam(filter.delivery_status)}`
|
||||
: "";
|
||||
|
||||
const fromSql = `
|
||||
FROM PURCHASE_ORDER_MASTER POM
|
||||
LEFT JOIN PROJECT_MGMT CM ON CM.OBJID = POM.CONTRACT_MGMT_OBJID
|
||||
LEFT JOIN (
|
||||
SELECT POP.PURCHASE_ORDER_MASTER_OBJID,
|
||||
SUM(COALESCE(POP.ORDER_QTY::NUMERIC, 0)) AS TOTAL_PO_QTY,
|
||||
MAX(AP_AGG.MAX_RECEIPT_DATE) AS CUR_DELIVERY_DATE,
|
||||
SUM(COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0)) AS TOTAL_DELIVERY_QTY,
|
||||
SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(POP.ORDER_QTY::NUMERIC, 0)) AS TOTAL_SUPPLY_PRICE,
|
||||
SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0)) AS TOTAL_DELIVERY_PRICE,
|
||||
SUM(COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) *
|
||||
(COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.SUM_RECEIPT_QTY, 0))) AS TOTAL_NOT_DELIVERY_PRICE
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
LEFT JOIN (
|
||||
SELECT PARENT_OBJID, PART_OBJID,
|
||||
SUM(COALESCE(RECEIPT_QTY::NUMERIC, 0)) AS SUM_RECEIPT_QTY,
|
||||
MAX(RECEIPT_DATE) AS MAX_RECEIPT_DATE
|
||||
FROM ARRIVAL_PLAN
|
||||
GROUP BY PARENT_OBJID, PART_OBJID
|
||||
) AP_AGG ON AP_AGG.PARENT_OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
AND AP_AGG.PART_OBJID = POP.PART_OBJID
|
||||
GROUP BY POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
) S1 ON POM.OBJID = S1.PURCHASE_ORDER_MASTER_OBJID
|
||||
${whereSql}
|
||||
`;
|
||||
|
||||
const groupBySql = havingSql ? `GROUP BY POM.OBJID, S1.TOTAL_PO_QTY, S1.TOTAL_DELIVERY_QTY, POM.DELIVERY_DATE` : "";
|
||||
|
||||
const dataSql = `
|
||||
SELECT
|
||||
POM.OBJID AS objid,
|
||||
POM.PURCHASE_ORDER_NO AS purchase_order_no,
|
||||
POM.STATUS AS status,
|
||||
(SELECT REQUEST_MNG_NO FROM SALES_REQUEST_MASTER SRM WHERE SRM.OBJID = POM.SALES_REQUEST_OBJID LIMIT 1) AS proposal_no,
|
||||
CM.PROJECT_NO AS project_no,
|
||||
-- 첫 품번/품명 + "외 N건"
|
||||
(SELECT CASE WHEN COUNT(*) > 1 THEN MIN(PART_NO) || ' 외 ' || (COUNT(*) - 1) || '건' ELSE MIN(PART_NO) END
|
||||
FROM PURCHASE_ORDER_PART POPN WHERE POPN.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID) AS part_no,
|
||||
(SELECT CASE WHEN COUNT(*) > 1 THEN MIN(PART_NAME) || ' 외 ' || (COUNT(*) - 1) || '건' ELSE MIN(PART_NAME) END
|
||||
FROM PURCHASE_ORDER_PART POPN WHERE POPN.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID) AS part_name,
|
||||
POM.PARTNER_OBJID AS partner_objid,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID = POM.PARTNER_OBJID LIMIT 1) AS partner_name,
|
||||
(SELECT CC.CODE_NAME FROM COMM_CODE CC
|
||||
WHERE CC.CODE_ID = (SELECT POP2.CURRENCY FROM PURCHASE_ORDER_PART POP2
|
||||
WHERE POP2.PURCHASE_ORDER_MASTER_OBJID = POM.OBJID
|
||||
AND POP2.CURRENCY IS NOT NULL AND POP2.CURRENCY <> '' LIMIT 1)
|
||||
LIMIT 1) AS currency_name,
|
||||
POM.WRITER AS writer,
|
||||
COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = POM.WRITER LIMIT 1), POM.WRITER, '') AS writer_name,
|
||||
(SELECT COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = AP.WRITER), AP.WRITER, '')
|
||||
FROM ARRIVAL_PLAN AP
|
||||
WHERE AP.PARENT_OBJID = POM.OBJID
|
||||
AND AP.RECEIPT_QTY IS NOT NULL AND AP.RECEIPT_QTY::NUMERIC > 0
|
||||
ORDER BY AP.RECEIPT_DATE DESC LIMIT 1) AS delivery_writer_name,
|
||||
(SELECT AP.RECEIPT_DATE FROM ARRIVAL_PLAN AP
|
||||
WHERE AP.PARENT_OBJID = POM.OBJID
|
||||
AND AP.RECEIPT_QTY IS NOT NULL AND AP.RECEIPT_QTY::NUMERIC > 0
|
||||
ORDER BY AP.RECEIPT_DATE DESC LIMIT 1) AS delivery_regdate,
|
||||
COALESCE(S1.TOTAL_PO_QTY, 0) AS total_po_qty,
|
||||
COALESCE(S1.TOTAL_DELIVERY_QTY, 0) AS total_delivery_qty,
|
||||
COALESCE(S1.TOTAL_PO_QTY, 0) - COALESCE(S1.TOTAL_DELIVERY_QTY, 0) AS non_delivery_qty,
|
||||
COALESCE(S1.TOTAL_SUPPLY_PRICE, 0) AS total_supply_price,
|
||||
COALESCE(S1.TOTAL_DELIVERY_PRICE, 0) AS total_delivery_price,
|
||||
COALESCE(S1.TOTAL_NOT_DELIVERY_PRICE, 0) AS total_not_delivery_price,
|
||||
(SELECT COUNT(1)::int FROM ATTACH_FILE_INFO AF
|
||||
WHERE AF.TARGET_OBJID = POM.OBJID
|
||||
AND AF.DOC_TYPE = 'INSPECTION_FILE'
|
||||
AND UPPER(COALESCE(AF.STATUS, 'Active')) = 'ACTIVE') AS inspection_file_cnt,
|
||||
CASE WHEN COALESCE(S1.TOTAL_PO_QTY, 0) - COALESCE(S1.TOTAL_DELIVERY_QTY, 0) <= 0 THEN '입고완료'
|
||||
WHEN TO_CHAR(NOW(),'YYYY-MM-DD') > POM.DELIVERY_DATE THEN '지연'
|
||||
ELSE '입고중'
|
||||
END AS delivery_status,
|
||||
POM.PURCHASE_CLOSE_DATE AS purchase_close_date
|
||||
${fromSql}
|
||||
${groupBySql}
|
||||
${havingSql}
|
||||
ORDER BY POM.REGDATE DESC
|
||||
LIMIT ${addParam(limit)} OFFSET ${addParam(offset)}
|
||||
`;
|
||||
const countSql = `SELECT COUNT(*)::int AS cnt ${fromSql} ${groupBySql} ${havingSql}`;
|
||||
try {
|
||||
const [d, c] = await Promise.all([
|
||||
pool.query(dataSql, params),
|
||||
pool.query(countSql, params.slice(0, params.length - 2)),
|
||||
]);
|
||||
return { rows: d.rows, totalCount: c.rows[0]?.cnt ?? 0, page, pageSize };
|
||||
} catch (e: any) {
|
||||
logger.error("listInbound 실패", { error: e.message });
|
||||
return { rows: [], totalCount: 0, page, pageSize };
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 5) 품목별 입고관리 (wace deliveryMngPartList) ──
|
||||
// ─── 5) 품목별 입고관리 (wace deliveryMngPartList 매퍼 1:1) ──
|
||||
// 매퍼 본문: wace_plm/src/com/pms/mapper/purchaseOrder.xml:6309-6543
|
||||
// PURCHASE_ORDER_PART 행별 1행 + AP_AGG (입고집계) + IID_AGG/DEFECT_AGG (검사 — RPS 미존재로 0).
|
||||
|
||||
export async function listInboundByItem(filter: PurchaseListFilter): Promise<ListResult<any>> {
|
||||
const { page, pageSize } = clampPaging(filter);
|
||||
logger.warn("listInboundByItem: purchase_order_part / arrival_plan 미존재 — 빈 응답");
|
||||
return { rows: [], totalCount: 0, page, pageSize };
|
||||
const pool = getPool();
|
||||
const { limit, offset, page, pageSize } = clampPaging(filter);
|
||||
|
||||
const where: string[] = [
|
||||
`POM.MAIL_SEND_DATE IS NOT NULL`,
|
||||
`POM.STATUS = 'create'`,
|
||||
`(POM.MULTI_MASTER_YN = 'Y' OR COALESCE(POM.MULTI_MASTER_YN, '') <> 'Y' AND COALESCE(POM.MULTI_YN, '') <> 'Y')`,
|
||||
];
|
||||
const params: any[] = [];
|
||||
const addParam = (val: any) => { params.push(val); return `$${params.length}`; };
|
||||
|
||||
if (filter.year) where.push(`TO_CHAR(POM.REGDATE, 'YYYY') = ${addParam(String(filter.year))}`);
|
||||
if (filter.customer_cd) where.push(`CM.CUSTOMER_OBJID = REPLACE(${addParam(filter.customer_cd)}, 'C_', '')`);
|
||||
if (filter.project_no) where.push(`CM.PROJECT_NO ILIKE ${addParam(`%${filter.project_no}%`)}`);
|
||||
if (filter.purchase_order_no) where.push(`POM.PURCHASE_ORDER_NO ILIKE ${addParam(`%${filter.purchase_order_no}%`)}`);
|
||||
if (filter.partner_objid) where.push(`POM.PARTNER_OBJID = REPLACE(${addParam(filter.partner_objid)}, 'C_', '')`);
|
||||
if (filter.sales_mng_user_id) where.push(`POM.WRITER = ${addParam(filter.sales_mng_user_id)}`);
|
||||
if (filter.delivery_start_date) where.push(`POP.DELIVERY_REQUEST_DATE >= ${addParam(filter.delivery_start_date)}`);
|
||||
if (filter.delivery_end_date) where.push(`POP.DELIVERY_REQUEST_DATE <= ${addParam(filter.delivery_end_date)}`);
|
||||
if (filter.reg_start_date) where.push(`TO_CHAR(POM.REGDATE, 'YYYY-MM-DD') >= ${addParam(filter.reg_start_date)}`);
|
||||
if (filter.reg_end_date) where.push(`TO_CHAR(POM.REGDATE, 'YYYY-MM-DD') <= ${addParam(filter.reg_end_date)}`);
|
||||
if (filter.part_no) where.push(`POP.PART_NO ILIKE ${addParam(`%${filter.part_no}%`)}`);
|
||||
if (filter.part_name) where.push(`POP.PART_NAME ILIKE ${addParam(`%${filter.part_name}%`)}`);
|
||||
if (filter.part_spec) where.push(`POP.SPEC ILIKE ${addParam(`%${filter.part_spec}%`)}`);
|
||||
if (filter.delivery_status) {
|
||||
where.push(`(CASE WHEN COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.DELIVERY_QTY, 0) <= 0 THEN '입고완료'
|
||||
WHEN TO_CHAR(NOW(),'YYYY-MM-DD') > POM.DELIVERY_DATE THEN '지연'
|
||||
ELSE '입고중' END) = ${addParam(filter.delivery_status)}`);
|
||||
}
|
||||
|
||||
const whereSql = `WHERE ${where.join(" AND ")}`;
|
||||
const fromSql = `
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM ON POM.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
LEFT JOIN PROJECT_MGMT CM ON CM.OBJID = POM.CONTRACT_MGMT_OBJID
|
||||
LEFT JOIN (
|
||||
SELECT PARENT_OBJID, PART_OBJID, SUM(COALESCE(RECEIPT_QTY::NUMERIC, 0)) AS DELIVERY_QTY
|
||||
FROM ARRIVAL_PLAN
|
||||
GROUP BY PARENT_OBJID, PART_OBJID
|
||||
) AP_AGG ON AP_AGG.PARENT_OBJID = POM.OBJID AND AP_AGG.PART_OBJID = POP.PART_OBJID
|
||||
${whereSql}
|
||||
`;
|
||||
|
||||
const dataSql = `
|
||||
SELECT
|
||||
POP.OBJID AS objid,
|
||||
POP.OBJID AS purchase_order_part_objid,
|
||||
POM.OBJID AS purchase_order_master_objid,
|
||||
POM.STATUS AS status,
|
||||
(SELECT REQUEST_MNG_NO FROM SALES_REQUEST_MASTER SRM WHERE SRM.OBJID = POM.SALES_REQUEST_OBJID LIMIT 1) AS proposal_no,
|
||||
POM.PURCHASE_ORDER_NO AS purchase_order_no,
|
||||
CM.PROJECT_NO AS project_no,
|
||||
-- 부품품번 (sales_request_part 미존재 → POP.PART_NO fallback)
|
||||
POP.PART_NO AS component_part_no,
|
||||
POP.PART_NO AS part_no,
|
||||
POP.PART_NAME AS part_name,
|
||||
POM.PARTNER_OBJID AS partner_objid,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID = POM.PARTNER_OBJID LIMIT 1) AS partner_name,
|
||||
(SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = POP.CURRENCY LIMIT 1) AS currency_name,
|
||||
POP.DELIVERY_REQUEST_DATE AS delivery_request_date,
|
||||
COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = POM.WRITER LIMIT 1), POM.WRITER, '') AS writer_name,
|
||||
(SELECT COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = AP.WRITER), AP.WRITER, '')
|
||||
FROM ARRIVAL_PLAN AP
|
||||
WHERE AP.PARENT_OBJID = POM.OBJID
|
||||
AND AP.PART_OBJID = POP.PART_OBJID
|
||||
AND AP.RECEIPT_QTY IS NOT NULL AND AP.RECEIPT_QTY::NUMERIC > 0
|
||||
ORDER BY AP.RECEIPT_DATE DESC LIMIT 1) AS delivery_writer_name,
|
||||
(SELECT AP.RECEIPT_DATE FROM ARRIVAL_PLAN AP
|
||||
WHERE AP.PARENT_OBJID = POM.OBJID
|
||||
AND AP.PART_OBJID = POP.PART_OBJID
|
||||
AND AP.RECEIPT_QTY IS NOT NULL AND AP.RECEIPT_QTY::NUMERIC > 0
|
||||
ORDER BY AP.RECEIPT_DATE DESC LIMIT 1) AS delivery_regdate,
|
||||
COALESCE(POP.ORDER_QTY::NUMERIC, 0) AS order_qty,
|
||||
COALESCE(AP_AGG.DELIVERY_QTY, 0) AS delivery_qty,
|
||||
COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.DELIVERY_QTY, 0) AS non_delivery_qty,
|
||||
COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(POP.ORDER_QTY::NUMERIC, 0) AS total_supply_price,
|
||||
COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(AP_AGG.DELIVERY_QTY, 0) AS total_delivery_price,
|
||||
COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) *
|
||||
(COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.DELIVERY_QTY, 0)) AS total_not_delivery_price,
|
||||
-- 검사현황/폐기/확정수량 (incoming_inspection_* 미존재 → 0)
|
||||
'' AS inspection_status,
|
||||
0 AS defect_qty,
|
||||
COALESCE(AP_AGG.DELIVERY_QTY, 0) AS confirmed_qty,
|
||||
CASE WHEN COALESCE(POP.ORDER_QTY::NUMERIC, 0) - COALESCE(AP_AGG.DELIVERY_QTY, 0) <= 0 THEN '입고완료'
|
||||
WHEN TO_CHAR(NOW(),'YYYY-MM-DD') > POM.DELIVERY_DATE THEN '지연'
|
||||
ELSE '입고중'
|
||||
END AS delivery_status
|
||||
${fromSql}
|
||||
ORDER BY POM.REGDATE DESC, POP.OBJID
|
||||
LIMIT ${addParam(limit)} OFFSET ${addParam(offset)}
|
||||
`;
|
||||
const countSql = `SELECT COUNT(*)::int AS cnt ${fromSql}`;
|
||||
try {
|
||||
const [d, c] = await Promise.all([
|
||||
pool.query(dataSql, params),
|
||||
pool.query(countSql, params.slice(0, params.length - 2)),
|
||||
]);
|
||||
return { rows: d.rows, totalCount: c.rows[0]?.cnt ?? 0, page, pageSize };
|
||||
} catch (e: any) {
|
||||
logger.error("listInboundByItem 실패", { error: e.message });
|
||||
return { rows: [], totalCount: 0, page, pageSize };
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 6) 입고일별 입고관리 (wace purchaseCloseList) ──
|
||||
// ─── 6) 입고일별 입고관리 (wace purchaseCloseList 매퍼 1:1) ──
|
||||
// 매퍼 본문: wace_plm/src/com/pms/mapper/purchaseOrder.xml:6549-6765
|
||||
// ARRIVAL_PLAN 행별 (RECEIPT_QTY > 0) + 매입마감/관세/세금계산서 컬럼.
|
||||
|
||||
export async function listInboundByDate(filter: PurchaseListFilter): Promise<ListResult<any>> {
|
||||
const { page, pageSize } = clampPaging(filter);
|
||||
logger.warn("listInboundByDate: arrival_plan / purchase_order_part 미존재 — 빈 응답");
|
||||
return { rows: [], totalCount: 0, page, pageSize };
|
||||
const pool = getPool();
|
||||
const { limit, offset, page, pageSize } = clampPaging(filter);
|
||||
|
||||
const where: string[] = [
|
||||
`POM.MAIL_SEND_DATE IS NOT NULL`,
|
||||
`POM.STATUS = 'create'`,
|
||||
`COALESCE(AP.RECEIPT_QTY, '0')::NUMERIC > 0`,
|
||||
];
|
||||
const params: any[] = [];
|
||||
const addParam = (val: any) => { params.push(val); return `$${params.length}`; };
|
||||
|
||||
if (filter.year) where.push(`TO_CHAR(POM.REGDATE, 'YYYY') = ${addParam(String(filter.year))}`);
|
||||
if (filter.customer_cd) where.push(`CM.CUSTOMER_OBJID = REPLACE(${addParam(filter.customer_cd)}, 'C_', '')`);
|
||||
if (filter.project_no) where.push(`CM.PROJECT_NO ILIKE ${addParam(`%${filter.project_no}%`)}`);
|
||||
if (filter.purchase_order_no) where.push(`POM.PURCHASE_ORDER_NO ILIKE ${addParam(`%${filter.purchase_order_no}%`)}`);
|
||||
if (filter.partner_objid) where.push(`POM.PARTNER_OBJID = REPLACE(${addParam(filter.partner_objid)}, 'C_', '')`);
|
||||
if (filter.sales_mng_user_id) where.push(`POM.WRITER = ${addParam(filter.sales_mng_user_id)}`);
|
||||
if (filter.part_no) where.push(`POP.PART_NO ILIKE ${addParam(`%${filter.part_no}%`)}`);
|
||||
if (filter.part_name) where.push(`POP.PART_NAME ILIKE ${addParam(`%${filter.part_name}%`)}`);
|
||||
if (filter.part_spec) where.push(`POP.SPEC ILIKE ${addParam(`%${filter.part_spec}%`)}`);
|
||||
if (filter.receipt_date_start) where.push(`AP.RECEIPT_DATE >= ${addParam(filter.receipt_date_start)}`);
|
||||
if (filter.receipt_date_end) where.push(`AP.RECEIPT_DATE <= ${addParam(filter.receipt_date_end)}`);
|
||||
if (filter.close_status === "Y") where.push(`AP.PURCHASE_CLOSE_DATE IS NOT NULL AND AP.PURCHASE_CLOSE_DATE <> ''`);
|
||||
if (filter.close_status === "N") where.push(`(AP.PURCHASE_CLOSE_DATE IS NULL OR AP.PURCHASE_CLOSE_DATE = '')`);
|
||||
|
||||
const whereSql = `WHERE ${where.join(" AND ")}`;
|
||||
const fromSql = `
|
||||
FROM ARRIVAL_PLAN AP
|
||||
JOIN PURCHASE_ORDER_MASTER POM ON POM.OBJID = AP.PARENT_OBJID
|
||||
LEFT JOIN PURCHASE_ORDER_PART POP
|
||||
ON POP.PURCHASE_ORDER_MASTER_OBJID = AP.PARENT_OBJID
|
||||
AND POP.PART_OBJID = AP.PART_OBJID
|
||||
LEFT JOIN PROJECT_MGMT CM ON CM.OBJID = POM.CONTRACT_MGMT_OBJID
|
||||
${whereSql}
|
||||
`;
|
||||
const dataSql = `
|
||||
SELECT
|
||||
AP.OBJID AS objid,
|
||||
AP.OBJID AS arrival_plan_objid,
|
||||
POP.OBJID AS purchase_order_part_objid,
|
||||
POM.OBJID AS purchase_order_master_objid,
|
||||
(SELECT REQUEST_MNG_NO FROM SALES_REQUEST_MASTER SRM WHERE SRM.OBJID = POM.SALES_REQUEST_OBJID LIMIT 1) AS proposal_no,
|
||||
POM.PURCHASE_ORDER_NO AS purchase_order_no,
|
||||
CM.PROJECT_NO AS project_no,
|
||||
POP.PART_NO AS component_part_no,
|
||||
POP.PART_NO AS part_no,
|
||||
POP.PART_NAME AS part_name,
|
||||
(SELECT CLIENT_NM FROM CLIENT_MNG WHERE OBJID = POM.PARTNER_OBJID LIMIT 1) AS partner_name,
|
||||
(SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = POP.CURRENCY LIMIT 1) AS currency_name,
|
||||
AP.RECEIPT_DATE AS receipt_date,
|
||||
COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = POM.WRITER LIMIT 1), POM.WRITER, '') AS writer_name,
|
||||
COALESCE((SELECT USER_NAME FROM USER_INFO WHERE USER_ID = AP.WRITER LIMIT 1), AP.WRITER, '') AS delivery_writer_name,
|
||||
COALESCE(AP.RECEIPT_QTY::NUMERIC, 0) AS receipt_qty,
|
||||
COALESCE(POP.PARTNER_PRICE::NUMERIC, 0) * COALESCE(AP.RECEIPT_QTY::NUMERIC, 0) AS total_delivery_price,
|
||||
'' AS inspection_status,
|
||||
0 AS defect_qty,
|
||||
COALESCE(AP.RECEIPT_QTY::NUMERIC, 0) AS confirmed_qty,
|
||||
AP.SUB_LOCATION AS sub_location_name,
|
||||
(SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = AP.FOREIGN_TYPE LIMIT 1) AS foreign_type_name,
|
||||
AP.EXCHANGE_RATE AS exchange_rate,
|
||||
(SELECT CC.CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = AP.TAX_TYPE LIMIT 1) AS tax_type_name,
|
||||
AP.TAX_INVOICE_DATE AS tax_invoice_date,
|
||||
AP.EXPORT_DECL_NO AS export_decl_no,
|
||||
AP.LOADING_DATE AS loading_date,
|
||||
AP.DUTY AS duty,
|
||||
AP.IMPORT_VAT AS import_vat,
|
||||
AP.PURCHASE_CLOSE_DATE AS purchase_close_date
|
||||
${fromSql}
|
||||
ORDER BY AP.RECEIPT_DATE DESC NULLS LAST, AP.OBJID
|
||||
LIMIT ${addParam(limit)} OFFSET ${addParam(offset)}
|
||||
`;
|
||||
const countSql = `SELECT COUNT(*)::int AS cnt ${fromSql}`;
|
||||
try {
|
||||
const [d, c] = await Promise.all([
|
||||
pool.query(dataSql, params),
|
||||
pool.query(countSql, params.slice(0, params.length - 2)),
|
||||
]);
|
||||
return { rows: d.rows, totalCount: c.rows[0]?.cnt ?? 0, page, pageSize };
|
||||
} catch (e: any) {
|
||||
logger.error("listInboundByDate 실패", { error: e.message });
|
||||
return { rows: [], totalCount: 0, page, pageSize };
|
||||
}
|
||||
}
|
||||
|
||||
// ─── 7) 프로젝트별 발주/입고 현황 (wace projectPurchaseDeliveryStatus) ──
|
||||
@@ -451,23 +760,90 @@ export async function listProjectStatus(filter: PurchaseListFilter): Promise<Lis
|
||||
JOIN MBOM_HEADER MH2 ON MD.MBOM_HEADER_OBJID = MH2.OBJID
|
||||
WHERE MH2.PROJECT_OBJID = PM.OBJID::VARCHAR
|
||||
AND MH2.STATUS = 'Y'), 0) AS total_qty,
|
||||
-- 발주/입고/미발주/미입고 — purchase_order_part / arrival_plan 누락이라 모두 0
|
||||
0::int AS po_item_cnt,
|
||||
0::numeric AS po_qty,
|
||||
COALESCE((SELECT COUNT(DISTINCT MD.PART_OBJID)::int
|
||||
FROM MBOM_DETAIL MD
|
||||
JOIN MBOM_HEADER MH2 ON MD.MBOM_HEADER_OBJID = MH2.OBJID
|
||||
WHERE MH2.PROJECT_OBJID = PM.OBJID::VARCHAR
|
||||
AND MH2.STATUS = 'Y'), 0) AS non_po_item_cnt,
|
||||
COALESCE((SELECT SUM(NULLIF(MD.QTY, '')::numeric)
|
||||
FROM MBOM_DETAIL MD
|
||||
JOIN MBOM_HEADER MH2 ON MD.MBOM_HEADER_OBJID = MH2.OBJID
|
||||
WHERE MH2.PROJECT_OBJID = PM.OBJID::VARCHAR
|
||||
AND MH2.STATUS = 'Y'), 0) AS non_po_qty,
|
||||
0::int AS dlv_item_cnt,
|
||||
0::numeric AS dlv_qty,
|
||||
0::int AS non_dlv_item_cnt,
|
||||
0::numeric AS non_dlv_qty
|
||||
-- 발주 통계: PURCHASE_ORDER_PART × POM(STATUS='create' AND MAIL_SEND_DATE IS NOT NULL)
|
||||
COALESCE((SELECT COUNT(DISTINCT POP.PART_OBJID)::int
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM2 ON POM2.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
WHERE POM2.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM2.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM2.STATUS = 'create'), 0) AS po_item_cnt,
|
||||
COALESCE((SELECT SUM(COALESCE(POP.ORDER_QTY::numeric, 0))
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM2 ON POM2.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
WHERE POM2.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM2.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM2.STATUS = 'create'), 0) AS po_qty,
|
||||
-- 미발주 = BOM 품목수 - 발주 품목수 (음수 방지 GREATEST)
|
||||
GREATEST(
|
||||
COALESCE((SELECT COUNT(DISTINCT MD.PART_OBJID)::int
|
||||
FROM MBOM_DETAIL MD
|
||||
JOIN MBOM_HEADER MH2 ON MD.MBOM_HEADER_OBJID = MH2.OBJID
|
||||
WHERE MH2.PROJECT_OBJID = PM.OBJID::VARCHAR
|
||||
AND MH2.STATUS = 'Y'), 0)
|
||||
- COALESCE((SELECT COUNT(DISTINCT POP.PART_OBJID)::int
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM2 ON POM2.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
WHERE POM2.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM2.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM2.STATUS = 'create'), 0)
|
||||
, 0) AS non_po_item_cnt,
|
||||
GREATEST(
|
||||
COALESCE((SELECT SUM(NULLIF(MD.QTY, '')::numeric)
|
||||
FROM MBOM_DETAIL MD
|
||||
JOIN MBOM_HEADER MH2 ON MD.MBOM_HEADER_OBJID = MH2.OBJID
|
||||
WHERE MH2.PROJECT_OBJID = PM.OBJID::VARCHAR
|
||||
AND MH2.STATUS = 'Y'), 0)
|
||||
- COALESCE((SELECT SUM(COALESCE(POP.ORDER_QTY::numeric, 0))
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM2 ON POM2.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
WHERE POM2.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM2.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM2.STATUS = 'create'), 0)
|
||||
, 0) AS non_po_qty,
|
||||
-- 입고 통계: ARRIVAL_PLAN × POM (RECEIPT_QTY > 0)
|
||||
COALESCE((SELECT COUNT(DISTINCT AP.PART_OBJID)::int
|
||||
FROM ARRIVAL_PLAN AP
|
||||
JOIN PURCHASE_ORDER_MASTER POM3 ON POM3.OBJID = AP.PARENT_OBJID
|
||||
WHERE POM3.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM3.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM3.STATUS = 'create'
|
||||
AND COALESCE(AP.RECEIPT_QTY::numeric, 0) > 0), 0) AS dlv_item_cnt,
|
||||
COALESCE((SELECT SUM(COALESCE(AP.RECEIPT_QTY::numeric, 0))
|
||||
FROM ARRIVAL_PLAN AP
|
||||
JOIN PURCHASE_ORDER_MASTER POM3 ON POM3.OBJID = AP.PARENT_OBJID
|
||||
WHERE POM3.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM3.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM3.STATUS = 'create'), 0) AS dlv_qty,
|
||||
-- 미입고 = 발주 - 입고 (음수 방지)
|
||||
GREATEST(
|
||||
COALESCE((SELECT COUNT(DISTINCT POP.PART_OBJID)::int
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM2 ON POM2.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
WHERE POM2.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM2.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM2.STATUS = 'create'), 0)
|
||||
- COALESCE((SELECT COUNT(DISTINCT AP.PART_OBJID)::int
|
||||
FROM ARRIVAL_PLAN AP
|
||||
JOIN PURCHASE_ORDER_MASTER POM3 ON POM3.OBJID = AP.PARENT_OBJID
|
||||
WHERE POM3.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM3.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM3.STATUS = 'create'
|
||||
AND COALESCE(AP.RECEIPT_QTY::numeric, 0) > 0), 0)
|
||||
, 0) AS non_dlv_item_cnt,
|
||||
GREATEST(
|
||||
COALESCE((SELECT SUM(COALESCE(POP.ORDER_QTY::numeric, 0))
|
||||
FROM PURCHASE_ORDER_PART POP
|
||||
JOIN PURCHASE_ORDER_MASTER POM2 ON POM2.OBJID = POP.PURCHASE_ORDER_MASTER_OBJID
|
||||
WHERE POM2.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM2.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM2.STATUS = 'create'), 0)
|
||||
- COALESCE((SELECT SUM(COALESCE(AP.RECEIPT_QTY::numeric, 0))
|
||||
FROM ARRIVAL_PLAN AP
|
||||
JOIN PURCHASE_ORDER_MASTER POM3 ON POM3.OBJID = AP.PARENT_OBJID
|
||||
WHERE POM3.CONTRACT_MGMT_OBJID = PM.OBJID
|
||||
AND POM3.MAIL_SEND_DATE IS NOT NULL
|
||||
AND POM3.STATUS = 'create'), 0)
|
||||
, 0) AS non_dlv_qty
|
||||
FROM PROJECT_MGMT PM
|
||||
LEFT JOIN CONTRACT_MGMT CTR ON CTR.OBJID = PM.CONTRACT_OBJID
|
||||
${whereSql}
|
||||
|
||||
Reference in New Issue
Block a user