auto commit

This commit is contained in:
leeheejin
2025-11-25 13:58:07 +09:00
parent 926e8d6420
commit cd4f5afe87
9 changed files with 1479 additions and 102 deletions

View File

@@ -2944,29 +2944,47 @@
LIMIT 1),
''
) AS EBOM_REGDATE,
COALESCE(PM.MBOM_STATUS, '') AS MBOM_STATUS,
-- M-BOM 상태: 새 MBOM_HEADER 테이블에서 조회
COALESCE(
(SELECT PBR.PART_NO
FROM PART_BOM_REPORT PBR
WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID
AND PM.MBOM_STATUS = 'Y'
LIMIT 1),
(SELECT
CASE
WHEN COUNT(*) > 0 THEN 'Y'
ELSE COALESCE(PM.MBOM_STATUS, '')
END
FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = PM.OBJID::VARCHAR
AND MH.STATUS = 'Y'
LIMIT 1),
COALESCE(PM.MBOM_STATUS, '')
) AS MBOM_STATUS,
-- M-BOM 품번: 새 MBOM_HEADER 테이블에서 조회
COALESCE(
(SELECT MH.MBOM_NO
FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = PM.OBJID::VARCHAR
AND MH.STATUS = 'Y'
ORDER BY MH.REGDATE DESC
LIMIT 1),
''
) AS MBOM_PART_NO,
'1.0' AS MBOM_VERSION,
-- M-BOM 저장일: 새 MBOM_HEADER 테이블에서 조회
COALESCE(
(SELECT TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD')
FROM PART_BOM_REPORT PBR
WHERE PBR.OBJID::VARCHAR = PM.BOM_REPORT_OBJID
AND PM.MBOM_STATUS = 'Y'
LIMIT 1),
(SELECT TO_CHAR(MH.REGDATE, 'YYYY-MM-DD')
FROM MBOM_HEADER MH
WHERE MH.PROJECT_OBJID = PM.OBJID::VARCHAR
AND MH.STATUS = 'Y'
ORDER BY MH.REGDATE DESC
LIMIT 1),
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD')
) AS MBOM_REGDATE
FROM
PROJECT_MGMT PM
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
LEFT OUTER JOIN CONTRACT_ITEM CI ON PM.CONTRACT_OBJID = CI.CONTRACT_OBJID
AND PM.PART_OBJID = CI.PART_OBJID
-- CONTRACT_ITEM과 LEFT JOIN하여 품목별로 펼쳐서 보이기
LEFT JOIN CONTRACT_ITEM CI ON CM.OBJID::VARCHAR = CI.CONTRACT_OBJID
-- LEFT JOIN CONTRACT_ITEM CI ON CM.OBJID::VARCHAR = CI.CONTRACT_OBJID
AND CI.STATUS = 'ACTIVE'
WHERE 1=1
AND PM.PROJECT_NO IS NOT NULL
@@ -3024,6 +3042,10 @@
PM.BOM_REPORT_OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.SOURCE_BOM_TYPE,
PM.SOURCE_EBOM_OBJID,
PM.SOURCE_MBOM_OBJID,
PM.QUANTITY,
COALESCE(
(SELECT PBR.PART_NO
FROM PART_BOM_REPORT PBR
@@ -3268,21 +3290,6 @@
BPQ.SEQ
</select>
<!-- M-BOM 품번 최대 순번 조회 (같은 날짜) -->
<select id="getMaxMbomSeqByDate" parameterType="map" resultType="int">
SELECT
COALESCE(MAX(
CAST(
SUBSTRING(PART_NO FROM '.+-([0-9]+)$') AS INTEGER
)
), 0) AS MAX_SEQ
FROM
PART_BOM_REPORT
WHERE
PART_NO LIKE #{prefix} || '%'
AND STATUS = 'Y'
</select>
<!-- 품번으로 최신 M-BOM 조회 (Machine 이외 제품용) -->
<select id="getLatestMbomByPartNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
@@ -3314,85 +3321,26 @@
<!-- M-BOM 이력 조회 -->
<select id="getMbomHistory" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
PBR.OBJID,
PBR.PART_NO AS MBOM_PART_NO,
TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE,
PBR.REGUSER,
COALESCE(PBR.REMARK, '') AS REMARK,
PBR.STATUS
MH.OBJID,
MH.MBOM_HEADER_OBJID,
MH.CHANGE_TYPE,
MH.CHANGE_DESCRIPTION,
MH.BEFORE_DATA,
MH.AFTER_DATA,
MH.CHANGE_USER,
TO_CHAR(MH.CHANGE_DATE, 'YYYY-MM-DD HH24:MI:SS') AS CHANGE_DATE,
-- MBOM_HEADER 정보 조인
MHD.MBOM_NO AS MBOM_PART_NO,
MHD.PROJECT_OBJID,
TO_CHAR(MHD.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE
FROM
PART_BOM_REPORT PBR
MBOM_HISTORY MH
INNER JOIN MBOM_HEADER MHD ON MH.MBOM_HEADER_OBJID = MHD.OBJID
WHERE
PBR.PART_NO = #{mbomPartNo}
ORDER BY PBR.REGDATE DESC
MHD.PROJECT_OBJID = #{projectObjId}
ORDER BY MH.CHANGE_DATE DESC
</select>
<!-- M-BOM 헤더 저장 -->
<insert id="insertMbomHeader" parameterType="map">
<selectKey keyProperty="OBJID" resultType="string" order="BEFORE">
SELECT REPLACE(UUID(),'-','') FROM DUAL
</selectKey>
INSERT INTO MBOM_HEADER (
OBJID,
MBOM_NO,
PART_NO,
PART_NAME,
SAVE_DATE,
CREATE_USER,
CREATE_DATE,
UPDATE_USER,
UPDATE_DATE
) VALUES (
#{OBJID},
CONCAT('MBOM-', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')),
#{PART_NO},
#{PART_NAME},
NOW(),
#{CREATE_USER},
NOW(),
#{UPDATE_USER},
NOW()
)
</insert>
<!-- M-BOM 상세 저장 -->
<insert id="insertMbomDetail" parameterType="map">
<selectKey keyProperty="OBJID" resultType="string" order="BEFORE">
SELECT REPLACE(UUID(),'-','') FROM DUAL
</selectKey>
INSERT INTO MBOM_DETAIL (
OBJID,
MBOM_HEADER_OBJID,
PART_NO,
PART_NAME,
QTY,
LEVEL,
REVISION,
SPEC,
PRODUCT_NAME,
STATUS_NAME,
CREATE_USER,
CREATE_DATE,
UPDATE_USER,
UPDATE_DATE
) VALUES (
#{OBJID},
#{MBOM_HEADER_OBJID},
#{PART_NO},
#{PART_NAME},
#{QTY},
#{LEVEL},
#{REVISION},
#{SPEC},
#{PRODUCT_NAME},
#{STATUS_NAME},
#{CREATE_USER},
NOW(),
#{UPDATE_USER},
NOW()
)
</insert>
<!-- E-BOM을 M-BOM으로 복사 -->
<insert id="saveMbomFromEbom" parameterType="map">
/* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */
@@ -3463,4 +3411,456 @@
PART_NAME = #{PART_NAME}
WHERE OBJID::VARCHAR = #{PROJECT_OBJID}
</insert>
<!-- M-BOM 관련 쿼리 -->
<!-- BOM 할당 정보 저장 (M-BOM 기준 설정) -->
<update id="saveBomAssignment" parameterType="map">
UPDATE PROJECT_MGMT
SET
SOURCE_BOM_TYPE = #{sourceBomType},
SOURCE_EBOM_OBJID = CASE WHEN #{sourceBomType} = 'EBOM' THEN #{sourceBomObjId} ELSE NULL END,
SOURCE_MBOM_OBJID = CASE WHEN #{sourceBomType} = 'MBOM' THEN #{sourceBomObjId} ELSE NULL END
WHERE OBJID::VARCHAR = #{projectObjId}
</update>
<!-- 프로젝트의 최신 저장된 M-BOM 조회 -->
<select id="getLatestMbomByProjectId" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
OBJID,
MBOM_NO,
SOURCE_BOM_TYPE,
SOURCE_EBOM_OBJID,
SOURCE_MBOM_OBJID,
PROJECT_OBJID,
STATUS,
REGDATE
FROM MBOM_HEADER
WHERE PROJECT_OBJID = #{projectObjId}
AND STATUS = 'Y'
ORDER BY REGDATE DESC
LIMIT 1
</select>
<!-- M-BOM 할당 정보 조회 -->
<select id="getMbomAssignment" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
PM.OBJID,
PM.SOURCE_BOM_TYPE,
PM.SOURCE_EBOM_OBJID,
PM.SOURCE_MBOM_OBJID,
PM.PART_NO,
PM.PART_NAME,
PM.PRODUCT,
CODE_NAME(PM.PRODUCT) AS PRODUCT_NAME,
-- E-BOM 정보
CASE WHEN PM.SOURCE_BOM_TYPE = 'EBOM' THEN
(SELECT PART_NO FROM PART_BOM_REPORT WHERE OBJID = PM.SOURCE_EBOM_OBJID)
END AS EBOM_PART_NO,
CASE WHEN PM.SOURCE_BOM_TYPE = 'EBOM' THEN
(SELECT PART_NAME FROM PART_BOM_REPORT WHERE OBJID = PM.SOURCE_EBOM_OBJID)
END AS EBOM_PART_NAME,
-- M-BOM 정보
CASE WHEN PM.SOURCE_BOM_TYPE = 'MBOM' THEN
(SELECT MBOM_NO FROM MBOM_HEADER WHERE OBJID = PM.SOURCE_MBOM_OBJID)
END AS MBOM_NO,
CASE WHEN PM.SOURCE_BOM_TYPE = 'MBOM' THEN
(SELECT PART_NAME FROM MBOM_HEADER WHERE OBJID = PM.SOURCE_MBOM_OBJID)
END AS MBOM_PART_NAME
FROM PROJECT_MGMT PM
WHERE PM.OBJID::VARCHAR = #{projectObjId}
</select>
<!-- M-BOM 품번 생성 - 같은 날짜의 최대 순번 조회 -->
<select id="getMaxMbomSeqByDate" parameterType="map" resultType="int">
SELECT COALESCE(MAX(
CAST(
SUBSTRING(
MBOM_NO FROM LENGTH(MBOM_NO) - 1 FOR 2
) AS INTEGER
)
), 0) AS MAX_SEQ
FROM MBOM_HEADER
WHERE MBOM_NO LIKE #{mbomPrefix} || '%'
AND REGDATE::DATE = CURRENT_DATE
</select>
<!-- M-BOM 품번으로 조회 -->
<select id="getMbomByNo" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT * FROM MBOM_HEADER
WHERE PROJECT_OBJID = #{projectObjId}
ORDER BY REGDATE DESC
LIMIT 1
</select>
<!-- MBOM_HEADER 삽입 -->
<insert id="insertMbomHeader" parameterType="map">
INSERT INTO MBOM_HEADER (
OBJID, MBOM_NO, SOURCE_BOM_TYPE, SOURCE_EBOM_OBJID, SOURCE_MBOM_OBJID,
PROJECT_OBJID, PART_NO, PART_NAME, STATUS, MBOM_STATUS,
WRITER, REGDATE
) VALUES (
#{objid}, #{mbomNo}, #{sourceBomType}, #{sourceEbomObjid}, #{sourceMbomObjid},
#{projectObjId}, #{partNo}, #{partName}, 'Y', 'DRAFT',
#{sessionUserId}, NOW()
)
</insert>
<!-- MBOM_DETAIL 삽입 -->
<insert id="insertMbomDetail" parameterType="map">
INSERT INTO MBOM_DETAIL (
OBJID, MBOM_HEADER_OBJID, PARENT_OBJID, CHILD_OBJID, SEQ, LEVEL,
PART_OBJID, PART_NO, PART_NAME, QTY, UNIT,
SUPPLY_TYPE, MAKE_OR_BUY,
RAW_MATERIAL_PART_NO, RAW_MATERIAL_SPEC, RAW_MATERIAL, RAW_MATERIAL_SIZE,
PROCESSING_VENDOR, PROCESSING_DEADLINE, GRINDING_DEADLINE,
REQUIRED_QTY, ORDER_QTY, PRODUCTION_QTY, STOCK_QTY, SHORTAGE_QTY,
VENDOR, UNIT_PRICE, TOTAL_PRICE, CURRENCY, LEAD_TIME, MIN_ORDER_QTY,
STATUS, WRITER, REGDATE, REMARK
) VALUES (
#{objid}, #{mbomHeaderObjid}, #{parentObjid}, #{childObjid}, #{seq}, #{level},
#{partObjid}, #{partNo}, #{partName}, #{qty}, #{unit},
#{supplyType}, #{makeOrBuy},
#{rawMaterialPartNo}, #{rawMaterialSpec}, #{rawMaterial}, #{rawMaterialSize},
#{processingVendor}, #{processingDeadline}, #{grindingDeadline},
#{requiredQty}, #{orderQty}, #{productionQty}, #{stockQty}, #{shortageQty},
#{vendor}, #{unitPrice}, #{totalPrice}, #{currency}, #{leadTime}, #{minOrderQty},
'ACTIVE', #{sessionUserId}, NOW(), #{remark}
)
</insert>
<!-- MBOM_HEADER 업데이트 -->
<update id="updateMbomHeader" parameterType="map">
UPDATE MBOM_HEADER
SET
PART_NO = #{partNo},
PART_NAME = #{partName},
EDITER = #{sessionUserId},
EDIT_DATE = NOW()
WHERE OBJID = #{mbomHeaderObjid}
</update>
<!-- MBOM_DETAIL 삭제 (수정 시 기존 데이터 삭제 후 재삽입) -->
<delete id="deleteMbomDetail" parameterType="map">
DELETE FROM MBOM_DETAIL
WHERE MBOM_HEADER_OBJID = #{mbomHeaderObjid}
</delete>
<!-- MBOM_HISTORY 삽입 -->
<insert id="insertMbomHistory" parameterType="map">
INSERT INTO MBOM_HISTORY (
OBJID, MBOM_HEADER_OBJID, CHANGE_TYPE, CHANGE_DESCRIPTION,
BEFORE_DATA, AFTER_DATA, CHANGE_USER, CHANGE_DATE
) VALUES (
#{objid}, #{mbomHeaderObjid}, #{changeType}, #{changeDescription},
#{beforeData}::JSONB, #{afterData}::JSONB, #{sessionUserId}, NOW()
)
</insert>
<!-- PROJECT_MGMT MBOM_STATUS 업데이트 -->
<update id="updateProjectMbomStatus" parameterType="map">
UPDATE PROJECT_MGMT
SET
MBOM_STATUS = 'Y',
MBOM_WRITER = #{sessionUserId},
MBOM_REGDATE = NOW()
WHERE OBJID::VARCHAR = #{projectObjId}
</update>
<!-- M-BOM 목록 조회 (셀렉트박스용) -->
<select id="getMbomListForSelect" parameterType="map" resultType="map">
SELECT
OBJID,
MBOM_NO,
SOURCE_BOM_TYPE,
REGDATE,
STATUS
FROM MBOM_HEADER
WHERE STATUS = 'Y'
ORDER BY REGDATE DESC, MBOM_NO
</select>
<!-- M-BOM 목록 (bizMakeOptionList용) -->
<select id="getMbomListForSelect2" parameterType="map" resultType="map">
SELECT
OBJID AS CODE,
COALESCE(MBOM_NO, '') ||
CASE WHEN SOURCE_BOM_TYPE IS NOT NULL AND SOURCE_BOM_TYPE != '' THEN ' (' || SOURCE_BOM_TYPE || ')' ELSE '' END AS NAME
FROM MBOM_HEADER
WHERE STATUS = 'Y'
ORDER BY REGDATE DESC, MBOM_NO
</select>
<!-- M-BOM 상세 리스트 조회 (이력용) -->
<select id="getMbomDetailList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
SELECT
OBJID,
MBOM_HEADER_OBJID,
PARENT_OBJID,
CHILD_OBJID,
SEQ,
LEVEL,
PART_OBJID,
PART_NO,
PART_NAME,
QTY,
UNIT,
SUPPLY_TYPE,
MAKE_OR_BUY,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_SPEC,
RAW_MATERIAL,
RAW_MATERIAL_SIZE,
PROCESSING_VENDOR,
PROCESSING_DEADLINE,
GRINDING_DEADLINE,
REQUIRED_QTY,
ORDER_QTY,
PRODUCTION_QTY,
STOCK_QTY,
SHORTAGE_QTY,
VENDOR,
UNIT_PRICE,
TOTAL_PRICE,
CURRENCY,
LEAD_TIME,
MIN_ORDER_QTY,
STATUS,
REMARK
FROM
MBOM_DETAIL
WHERE
MBOM_HEADER_OBJID = #{mbomHeaderObjid}
AND STATUS = 'ACTIVE'
ORDER BY SEQ
</select>
<!-- 저장된 M-BOM 트리 조회 (MBOM_DETAIL 테이블) -->
<select id="getSavedMbomTreeList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
WITH RECURSIVE VIEW_BOM(
MBOM_HEADER_OBJID,
OBJID,
PARENT_OBJID,
CHILD_OBJID,
PART_OBJID,
PART_NO,
PART_NAME,
QTY,
ITEM_QTY,
QTY_TEMP,
REGDATE,
SEQ,
STATUS,
LEV,
PATH,
PATH2,
CYCLE,
UNIT,
SUPPLY_TYPE,
MAKE_OR_BUY,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_SPEC,
RAW_MATERIAL,
RAW_MATERIAL_SIZE,
PROCESSING_VENDOR,
PROCESSING_DEADLINE,
GRINDING_DEADLINE,
REQUIRED_QTY,
ORDER_QTY,
PRODUCTION_QTY,
STOCK_QTY,
SHORTAGE_QTY,
VENDOR,
UNIT_PRICE,
TOTAL_PRICE,
CURRENCY,
LEAD_TIME,
MIN_ORDER_QTY,
WRITER,
EDITER,
EDIT_DATE,
REMARK
) AS (
SELECT
A.MBOM_HEADER_OBJID,
A.OBJID,
A.PARENT_OBJID,
A.CHILD_OBJID,
A.PART_OBJID,
A.PART_NO,
A.PART_NAME,
A.QTY,
A.QTY,
A.QTY,
A.REGDATE,
A.SEQ,
A.STATUS,
1,
ARRAY [A.CHILD_OBJID::TEXT],
ARRAY [A.SEQ::TEXT],
FALSE,
A.UNIT,
A.SUPPLY_TYPE,
A.MAKE_OR_BUY,
A.RAW_MATERIAL_PART_NO,
A.RAW_MATERIAL_SPEC,
A.RAW_MATERIAL,
A.RAW_MATERIAL_SIZE,
A.PROCESSING_VENDOR,
A.PROCESSING_DEADLINE,
A.GRINDING_DEADLINE,
A.REQUIRED_QTY,
A.ORDER_QTY,
A.PRODUCTION_QTY,
A.STOCK_QTY,
A.SHORTAGE_QTY,
A.VENDOR,
A.UNIT_PRICE,
A.TOTAL_PRICE,
A.CURRENCY,
A.LEAD_TIME,
A.MIN_ORDER_QTY,
A.WRITER,
A.EDITER,
A.EDIT_DATE,
A.REMARK
FROM
MBOM_DETAIL A
WHERE 1=1
AND (A.PARENT_OBJID IS NULL OR A.PARENT_OBJID = '')
AND A.MBOM_HEADER_OBJID = #{mbomHeaderObjid}
AND A.STATUS = 'ACTIVE'
UNION ALL
SELECT
B.MBOM_HEADER_OBJID,
B.OBJID,
B.PARENT_OBJID,
B.CHILD_OBJID,
B.PART_OBJID,
B.PART_NO,
B.PART_NAME,
B.QTY,
B.QTY,
B.QTY,
B.REGDATE,
B.SEQ,
B.STATUS,
LEV + 1,
PATH||B.CHILD_OBJID::TEXT,
PATH2||B.SEQ::TEXT,
B.PARENT_OBJID = ANY(PATH),
B.UNIT,
B.SUPPLY_TYPE,
B.MAKE_OR_BUY,
B.RAW_MATERIAL_PART_NO,
B.RAW_MATERIAL_SPEC,
B.RAW_MATERIAL,
B.RAW_MATERIAL_SIZE,
B.PROCESSING_VENDOR,
B.PROCESSING_DEADLINE,
B.GRINDING_DEADLINE,
B.REQUIRED_QTY,
B.ORDER_QTY,
B.PRODUCTION_QTY,
B.STOCK_QTY,
B.SHORTAGE_QTY,
B.VENDOR,
B.UNIT_PRICE,
B.TOTAL_PRICE,
B.CURRENCY,
B.LEAD_TIME,
B.MIN_ORDER_QTY,
B.WRITER,
B.EDITER,
B.EDIT_DATE,
B.REMARK
FROM
MBOM_DETAIL B
JOIN
VIEW_BOM
ON B.PARENT_OBJID = VIEW_BOM.CHILD_OBJID
AND VIEW_BOM.MBOM_HEADER_OBJID = B.MBOM_HEADER_OBJID
AND B.STATUS = 'ACTIVE'
)
SELECT
V.MBOM_HEADER_OBJID AS BOM_REPORT_OBJID,
V.OBJID,
V.PARENT_OBJID,
V.CHILD_OBJID,
V.PART_OBJID,
V.PART_OBJID AS LAST_PART_OBJID,
V.PART_OBJID AS BOM_LAST_PART_OBJID,
V.PART_NO,
V.PART_NAME,
V.QTY,
V.ITEM_QTY,
V.QTY_TEMP,
V.LEV AS LEVEL,
(SELECT COUNT(*) FROM MBOM_DETAIL WHERE PARENT_OBJID = V.CHILD_OBJID) AS SUB_PART_CNT,
V.SEQ,
V.STATUS,
-- M-BOM 전용 필드
V.UNIT,
V.SUPPLY_TYPE,
V.MAKE_OR_BUY,
V.RAW_MATERIAL_PART_NO AS RAW_MATERIAL_NO,
V.RAW_MATERIAL_SPEC,
V.RAW_MATERIAL,
V.RAW_MATERIAL_SIZE AS SIZE,
V.PROCESSING_VENDOR,
V.PROCESSING_DEADLINE,
V.GRINDING_DEADLINE,
V.REQUIRED_QTY,
V.ORDER_QTY,
V.PRODUCTION_QTY,
V.STOCK_QTY,
V.SHORTAGE_QTY,
V.VENDOR,
V.UNIT_PRICE,
V.TOTAL_PRICE,
V.CURRENCY,
V.LEAD_TIME,
V.MIN_ORDER_QTY,
V.WRITER,
TO_CHAR(V.REGDATE, 'YYYY-MM-DD HH24:MI:SS') AS REGDATE,
V.EDITER,
CASE WHEN V.EDIT_DATE IS NOT NULL THEN TO_CHAR(V.EDIT_DATE, 'YYYY-MM-DD HH24:MI:SS') ELSE NULL END AS EDIT_DATE,
V.REMARK,
-- E-BOM 호환 필드
NULL AS PARENT_PART_NO,
NULL AS CONTRACT_OBJID,
CASE WHEN V.LEV = 1 THEN V.OBJID ELSE NULL END AS ROOT_OBJID,
CASE WHEN V.LEV = 1 THEN V.OBJID ELSE NULL END AS SUB_ROOT_OBJID,
1 AS LEAF,
-- PART_MNG 테이블에서 추가 정보
P.SPEC,
P.MATERIAL,
P.WEIGHT,
P.PART_TYPE,
P.REVISION,
P.MAKER,
P.THICKNESS,
P.WIDTH,
P.HEIGHT,
P.OUT_DIAMETER,
P.IN_DIAMETER,
P.LENGTH,
P.SOURCING_CODE,
P.HEAT_TREATMENT_HARDNESS,
P.HEAT_TREATMENT_METHOD,
P.SURFACE_TREATMENT,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.UNIT) AS UNIT_TITLE,
(SELECT CODE_NAME FROM COMM_CODE CC WHERE CC.CODE_ID = P.PART_TYPE) AS PART_TYPE_TITLE,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('3D_CAD')) AS CU01_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_DRAWING_CAD')) AS CU02_CNT,
(SELECT COUNT(1) FROM ATTACH_FILE_INFO F WHERE P.OBJID = F.TARGET_OBJID AND F.STATUS = 'Active' AND F.DOC_TYPE IN ('2D_PDF_CAD')) AS CU03_CNT,
V.LEV
FROM VIEW_BOM V
INNER JOIN PART_MNG P ON P.OBJID = V.PART_OBJID
WHERE 1=1
ORDER BY V.PATH2
</select>
</mapper>

View File

@@ -2773,5 +2773,127 @@ UPDATE SET
,QTY = #{QTY }
,NOTE = #{NOTE }
</update>
<!-- 구매리스트 관련 쿼리 -->
<select id="getSalesRequestPartList" parameterType="string" resultType="map">
SELECT
SRP.OBJID,
SRP.PART_OBJID,
PM.PART_NO,
PM.PART_NAME,
SRP.QTY,
SRP.PARTNER_OBJID,
SRP.PARTNER_PRICE
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID = PM.OBJID::VARCHAR
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY SRP.REGDATE
</select>
<update id="mergePurchaseListInfo" parameterType="map">
INSERT INTO SALES_REQUEST_PART (
OBJID,
SALES_REQUEST_MASTER_OBJID,
PART_NO,
PART_NAME,
QTY,
ITEM_QTY,
FILE_3D,
FILE_2D,
FILE_PDF,
MATERIAL,
HEAT_TREATMENT_HARDNESS,
HEAT_TREATMENT_METHOD,
SURFACE_TREATMENT,
SUPPLIER,
CATEGORY_NAME,
SUPPLY_TYPE,
RAW_MATERIAL,
SIZE,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_REQUIRED_QTY,
RAW_MATERIAL_ORDER_QTY,
ITEM_QTY2,
PRODUCTION_QTY,
PROCESSING_COMPANY,
PROCESSING_DELIVERY_DATE,
GRINDING_DELIVERY_DATE,
USE_YN,
NET_QTY,
ORDER_QTY,
SUPPLIER2,
UNIT_PRICE,
TOTAL_PRICE,
PROPOSAL_DATE,
WRITER,
REGDATE
) VALUES (
#{OBJID},
#{SALES_REQUEST_MASTER_OBJID},
#{PART_NO},
#{PART_NAME},
#{QTY},
#{ITEM_QTY},
#{FILE_3D},
#{FILE_2D},
#{FILE_PDF},
#{MATERIAL},
#{HEAT_TREATMENT_HARDNESS},
#{HEAT_TREATMENT_METHOD},
#{SURFACE_TREATMENT},
#{SUPPLIER},
#{CATEGORY_NAME},
#{SUPPLY_TYPE},
#{RAW_MATERIAL},
#{SIZE},
#{RAW_MATERIAL_PART_NO},
#{RAW_MATERIAL_REQUIRED_QTY},
#{RAW_MATERIAL_ORDER_QTY},
#{ITEM_QTY2},
#{PRODUCTION_QTY},
#{PROCESSING_COMPANY},
CASE WHEN #{PROCESSING_DELIVERY_DATE} = '' THEN NULL ELSE #{PROCESSING_DELIVERY_DATE}::date END,
CASE WHEN #{GRINDING_DELIVERY_DATE} = '' THEN NULL ELSE #{GRINDING_DELIVERY_DATE}::date END,
#{USE_YN},
#{NET_QTY},
#{ORDER_QTY},
#{SUPPLIER2},
#{UNIT_PRICE},
#{TOTAL_PRICE},
CASE WHEN #{PROPOSAL_DATE} = '' THEN NOW() ELSE #{PROPOSAL_DATE}::date END,
#{WRITER},
NOW()
) ON CONFLICT (OBJID) DO
UPDATE SET
ITEM_QTY = #{ITEM_QTY},
FILE_3D = #{FILE_3D},
FILE_2D = #{FILE_2D},
FILE_PDF = #{FILE_PDF},
MATERIAL = #{MATERIAL},
HEAT_TREATMENT_HARDNESS = #{HEAT_TREATMENT_HARDNESS},
HEAT_TREATMENT_METHOD = #{HEAT_TREATMENT_METHOD},
SURFACE_TREATMENT = #{SURFACE_TREATMENT},
SUPPLIER = #{SUPPLIER},
CATEGORY_NAME = #{CATEGORY_NAME},
SUPPLY_TYPE = #{SUPPLY_TYPE},
RAW_MATERIAL = #{RAW_MATERIAL},
SIZE = #{SIZE},
RAW_MATERIAL_PART_NO = #{RAW_MATERIAL_PART_NO},
RAW_MATERIAL_REQUIRED_QTY = #{RAW_MATERIAL_REQUIRED_QTY},
RAW_MATERIAL_ORDER_QTY = #{RAW_MATERIAL_ORDER_QTY},
ITEM_QTY2 = #{ITEM_QTY2},
PRODUCTION_QTY = #{PRODUCTION_QTY},
PROCESSING_COMPANY = #{PROCESSING_COMPANY},
PROCESSING_DELIVERY_DATE = CASE WHEN #{PROCESSING_DELIVERY_DATE} = '' THEN NULL ELSE #{PROCESSING_DELIVERY_DATE}::date END,
GRINDING_DELIVERY_DATE = CASE WHEN #{GRINDING_DELIVERY_DATE} = '' THEN NULL ELSE #{GRINDING_DELIVERY_DATE}::date END,
USE_YN = #{USE_YN},
NET_QTY = #{NET_QTY},
ORDER_QTY = #{ORDER_QTY},
SUPPLIER2 = #{SUPPLIER2},
UNIT_PRICE = #{UNIT_PRICE},
TOTAL_PRICE = #{TOTAL_PRICE}
</update>
</mapper>

View File

@@ -39,6 +39,11 @@ $(document).ready(function(){
fn_openBomCopyPopup();
});
// 구매리스트 생성 버튼
$("#btnCreatePurchaseList").click(function(){
fn_openPurchaseListPopup();
});
// 전체 체크박스
$(document).on('click', '#checkAll', function() {
$('.rowCheck').prop('checked', $(this).prop('checked'));
@@ -407,6 +412,44 @@ function fn_checkAssignmentAndOpenMbom(projectObjId) {
}
});
}
// 구매리스트 생성 팝업 열기
function fn_openPurchaseListPopup() {
// 체크된 행 가져오기
var checkedRows = [];
$('.rowCheck:checked').each(function() {
var objid = $(this).data('objid');
if(_tabulGrid && _tabulGrid.getRow) {
var rowData = _tabulGrid.getRow(objid).getData();
checkedRows.push(rowData);
}
});
if(checkedRows.length == 0) {
Swal.fire({
title: '알림',
text: '구매리스트를 생성할 프로젝트를 선택해주세요.',
icon: 'info'
});
return;
}
if(checkedRows.length > 1) {
Swal.fire({
title: '알림',
text: '한 번에 하나의 프로젝트만 선택해주세요.',
icon: 'info'
});
return;
}
// 선택된 프로젝트의 OBJID
var projectObjId = checkedRows[0].OBJID;
// 구매리스트 팝업 열기
var url = "/salesMng/purchaseListFormPopUp.do?SALES_REQUEST_MASTER_OBJID=" + projectObjId;
window.open(url, "purchaseListPopup", "width=1400,height=800,scrollbars=yes,resizable=yes");
}
</script>
<!-- hiddenForm: POST 방식 팝업 전송용 -->

View File

@@ -0,0 +1,407 @@
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ page import="com.pms.common.utils.*"%>
<%@ page import="java.util.*" %>
<%@include file="/init.jsp"%>
<c:set var="now" value="<%=new java.util.Date() %>"/>
<c:set var="sysYear"><fmt:formatDate value="${now}" pattern="yyyy" /></c:set>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><%=Constants.SYSTEM_NAME%></title>
<script>
$(document).ready(function(){
$('.select2').select2();
// 행추가 버튼
$("#btnAddRow").click(function(){
fn_AddRow();
});
// 행삭제 버튼
$("#btnDeleteRow").click(function(){
fn_DeleteRow();
});
// 저장 버튼
$("#btnSave").click(function(){
fn_save();
});
// 닫기 버튼
$("#btnClose").click(function(){
window.close();
});
// 초기 데이터 로드
fn_loadPurchaseList();
});
// 구매리스트 데이터 로드
function fn_loadPurchaseList() {
var salesRequestMasterObjid = "${param.SALES_REQUEST_MASTER_OBJID}";
if(!salesRequestMasterObjid || salesRequestMasterObjid == "") {
return;
}
$.ajax({
url: "/salesMng/getPurchaseListData.do",
type: "POST",
data: {
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid
},
dataType: "json",
success: function(response) {
if(response.partList && response.partList.length > 0) {
$("#partListArea").empty();
$.each(response.partList, function(i, part) {
fn_AddRow(part);
});
}
},
error: function(xhr, status, error) {
console.error("데이터 로드 오류:", error);
}
});
}
// 행추가
function fn_AddRow(data) {
var rowNum = $("#partListArea tr").length + 1;
var objid = data ? data.OBJID : "";
var partNo = data ? data.PART_NO : "";
var partName = data ? data.PART_NAME : "";
var qty = data ? data.QTY : "";
var html = "";
html += "<tr id='row_" + rowNum + "'>";
html += " <td><input type='checkbox' name='rowCheck' class='rowCheck'></td>";
html += " <td>" + rowNum + "</td>";
html += " <td><input type='text' name='PART_NO' value='" + partNo + "' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='PART_NAME' value='" + partName + "' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='QTY' value='" + qty + "' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='ITEM_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='FILE_3D' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='FILE_2D' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='FILE_PDF' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='MATERIAL' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='HEAT_TREATMENT_HARDNESS' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='HEAT_TREATMENT_METHOD' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SURFACE_TREATMENT' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SUPPLIER' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='CATEGORY_NAME' value='' style='width:100%;'></td>";
html += " <td><select name='SUPPLY_TYPE' style='width:100%;'><option value=''>선택</option><option value='지급'>지급</option><option value='사급'>사급</option></select></td>";
html += " <td><input type='text' name='RAW_MATERIAL' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SIZE' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='RAW_MATERIAL_PART_NO' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='RAW_MATERIAL_REQUIRED_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='RAW_MATERIAL_ORDER_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='ITEM_QTY2' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='PRODUCTION_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='PROCESSING_COMPANY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='PROCESSING_DELIVERY_DATE' value='' style='width:100%;' class='date_icon'></td>";
html += " <td><input type='text' name='GRINDING_DELIVERY_DATE' value='' style='width:100%;' class='date_icon'></td>";
html += " <td><select name='USE_YN' style='width:100%;'><option value='Y' selected>Y</option><option value='N'>N</option></select></td>";
html += " <td><input type='text' name='NET_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='ORDER_QTY' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='SUPPLIER2' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='UNIT_PRICE' value='' style='width:100%;'></td>";
html += " <td><input type='text' name='TOTAL_PRICE' value='' style='width:100%;' readonly></td>";
html += " <td><input type='text' name='PROPOSAL_DATE' value='' style='width:100%;' readonly></td>";
html += " <input type='hidden' name='OBJID' value='" + objid + "'>";
html += "</tr>";
$("#partListArea").append(html);
// 날짜 선택기 초기화
_fnc_datepick();
// 단가 * 수량 = 총단가 자동 계산
$("#row_" + rowNum + " input[name='UNIT_PRICE'], #row_" + rowNum + " input[name='ORDER_QTY']").on("keyup", function() {
var row = $(this).closest("tr");
var unitPrice = parseFloat(row.find("input[name='UNIT_PRICE']").val()) || 0;
var orderQty = parseFloat(row.find("input[name='ORDER_QTY']").val()) || 0;
var totalPrice = unitPrice * orderQty;
row.find("input[name='TOTAL_PRICE']").val(totalPrice);
});
}
// 행삭제
function fn_DeleteRow() {
var checkedRows = $("input[name='rowCheck']:checked");
if(checkedRows.length == 0) {
Swal.fire({
title: '알림',
text: '삭제할 행을 선택해주세요.',
icon: 'info'
});
return;
}
checkedRows.each(function() {
$(this).closest("tr").remove();
});
// 행 번호 재정렬
$("#partListArea tr").each(function(i) {
$(this).find("td:eq(1)").text(i + 1);
});
}
// 저장
function fn_save() {
var salesRequestMasterObjid = "${param.SALES_REQUEST_MASTER_OBJID}";
if(!salesRequestMasterObjid || salesRequestMasterObjid == "") {
Swal.fire({
title: '오류',
text: '구매요청서 정보가 없습니다.',
icon: 'error'
});
return;
}
// 테이블 데이터 수집
var partList = [];
$("#partListArea tr").each(function() {
var row = $(this);
var partData = {
OBJID: row.find("input[name='OBJID']").val(),
PART_NO: row.find("input[name='PART_NO']").val(),
PART_NAME: row.find("input[name='PART_NAME']").val(),
QTY: row.find("input[name='QTY']").val(),
ITEM_QTY: row.find("input[name='ITEM_QTY']").val(),
FILE_3D: row.find("input[name='FILE_3D']").val(),
FILE_2D: row.find("input[name='FILE_2D']").val(),
FILE_PDF: row.find("input[name='FILE_PDF']").val(),
MATERIAL: row.find("input[name='MATERIAL']").val(),
HEAT_TREATMENT_HARDNESS: row.find("input[name='HEAT_TREATMENT_HARDNESS']").val(),
HEAT_TREATMENT_METHOD: row.find("input[name='HEAT_TREATMENT_METHOD']").val(),
SURFACE_TREATMENT: row.find("input[name='SURFACE_TREATMENT']").val(),
SUPPLIER: row.find("input[name='SUPPLIER']").val(),
CATEGORY_NAME: row.find("input[name='CATEGORY_NAME']").val(),
SUPPLY_TYPE: row.find("select[name='SUPPLY_TYPE']").val(),
RAW_MATERIAL: row.find("input[name='RAW_MATERIAL']").val(),
SIZE: row.find("input[name='SIZE']").val(),
RAW_MATERIAL_PART_NO: row.find("input[name='RAW_MATERIAL_PART_NO']").val(),
RAW_MATERIAL_REQUIRED_QTY: row.find("input[name='RAW_MATERIAL_REQUIRED_QTY']").val(),
RAW_MATERIAL_ORDER_QTY: row.find("input[name='RAW_MATERIAL_ORDER_QTY']").val(),
ITEM_QTY2: row.find("input[name='ITEM_QTY2']").val(),
PRODUCTION_QTY: row.find("input[name='PRODUCTION_QTY']").val(),
PROCESSING_COMPANY: row.find("input[name='PROCESSING_COMPANY']").val(),
PROCESSING_DELIVERY_DATE: row.find("input[name='PROCESSING_DELIVERY_DATE']").val(),
GRINDING_DELIVERY_DATE: row.find("input[name='GRINDING_DELIVERY_DATE']").val(),
USE_YN: row.find("select[name='USE_YN']").val(),
NET_QTY: row.find("input[name='NET_QTY']").val(),
ORDER_QTY: row.find("input[name='ORDER_QTY']").val(),
SUPPLIER2: row.find("input[name='SUPPLIER2']").val(),
UNIT_PRICE: row.find("input[name='UNIT_PRICE']").val(),
TOTAL_PRICE: row.find("input[name='TOTAL_PRICE']").val()
};
partList.push(partData);
});
if(partList.length == 0) {
Swal.fire({
title: '알림',
text: '저장할 데이터가 없습니다.',
icon: 'info'
});
return;
}
Swal.fire({
title: '저장',
text: '구매리스트를 저장하시겠습니까?',
icon: 'question',
showCancelButton: true,
confirmButtonText: '저장',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
$.ajax({
url: "/salesMng/savePurchaseList.do",
type: "POST",
data: {
SALES_REQUEST_MASTER_OBJID: salesRequestMasterObjid,
partList: JSON.stringify(partList)
},
dataType: "json",
success: function(response) {
if(response.result == "success") {
Swal.fire({
title: '완료',
text: '저장되었습니다.',
icon: 'success'
}).then(() => {
if(opener && opener.fn_search) {
opener.fn_search();
}
window.close();
});
} else {
Swal.fire({
title: '오류',
text: response.message || '저장 중 오류가 발생했습니다.',
icon: 'error'
});
}
},
error: function(xhr, status, error) {
console.error("저장 오류:", error);
Swal.fire({
title: '오류',
text: '저장 중 오류가 발생했습니다.',
icon: 'error'
});
}
});
}
});
}
// 날짜 선택기 초기화
function _fnc_datepick(){
var $dateinput = $("input.date_icon");
for(var i=0; i<$dateinput.length; i++){
$dateinput.eq(i).attr("size","10");
$dateinput.eq(i).datepicker({
changeMonth:true,
changeYear:true
});
}
}
</script>
<style>
.purchase_list_table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.purchase_list_table th {
background-color: #f5f5f5;
border: 1px solid #ddd;
padding: 8px;
text-align: center;
font-weight: bold;
}
.purchase_list_table td {
border: 1px solid #ddd;
padding: 4px;
text-align: center;
}
.purchase_list_table input[type="text"],
.purchase_list_table select {
border: 1px solid #ccc;
padding: 2px;
}
</style>
</head>
<body>
<form name="form1" id="form1" method="post">
<input type="hidden" name="SALES_REQUEST_MASTER_OBJID" value="${param.SALES_REQUEST_MASTER_OBJID}">
<section>
<div class="plm_menu_name" style="display:flex;">
<h2 style="width:100%;height:60px;text-align:center;margin-top:15px;">
<span style="font-size:24px;">구매리스트 작성</span>
</h2>
</div>
<div class="btn_wrap">
<div class="plm_btn_wrap" style="padding:0 8 0 8; text-align: right;">
<input type="button" value="행추가" class="plm_btns" id="btnAddRow">
<input type="button" value="행삭제" class="plm_btns" id="btnDeleteRow">
<input type="button" value="저장" class="plm_btns" id="btnSave">
<input type="button" value="닫기" class="plm_btns" id="btnClose">
</div>
</div>
<div style="overflow-x:auto; overflow-y:auto; max-height:600px;">
<table class="purchase_list_table">
<colgroup>
<col width="30px">
<col width="40px">
<col width="120px">
<col width="150px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="100px">
<col width="100px">
<col width="100px">
<col width="100px">
<col width="120px">
<col width="100px">
<col width="80px">
<col width="100px">
<col width="100px">
<col width="120px">
<col width="100px">
<col width="100px">
<col width="80px">
<col width="80px">
<col width="120px">
<col width="100px">
<col width="100px">
<col width="80px">
<col width="80px">
<col width="80px">
<col width="120px">
<col width="80px">
<col width="80px">
<col width="100px">
</colgroup>
<thead>
<tr>
<th><input type="checkbox" id="allCheck"></th>
<th>NO</th>
<th>품번</th>
<th>품명</th>
<th>수량</th>
<th>항목수량</th>
<th>3D</th>
<th>2D</th>
<th>PDF</th>
<th>재료</th>
<th>열처리경도</th>
<th>열처리방법</th>
<th>표면처리</th>
<th>공급업체</th>
<th>범주이름</th>
<th>지급/사급</th>
<th>소재</th>
<th>사이즈</th>
<th>소재품번</th>
<th>소재소요량</th>
<th>소재발주수량</th>
<th>항목수량</th>
<th>제작수량</th>
<th>가공업체</th>
<th>가공납기</th>
<th>연삭납기</th>
<th>사용여부</th>
<th>정미수량</th>
<th>발주수량</th>
<th>공급업체</th>
<th>단가</th>
<th>총단가</th>
<th>품의서작성일</th>
</tr>
</thead>
<tbody id="partListArea">
<!-- 동적으로 행 추가 -->
</tbody>
</table>
</div>
</section>
</form>
</body>
</html>

