feat(returns): v8.59 반품 입고 중복 경고 및 송장 공백 매칭 개선
- 반품 입고 시 이미 등록된 송장번호면 중복 경고 안내창 표시 - 송장번호 입력값 strip 및 조회 쿼리 TRIM 적용으로 공백 매칭 문제 해결 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+29
-4
@@ -90,6 +90,7 @@ async def return_lookup(tracking_no: str):
|
|||||||
@router.post("/request")
|
@router.post("/request")
|
||||||
async def create_return_request(req: ReturnRequest):
|
async def create_return_request(req: ReturnRequest):
|
||||||
try:
|
try:
|
||||||
|
req.tracking_no = req.tracking_no.strip()
|
||||||
conn = get_return_db_conn()
|
conn = get_return_db_conn()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
if req.id:
|
if req.id:
|
||||||
@@ -117,7 +118,7 @@ async def get_return_requests(tracking_no: Optional[str] = None):
|
|||||||
conn = get_return_db_conn()
|
conn = get_return_db_conn()
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
if tracking_no:
|
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:
|
else:
|
||||||
cur.execute("SELECT * FROM return_requests ORDER BY id DESC LIMIT 50")
|
cur.execute("SELECT * FROM return_requests ORDER BY id DESC LIMIT 50")
|
||||||
rows = cur.fetchall()
|
rows = cur.fetchall()
|
||||||
@@ -151,7 +152,7 @@ async def create_return_receive_bulk(req: BulkReturnReceive):
|
|||||||
address = ""
|
address = ""
|
||||||
|
|
||||||
# 1. Check return_requests
|
# 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()
|
req_row = cur_return.fetchone()
|
||||||
if req_row:
|
if req_row:
|
||||||
mall = req_row['mall'] or ""
|
mall = req_row['mall'] or ""
|
||||||
@@ -203,11 +204,35 @@ async def create_return_receive_bulk(req: BulkReturnReceive):
|
|||||||
@router.post("/receive")
|
@router.post("/receive")
|
||||||
async def create_return_receive(req: ReturnReceive):
|
async def create_return_receive(req: ReturnReceive):
|
||||||
try:
|
try:
|
||||||
|
req.tracking_no = req.tracking_no.strip()
|
||||||
conn = get_return_db_conn()
|
conn = get_return_db_conn()
|
||||||
cur = conn.cursor()
|
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:
|
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()
|
req_row = cur.fetchone()
|
||||||
if not req_row:
|
if not req_row:
|
||||||
if req.remarks:
|
if req.remarks:
|
||||||
|
|||||||
+18
-2
@@ -1673,7 +1673,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const payload = {
|
const payload = {
|
||||||
receive_date: document.getElementById('rec-date').value,
|
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,
|
mall: document.getElementById('rec-mall').value,
|
||||||
receiver_name: document.getElementById('rec-name').value,
|
receiver_name: document.getElementById('rec-name').value,
|
||||||
phone: document.getElementById('rec-phone').value,
|
phone: document.getElementById('rec-phone').value,
|
||||||
@@ -1691,7 +1691,12 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
headers: {'Content-Type': 'application/json'},
|
headers: {'Content-Type': 'application/json'},
|
||||||
body: JSON.stringify(payload)
|
body: JSON.stringify(payload)
|
||||||
});
|
});
|
||||||
if(res.ok) {
|
let result = {};
|
||||||
|
try {
|
||||||
|
result = await res.json();
|
||||||
|
} catch(err) {}
|
||||||
|
|
||||||
|
if(res.ok && result.success !== false) {
|
||||||
formRec.reset();
|
formRec.reset();
|
||||||
document.getElementById('rec-date').value = new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60000).toISOString().split('T')[0];
|
document.getElementById('rec-date').value = new Date(new Date().getTime() - new Date().getTimezoneOffset() * 60000).toISOString().split('T')[0];
|
||||||
if(recId) recId.value = '';
|
if(recId) recId.value = '';
|
||||||
@@ -1701,6 +1706,17 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
if (typeof loadReturnRequests === 'function') {
|
if (typeof loadReturnRequests === 'function') {
|
||||||
loadReturnRequests();
|
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 {
|
} else {
|
||||||
alert('등록 실패');
|
alert('등록 실패');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,10 +46,10 @@
|
|||||||
<h1>No.1 King</h1>
|
<h1>No.1 King</h1>
|
||||||
<p>CS 통합 관리</p>
|
<p>CS 통합 관리</p>
|
||||||
<div id="app-version-text" style="color: #a0aec0; font-size: 0.95rem; margin-top: 4px; font-weight: normal;">
|
<div id="app-version-text" style="color: #a0aec0; font-size: 0.95rem; margin-top: 4px; font-weight: normal;">
|
||||||
Ver 8.58
|
Ver 8.59
|
||||||
</div>
|
</div>
|
||||||
<div style="color: #a0aec0; font-size: 0.75rem; margin-top: 4px; font-weight: normal;">
|
<div style="color: #a0aec0; font-size: 0.75rem; margin-top: 4px; font-weight: normal;">
|
||||||
(2026.06.01)
|
(2026.06.15)
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul class="nav-links">
|
<ul class="nav-links">
|
||||||
|
|||||||
@@ -1,4 +1,17 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "v8.59",
|
||||||
|
"date": "2026.06.15",
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
"반품 입고 시 이미 등록된 송장번호 입력 시 중복 입고 경고 안내창을 표시하도록 기능 추가",
|
||||||
|
"송장번호 입력값 및 데이터베이스 조회 쿼리에 공백 제거(TRIM/strip) 처리를 적용하여 공백 포함 데이터 매칭 문제 개선"
|
||||||
|
],
|
||||||
|
"type": "modified"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "v8.58",
|
"version": "v8.58",
|
||||||
"date": "2026.06.01",
|
"date": "2026.06.01",
|
||||||
|
|||||||
Reference in New Issue
Block a user