공용 NumberInput + 숫자 포맷 정책 적용 (수량 1,234 / 금액 1,234.00)

- NumberInput 공용 컴포넌트: blur 시 콤마+소수점 자릿수 강제,
  focus 시 raw 숫자로 전환되어 자유 편집, 잘못된 입력은 이전 값 유지.
- 다이얼로그 수량/단가 input → NumberInput 으로 교체.
- 백엔드 정규화 — M-BOM/detail/proposal-targets:
  qty=FLOOR()::INTEGER, unit_price/partner_price/total_price=NUMERIC(18,2)
  (운영 sales_request_part 는 정수 String 이지만 M-BOM production_qty
   NUMERIC(15,4) 가 흘러들어와 '4.0000' 노출되던 문제 차단).
- ProposalCreateDialog fmt: Math.floor 후 ko-KR toLocaleString.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
hjjeong
2026-05-15 14:52:50 +09:00
parent 1fb438bdcb
commit 0fe71298d2
4 changed files with 143 additions and 20 deletions
@@ -321,10 +321,10 @@ export async function getPurchaseRequestDetail(srmObjid: string) {
`SELECT SRP.OBJID, SRP.PART_OBJID,
COALESCE(PM.PART_NO, '') AS PART_NO,
COALESCE(PM.PART_NAME, '') AS PART_NAME,
COALESCE(SRP.QTY, '0') AS QTY,
COALESCE(FLOOR(NULLIF(SRP.QTY, '')::NUMERIC)::INTEGER, 0)::TEXT AS QTY,
SRP.ORG_QTY, SRP.PARTNER_OBJID,
COALESCE(SRP.PARTNER_PRICE, '') AS PARTNER_PRICE,
COALESCE(SRP.UNIT_PRICE, 0) AS UNIT_PRICE,
COALESCE(NULLIF(SRP.PARTNER_PRICE, '')::NUMERIC, 0)::NUMERIC(18,2) AS PARTNER_PRICE,
COALESCE(SRP.UNIT_PRICE, 0)::NUMERIC(18,2) AS UNIT_PRICE,
COALESCE(SRP.VENDOR_PM, '') AS VENDOR_PM,
SRP.DELIVERY_REQUEST_DATE, SRP.STATUS, SRP.PROPOSAL_DATE
FROM SALES_REQUEST_PART SRP
@@ -346,7 +346,7 @@ export async function listVendorOptions(): Promise<{ code: string; label: string
const r = await pool.query(
`SELECT OBJID::VARCHAR AS code, CLIENT_NM AS label
FROM CLIENT_MNG
WHERE COALESCE(STATUS, 'active') IN ('active', '활성', 'ACTIVE')
WHERE COALESCE(USE_YN, '1') IN ('1', 'Y', 'y')
AND CLIENT_NM IS NOT NULL AND CLIENT_NM <> ''
ORDER BY CLIENT_NM`,
);
@@ -410,8 +410,8 @@ export async function listMbomPartsForProject(projectObjid: string) {
COALESCE(PM.PART_NO, '') AS part_no,
COALESCE(PM.PART_NAME, '') AS part_name,
COALESCE(MD.UNIT, '') AS unit,
COALESCE(MD.PRODUCTION_QTY, MD.PO_QTY, 0) AS qty,
COALESCE(MD.UNIT_PRICE, 0) AS unit_price,
COALESCE(FLOOR(COALESCE(MD.PRODUCTION_QTY, MD.PO_QTY, 0))::INTEGER, 0) AS qty,
COALESCE(MD.UNIT_PRICE, 0)::NUMERIC(18,2) AS unit_price,
COALESCE(MD.VENDOR, '') AS vendor_objid,
CASE
WHEN MD.VENDOR IS NULL OR MD.VENDOR = '' THEN ''
@@ -558,9 +558,9 @@ export async function getProposalTargetParts(srmObjid: string) {
SRP.OBJID, SRP.PART_OBJID,
COALESCE(PM.PART_NO, '') AS PART_NO,
COALESCE(PM.PART_NAME, '') AS PART_NAME,
COALESCE(SRP.QTY, '0') AS QTY,
COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE,'')::NUMERIC, 0) AS UNIT_PRICE,
SRP.TOTAL_PRICE,
COALESCE(FLOOR(NULLIF(SRP.QTY, '')::NUMERIC)::INTEGER, 0)::TEXT AS QTY,
COALESCE(SRP.UNIT_PRICE, NULLIF(SRP.PARTNER_PRICE,'')::NUMERIC, 0)::NUMERIC(18,2) AS UNIT_PRICE,
SRP.TOTAL_PRICE::NUMERIC(18,2) AS TOTAL_PRICE,
COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID, '') AS VENDOR_PM,
CASE
WHEN COALESCE(SRP.VENDOR_PM, SRP.PARTNER_OBJID) IS NULL THEN ''
@@ -587,7 +587,7 @@ export async function getProposalTargetParts(srmObjid: string) {
SRP.OBJID, SRP.PART_OBJID,
COALESCE(PM.PART_NO,'') AS PART_NO,
COALESCE(PM.PART_NAME,'') AS PART_NAME,
COALESCE(SRP.QTY,'0') AS QTY
COALESCE(FLOOR(NULLIF(SRP.QTY, '')::NUMERIC)::INTEGER, 0)::TEXT AS QTY
FROM SALES_REQUEST_PART SRP
LEFT JOIN PART_MNG PM ON SRP.PART_OBJID::VARCHAR = PM.OBJID::VARCHAR
WHERE SRP.SALES_REQUEST_MASTER_OBJID = $1