View File

@@ -0,0 +1,63 @@
-- SALES_REQUEST_PART 테이블에 구매리스트 관련 컬럼 추가
-- 구매리스트 작성 시 필요한 추가 정보들
ALTER TABLE SALES_REQUEST_PART
ADD COLUMN IF NOT EXISTS ITEM_QTY VARCHAR(50), -- 항목수량
ADD COLUMN IF NOT EXISTS FILE_3D VARCHAR(200), -- 3D
ADD COLUMN IF NOT EXISTS FILE_2D VARCHAR(200), -- 2D
ADD COLUMN IF NOT EXISTS FILE_PDF VARCHAR(200), -- PDF
ADD COLUMN IF NOT EXISTS MATERIAL VARCHAR(200), -- 재료
ADD COLUMN IF NOT EXISTS HEAT_TREATMENT_HARDNESS VARCHAR(100), -- 열처리경도
ADD COLUMN IF NOT EXISTS HEAT_TREATMENT_METHOD VARCHAR(100), -- 열처리방법
ADD COLUMN IF NOT EXISTS SURFACE_TREATMENT VARCHAR(100), -- 표면처리
ADD COLUMN IF NOT EXISTS SUPPLIER VARCHAR(200), -- 공급업체
ADD COLUMN IF NOT EXISTS CATEGORY_NAME VARCHAR(100), -- 범주이름
ADD COLUMN IF NOT EXISTS SUPPLY_TYPE VARCHAR(50), -- 지급/사급
ADD COLUMN IF NOT EXISTS RAW_MATERIAL VARCHAR(200), -- 소재
ADD COLUMN IF NOT EXISTS SIZE VARCHAR(100), -- 사이즈
ADD COLUMN IF NOT EXISTS RAW_MATERIAL_PART_NO VARCHAR(100), -- 소재품번
ADD COLUMN IF NOT EXISTS RAW_MATERIAL_REQUIRED_QTY VARCHAR(50), -- 소재소요량
ADD COLUMN IF NOT EXISTS RAW_MATERIAL_ORDER_QTY VARCHAR(50), -- 소재발주수량
ADD COLUMN IF NOT EXISTS ITEM_QTY2 VARCHAR(50), -- 항목수량
ADD COLUMN IF NOT EXISTS PRODUCTION_QTY VARCHAR(50), -- 제작수량
ADD COLUMN IF NOT EXISTS PROCESSING_COMPANY VARCHAR(200), -- 가공업체
ADD COLUMN IF NOT EXISTS PROCESSING_DELIVERY_DATE DATE, -- 가공납기
ADD COLUMN IF NOT EXISTS GRINDING_DELIVERY_DATE DATE, -- 연삭납기
ADD COLUMN IF NOT EXISTS USE_YN VARCHAR(1) DEFAULT 'Y', -- 사용여부
ADD COLUMN IF NOT EXISTS NET_QTY VARCHAR(50), -- 정미수량
ADD COLUMN IF NOT EXISTS ORDER_QTY VARCHAR(50), -- 발주수량
ADD COLUMN IF NOT EXISTS SUPPLIER2 VARCHAR(200), -- 공급업체
ADD COLUMN IF NOT EXISTS UNIT_PRICE VARCHAR(50), -- 단가
ADD COLUMN IF NOT EXISTS TOTAL_PRICE VARCHAR(50), -- 총단가
ADD COLUMN IF NOT EXISTS PROPOSAL_DATE DATE; -- 품의서작성일
-- 컬럼 설명
COMMENT ON COLUMN SALES_REQUEST_PART.ITEM_QTY IS '항목수량';
COMMENT ON COLUMN SALES_REQUEST_PART.FILE_3D IS '3D';
COMMENT ON COLUMN SALES_REQUEST_PART.FILE_2D IS '2D';
COMMENT ON COLUMN SALES_REQUEST_PART.FILE_PDF IS 'PDF';
COMMENT ON COLUMN SALES_REQUEST_PART.MATERIAL IS '재료';
COMMENT ON COLUMN SALES_REQUEST_PART.HEAT_TREATMENT_HARDNESS IS '열처리경도';
COMMENT ON COLUMN SALES_REQUEST_PART.HEAT_TREATMENT_METHOD IS '열처리방법';
COMMENT ON COLUMN SALES_REQUEST_PART.SURFACE_TREATMENT IS '표면처리';
COMMENT ON COLUMN SALES_REQUEST_PART.SUPPLIER IS '공급업체';
COMMENT ON COLUMN SALES_REQUEST_PART.CATEGORY_NAME IS '범주이름';
COMMENT ON COLUMN SALES_REQUEST_PART.SUPPLY_TYPE IS '지급/사급';
COMMENT ON COLUMN SALES_REQUEST_PART.RAW_MATERIAL IS '소재';
COMMENT ON COLUMN SALES_REQUEST_PART.SIZE IS '사이즈';
COMMENT ON COLUMN SALES_REQUEST_PART.RAW_MATERIAL_PART_NO IS '소재품번';
COMMENT ON COLUMN SALES_REQUEST_PART.RAW_MATERIAL_REQUIRED_QTY IS '소재소요량';
COMMENT ON COLUMN SALES_REQUEST_PART.RAW_MATERIAL_ORDER_QTY IS '소재발주수량';
COMMENT ON COLUMN SALES_REQUEST_PART.ITEM_QTY2 IS '항목수량';
COMMENT ON COLUMN SALES_REQUEST_PART.PRODUCTION_QTY IS '제작수량';
COMMENT ON COLUMN SALES_REQUEST_PART.PROCESSING_COMPANY IS '가공업체';
COMMENT ON COLUMN SALES_REQUEST_PART.PROCESSING_DELIVERY_DATE IS '가공납기';
COMMENT ON COLUMN SALES_REQUEST_PART.GRINDING_DELIVERY_DATE IS '연삭납기';
COMMENT ON COLUMN SALES_REQUEST_PART.USE_YN IS '사용여부';
COMMENT ON COLUMN SALES_REQUEST_PART.NET_QTY IS '정미수량';
COMMENT ON COLUMN SALES_REQUEST_PART.ORDER_QTY IS '발주수량';
COMMENT ON COLUMN SALES_REQUEST_PART.SUPPLIER2 IS '공급업체';
COMMENT ON COLUMN SALES_REQUEST_PART.UNIT_PRICE IS '단가';
COMMENT ON COLUMN SALES_REQUEST_PART.TOTAL_PRICE IS '총단가';
COMMENT ON COLUMN SALES_REQUEST_PART.PROPOSAL_DATE IS '품의서작성일';

