From a2a5d53d9b86135fed8dfb18dc92caaba6ea4983 Mon Sep 17 00:00:00 2001 From: king Date: Mon, 15 Jun 2026 12:27:42 +0900 Subject: [PATCH] =?UTF-8?q?feat(returns):=20v8.59=20=EB=B0=98=ED=92=88=20?= =?UTF-8?q?=EC=9E=85=EA=B3=A0=20=EC=A4=91=EB=B3=B5=20=EA=B2=BD=EA=B3=A0=20?= =?UTF-8?q?=EB=B0=8F=20=EC=86=A1=EC=9E=A5=20=EA=B3=B5=EB=B0=B1=20=EB=A7=A4?= =?UTF-8?q?=EC=B9=AD=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 반품 입고 시 이미 등록된 송장번호면 중복 경고 안내창 표시 - 송장번호 입력값 strip 및 조회 쿼리 TRIM 적용으로 공백 매칭 문제 해결 Co-Authored-By: Claude Opus 4.8 --- routers/returns.py | 33 +++++++++++++++++++++++++++++---- static/js/app.js | 20 ++++++++++++++++++-- templates/index.html | 4 ++-- version_history.json | 13 +++++++++++++ 4 files changed, 62 insertions(+), 8 deletions(-) diff --git a/routers/returns.py b/routers/returns.py index 780fb3b..e874838 100644 --- a/routers/returns.py +++ b/routers/returns.py @@ -90,6 +90,7 @@ async def return_lookup(tracking_no: str): @router.post("/request") async def create_return_request(req: ReturnRequest): try: + req.tracking_no = req.tracking_no.strip() conn = get_return_db_conn() cur = conn.cursor() if req.id: @@ -117,7 +118,7 @@ async def get_return_requests(tracking_no: Optional[str] = None): conn = get_return_db_conn() cur = conn.cursor() if tracking_no: - cur.execute("SELECT * FROM return_requests WHERE tracking_no = %s ORDER BY created_at DESC LIMIT 1", (tracking_no,)) + cur.execute("SELECT * FROM return_requests WHERE TRIM(tracking_no) = %s ORDER BY created_at DESC LIMIT 1", (tracking_no.strip(),)) else: cur.execute("SELECT * FROM return_requests ORDER BY id DESC LIMIT 50") rows = cur.fetchall() @@ -151,7 +152,7 @@ async def create_return_receive_bulk(req: BulkReturnReceive): address = "" # 1. Check return_requests - cur_return.execute("SELECT mall, receiver_name, phone, address, request_type, remarks FROM return_requests WHERE tracking_no = %s", (tracking_no,)) + cur_return.execute("SELECT mall, receiver_name, phone, address, request_type, remarks FROM return_requests WHERE TRIM(tracking_no) = %s", (tracking_no,)) req_row = cur_return.fetchone() if req_row: mall = req_row['mall'] or "" @@ -203,11 +204,35 @@ async def create_return_receive_bulk(req: BulkReturnReceive): @router.post("/receive") async def create_return_receive(req: ReturnReceive): try: + req.tracking_no = req.tracking_no.strip() conn = get_return_db_conn() cur = conn.cursor() - + + # 중복 송장 검사 + if req.id: + cur.execute(""" + SELECT receive_date, receiver_name, phone, mall, receive_status, remarks + FROM return_receivings + WHERE TRIM(tracking_no) = %s AND id != %s + """, (req.tracking_no, req.id)) + else: + cur.execute(""" + SELECT receive_date, receiver_name, phone, mall, receive_status, remarks + FROM return_receivings + WHERE TRIM(tracking_no) = %s + """, (req.tracking_no,)) + + dup = cur.fetchone() + if dup: + conn.close() + return { + "success": False, + "error_type": "duplicate", + "data": dict(dup) + } + if not req.id: - cur.execute("SELECT request_type, remarks FROM return_requests WHERE tracking_no = %s", (req.tracking_no,)) + cur.execute("SELECT request_type, remarks FROM return_requests WHERE TRIM(tracking_no) = %s", (req.tracking_no,)) req_row = cur.fetchone() if not req_row: if req.remarks: diff --git a/static/js/app.js b/static/js/app.js index 0be619e..94483a2 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1673,7 +1673,7 @@ document.addEventListener('DOMContentLoaded', () => { e.preventDefault(); const payload = { receive_date: document.getElementById('rec-date').value, - tracking_no: document.getElementById('rec-tracking-no').value, + tracking_no: document.getElementById('rec-tracking-no').value.trim(), mall: document.getElementById('rec-mall').value, receiver_name: document.getElementById('rec-name').value, phone: document.getElementById('rec-phone').value, @@ -1691,7 +1691,12 @@ document.addEventListener('DOMContentLoaded', () => { headers: {'Content-Type': 'application/json'}, body: JSON.stringify(payload) }); - if(res.ok) { + let result = {}; + try { + result = await res.json(); + } catch(err) {} + + if(res.ok && result.success !== false) { formRec.reset(); document.getElementById('rec-date').value = new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60000).toISOString().split('T')[0]; if(recId) recId.value = ''; @@ -1701,6 +1706,17 @@ document.addEventListener('DOMContentLoaded', () => { if (typeof loadReturnRequests === 'function') { loadReturnRequests(); } + } else if (result.error_type === 'duplicate') { + const dup = result.data || {}; + alert( + `🚨 [안내] 이미 입고된 송장번호입니다.\n\n` + + `• 입고날짜: ${dup.receive_date || ''}\n` + + `• 이름: ${dup.receiver_name || ''}\n` + + `• 핸드폰 번호: ${dup.phone || ''}\n` + + `• 쇼핑몰: ${dup.mall || ''}\n` + + `• 입고상태: ${dup.receive_status || ''}\n` + + `• 비고: ${dup.remarks || ''}` + ); } else { alert('등록 실패'); } diff --git a/templates/index.html b/templates/index.html index 24c7c0a..1514061 100644 --- a/templates/index.html +++ b/templates/index.html @@ -46,10 +46,10 @@

No.1 King

CS 통합 관리

- Ver 8.58 + Ver 8.59
- (2026.06.01) + (2026.06.15)