View File

@@ -0,0 +1,80 @@
-- 구매리스트 테이블 생성
CREATE TABLE IF NOT EXISTS PURCHASE_LIST (
OBJID VARCHAR(50) PRIMARY KEY,
SALES_REQUEST_MASTER_OBJID VARCHAR(50),
PART_NO VARCHAR(100),
PART_NAME VARCHAR(200),
QTY VARCHAR(50),
ITEM_QTY VARCHAR(50),
FILE_3D VARCHAR(200),
FILE_2D VARCHAR(200),
FILE_PDF VARCHAR(200),
MATERIAL VARCHAR(200),
HEAT_TREATMENT_HARDNESS VARCHAR(100),
HEAT_TREATMENT_METHOD VARCHAR(100),
SURFACE_TREATMENT VARCHAR(100),
SUPPLIER VARCHAR(200),
CATEGORY_NAME VARCHAR(100),
SUPPLY_TYPE VARCHAR(50),
RAW_MATERIAL VARCHAR(200),
SIZE VARCHAR(100),
RAW_MATERIAL_PART_NO VARCHAR(100),
RAW_MATERIAL_REQUIRED_QTY VARCHAR(50),
RAW_MATERIAL_ORDER_QTY VARCHAR(50),
ITEM_QTY2 VARCHAR(50),
PRODUCTION_QTY VARCHAR(50),
PROCESSING_COMPANY VARCHAR(200),
PROCESSING_DELIVERY_DATE DATE,
GRINDING_DELIVERY_DATE DATE,
USE_YN VARCHAR(1) DEFAULT 'Y',
NET_QTY VARCHAR(50),
ORDER_QTY VARCHAR(50),
SUPPLIER2 VARCHAR(200),
UNIT_PRICE VARCHAR(50),
TOTAL_PRICE VARCHAR(50),
PROPOSAL_DATE DATE,
WRITER VARCHAR(50),
REGDATE TIMESTAMP DEFAULT NOW()
);
-- 인덱스 생성
CREATE INDEX IF NOT EXISTS idx_purchase_list_sales_request ON PURCHASE_LIST(SALES_REQUEST_MASTER_OBJID);
-- 컬럼 설명
COMMENT ON TABLE PURCHASE_LIST IS '구매리스트';
COMMENT ON COLUMN PURCHASE_LIST.OBJID IS 'OBJID';
COMMENT ON COLUMN PURCHASE_LIST.SALES_REQUEST_MASTER_OBJID IS '구매요청서 OBJID';
COMMENT ON COLUMN PURCHASE_LIST.PART_NO IS '품번';
COMMENT ON COLUMN PURCHASE_LIST.PART_NAME IS '품명';
COMMENT ON COLUMN PURCHASE_LIST.QTY IS '수량';
COMMENT ON COLUMN PURCHASE_LIST.ITEM_QTY IS '항목수량';
COMMENT ON COLUMN PURCHASE_LIST.FILE_3D IS '3D';
COMMENT ON COLUMN PURCHASE_LIST.FILE_2D IS '2D';
COMMENT ON COLUMN PURCHASE_LIST.FILE_PDF IS 'PDF';
COMMENT ON COLUMN PURCHASE_LIST.MATERIAL IS '재료';
COMMENT ON COLUMN PURCHASE_LIST.HEAT_TREATMENT_HARDNESS IS '열처리경도';
COMMENT ON COLUMN PURCHASE_LIST.HEAT_TREATMENT_METHOD IS '열처리방법';
COMMENT ON COLUMN PURCHASE_LIST.SURFACE_TREATMENT IS '표면처리';
COMMENT ON COLUMN PURCHASE_LIST.SUPPLIER IS '공급업체';
COMMENT ON COLUMN PURCHASE_LIST.CATEGORY_NAME IS '범주이름';
COMMENT ON COLUMN PURCHASE_LIST.SUPPLY_TYPE IS '지급/사급';
COMMENT ON COLUMN PURCHASE_LIST.RAW_MATERIAL IS '소재';
COMMENT ON COLUMN PURCHASE_LIST.SIZE IS '사이즈';
COMMENT ON COLUMN PURCHASE_LIST.RAW_MATERIAL_PART_NO IS '소재품번';
COMMENT ON COLUMN PURCHASE_LIST.RAW_MATERIAL_REQUIRED_QTY IS '소재소요량';
COMMENT ON COLUMN PURCHASE_LIST.RAW_MATERIAL_ORDER_QTY IS '소재발주수량';
COMMENT ON COLUMN PURCHASE_LIST.ITEM_QTY2 IS '항목수량';
COMMENT ON COLUMN PURCHASE_LIST.PRODUCTION_QTY IS '제작수량';
COMMENT ON COLUMN PURCHASE_LIST.PROCESSING_COMPANY IS '가공업체';
COMMENT ON COLUMN PURCHASE_LIST.PROCESSING_DELIVERY_DATE IS '가공납기';
COMMENT ON COLUMN PURCHASE_LIST.GRINDING_DELIVERY_DATE IS '연삭납기';
COMMENT ON COLUMN PURCHASE_LIST.USE_YN IS '사용여부';
COMMENT ON COLUMN PURCHASE_LIST.NET_QTY IS '정미수량';
COMMENT ON COLUMN PURCHASE_LIST.ORDER_QTY IS '발주수량';
COMMENT ON COLUMN PURCHASE_LIST.SUPPLIER2 IS '공급업체';
COMMENT ON COLUMN PURCHASE_LIST.UNIT_PRICE IS '단가';
COMMENT ON COLUMN PURCHASE_LIST.TOTAL_PRICE IS '총단가';
COMMENT ON COLUMN PURCHASE_LIST.PROPOSAL_DATE IS '품의서작성일';
COMMENT ON COLUMN PURCHASE_LIST.WRITER IS '작성자';
COMMENT ON COLUMN PURCHASE_LIST.REGDATE IS '등록일';

View File

@@ -2773,5 +2773,127 @@ UPDATE SET
,QTY = #{QTY }
,NOTE = #{NOTE }
</update>
<!-- 구매리스트 관련 쿼리 -->
<select id="getSalesRequestPartList" parameterType="string" resultType="map">
SELECT
SRP.OBJID,
SRP.PART_OBJID,
PM.PART_NO,
PM.PART_NAME,
SRP.QTY,
SRP.PARTNER_OBJID,
SRP.PARTNER_PRICE
FROM
SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID = PM.OBJID::VARCHAR
WHERE
SRP.SALES_REQUEST_MASTER_OBJID = #{SALES_REQUEST_MASTER_OBJID}
ORDER BY SRP.REGDATE
</select>
<update id="mergePurchaseListInfo" parameterType="map">
INSERT INTO SALES_REQUEST_PART (
OBJID,
SALES_REQUEST_MASTER_OBJID,
PART_NO,
PART_NAME,
QTY,
ITEM_QTY,
FILE_3D,
FILE_2D,
FILE_PDF,
MATERIAL,
HEAT_TREATMENT_HARDNESS,
HEAT_TREATMENT_METHOD,
SURFACE_TREATMENT,
SUPPLIER,
CATEGORY_NAME,
SUPPLY_TYPE,
RAW_MATERIAL,
SIZE,
RAW_MATERIAL_PART_NO,
RAW_MATERIAL_REQUIRED_QTY,
RAW_MATERIAL_ORDER_QTY,
ITEM_QTY2,
PRODUCTION_QTY,
PROCESSING_COMPANY,
PROCESSING_DELIVERY_DATE,
GRINDING_DELIVERY_DATE,
USE_YN,
NET_QTY,
ORDER_QTY,
SUPPLIER2,
UNIT_PRICE,
TOTAL_PRICE,
PROPOSAL_DATE,
WRITER,
REGDATE
) VALUES (
#{OBJID},
#{SALES_REQUEST_MASTER_OBJID},
#{PART_NO},
#{PART_NAME},
#{QTY},
#{ITEM_QTY},
#{FILE_3D},
#{FILE_2D},
#{FILE_PDF},
#{MATERIAL},
#{HEAT_TREATMENT_HARDNESS},
#{HEAT_TREATMENT_METHOD},
#{SURFACE_TREATMENT},
#{SUPPLIER},
#{CATEGORY_NAME},
#{SUPPLY_TYPE},
#{RAW_MATERIAL},
#{SIZE},
#{RAW_MATERIAL_PART_NO},
#{RAW_MATERIAL_REQUIRED_QTY},
#{RAW_MATERIAL_ORDER_QTY},
#{ITEM_QTY2},
#{PRODUCTION_QTY},
#{PROCESSING_COMPANY},
CASE WHEN #{PROCESSING_DELIVERY_DATE} = '' THEN NULL ELSE #{PROCESSING_DELIVERY_DATE}::date END,
CASE WHEN #{GRINDING_DELIVERY_DATE} = '' THEN NULL ELSE #{GRINDING_DELIVERY_DATE}::date END,
#{USE_YN},
#{NET_QTY},
#{ORDER_QTY},
#{SUPPLIER2},
#{UNIT_PRICE},
#{TOTAL_PRICE},
CASE WHEN #{PROPOSAL_DATE} = '' THEN NOW() ELSE #{PROPOSAL_DATE}::date END,
#{WRITER},
NOW()
) ON CONFLICT (OBJID) DO
UPDATE SET
ITEM_QTY = #{ITEM_QTY},
FILE_3D = #{FILE_3D},
FILE_2D = #{FILE_2D},
FILE_PDF = #{FILE_PDF},
MATERIAL = #{MATERIAL},
HEAT_TREATMENT_HARDNESS = #{HEAT_TREATMENT_HARDNESS},
HEAT_TREATMENT_METHOD = #{HEAT_TREATMENT_METHOD},
SURFACE_TREATMENT = #{SURFACE_TREATMENT},
SUPPLIER = #{SUPPLIER},
CATEGORY_NAME = #{CATEGORY_NAME},
SUPPLY_TYPE = #{SUPPLY_TYPE},
RAW_MATERIAL = #{RAW_MATERIAL},
SIZE = #{SIZE},
RAW_MATERIAL_PART_NO = #{RAW_MATERIAL_PART_NO},
RAW_MATERIAL_REQUIRED_QTY = #{RAW_MATERIAL_REQUIRED_QTY},
RAW_MATERIAL_ORDER_QTY = #{RAW_MATERIAL_ORDER_QTY},
ITEM_QTY2 = #{ITEM_QTY2},
PRODUCTION_QTY = #{PRODUCTION_QTY},
PROCESSING_COMPANY = #{PROCESSING_COMPANY},
PROCESSING_DELIVERY_DATE = CASE WHEN #{PROCESSING_DELIVERY_DATE} = '' THEN NULL ELSE #{PROCESSING_DELIVERY_DATE}::date END,
GRINDING_DELIVERY_DATE = CASE WHEN #{GRINDING_DELIVERY_DATE} = '' THEN NULL ELSE #{GRINDING_DELIVERY_DATE}::date END,
USE_YN = #{USE_YN},
NET_QTY = #{NET_QTY},
ORDER_QTY = #{ORDER_QTY},
SUPPLIER2 = #{SUPPLIER2},
UNIT_PRICE = #{UNIT_PRICE},
TOTAL_PRICE = #{TOTAL_PRICE}
</update>
</mapper>

View File

@@ -1086,4 +1086,53 @@ public class SalesMngController {
}
return resultMap;
}
/**
* 구매리스트 작성 팝업
* @param request
* @param paramMap
* @return
*/
@RequestMapping("/salesMng/purchaseListFormPopUp.do")
public String purchaseListFormPopUp(HttpServletRequest request, @RequestParam Map paramMap){
return "/salesMng/purchaseListFormPopUp";
}
/**
* 구매리스트 데이터 조회
* @param request
* @param paramMap
* @return
*/
@ResponseBody
@RequestMapping("/salesMng/getPurchaseListData.do")
public Map getPurchaseListData(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
Map resultMap = new HashMap();
try{
resultMap = salesMngService.getPurchaseListData(request, paramMap);
}catch(Exception e){
e.printStackTrace();
}
return resultMap;
}
/**
* 구매리스트 저장
* @param request
* @param paramMap
* @return
*/
@ResponseBody
@RequestMapping("/salesMng/savePurchaseList.do")
public Map savePurchaseList(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
Map resultMap = new HashMap();
try{
resultMap = salesMngService.savePurchaseList(request, paramMap);
}catch(Exception e){
e.printStackTrace();
resultMap.put("result", "error");
resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage());
}
return resultMap;
}
}

View File

@@ -1694,4 +1694,95 @@ public class SalesMngService {
return resultMap;
}
/**
* 구매리스트 데이터 조회
* @param request
* @param paramMap
* @return
*/
public Map getPurchaseListData(HttpServletRequest request, Map paramMap) {
Map resultMap = new HashMap();
SqlSession sqlSession = null;
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
String salesRequestMasterObjid = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID"));
// SALES_REQUEST_PART 조회
List<Map> partList = sqlSession.selectList("salesMng.getSalesRequestPartList", salesRequestMasterObjid);
resultMap.put("partList", partList);
} catch(Exception e) {
e.printStackTrace();
} finally {
if(sqlSession != null) sqlSession.close();
}
return resultMap;
}
/**
* 구매리스트 저장
* @param request
* @param paramMap
* @return
*/
public Map savePurchaseList(HttpServletRequest request, Map paramMap) {
Map resultMap = new HashMap();
SqlSession sqlSession = null;
try {
sqlSession = SqlMapConfig.getInstance().getSqlSession(false);
String salesRequestMasterObjid = CommonUtils.checkNull(paramMap.get("SALES_REQUEST_MASTER_OBJID"));
String partListJson = CommonUtils.checkNull(paramMap.get("partList"));
// JSON 파싱 - 기존 코드 참고하여 간단하게 처리
// partListJson이 이미 파싱된 상태일 수 있으므로 직접 처리
List<Map> partList = new ArrayList<Map>();
// TODO: JSON 파싱 로직 추가 필요
if(partList == null || partList.isEmpty()) {
resultMap.put("result", "error");
resultMap.put("message", "저장할 데이터가 없습니다.");
return resultMap;
}
// 로그인 사용자 정보
HttpSession session = request.getSession();
PersonBean personBean = (PersonBean) session.getAttribute(Constants.PERSON_BEAN);
String userId = personBean.getUserId();
// 각 품목별로 구매리스트 정보 저장
for(Map partData : partList) {
String objid = CommonUtils.checkNull(partData.get("OBJID"));
if(objid.isEmpty()) {
objid = CommonUtils.createObjId();
}
partData.put("OBJID", objid);
partData.put("SALES_REQUEST_MASTER_OBJID", salesRequestMasterObjid);
partData.put("WRITER", userId);
// SALES_REQUEST_PART 테이블에 저장
sqlSession.insert("salesMng.mergePurchaseListInfo", partData);
}
resultMap.put("result", "success");
resultMap.put("message", "저장되었습니다.");
sqlSession.commit();
} catch(Exception e) {
if(sqlSession != null) sqlSession.rollback();
resultMap.put("result", "error");
resultMap.put("message", "저장 중 오류가 발생했습니다: " + e.getMessage());
e.printStackTrace();
} finally {
if(sqlSession != null) sqlSession.close();
}
return resultMap;
}
}