feat: 반품관리 페이지 추가

This commit is contained in:
thug0bin 2026-03-08 10:03:42 +09:00
parent 09948c234f
commit d6cf4c2cc1
2 changed files with 1282 additions and 0 deletions

View File

@ -5234,6 +5234,158 @@ def api_kims_log_detail(log_id):
return jsonify({'success': False, 'error': str(e)})
# ─────────────────────────────────────────────────────────────
# 반품 후보 관리
# ─────────────────────────────────────────────────────────────
@app.route('/admin/return-management')
def admin_return_management():
"""반품 후보 관리 페이지"""
return render_template('admin_return_management.html')
@app.route('/api/return-candidates')
def api_return_candidates():
"""반품 후보 목록 조회 API"""
status = request.args.get('status', '')
urgency = request.args.get('urgency', '')
search = request.args.get('search', '')
sort = request.args.get('sort', 'months_desc')
try:
db_path = os.path.join(BACKEND_DIR, 'db', 'orders.db')
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# 기본 쿼리
query = "SELECT * FROM return_candidates WHERE 1=1"
params = []
# 상태 필터
if status:
query += " AND status = ?"
params.append(status)
# 검색어 필터
if search:
query += " AND (drug_name LIKE ? OR drug_code LIKE ?)"
params.extend([f'%{search}%', f'%{search}%'])
# 긴급도 필터
if urgency == 'critical':
query += " AND (months_since_use >= 36 OR months_since_purchase >= 36)"
elif urgency == 'warning':
query += " AND ((months_since_use >= 24 OR months_since_purchase >= 24) AND (COALESCE(months_since_use, 0) < 36 AND COALESCE(months_since_purchase, 0) < 36))"
elif urgency == 'normal':
query += " AND (COALESCE(months_since_use, 0) < 24 AND COALESCE(months_since_purchase, 0) < 24)"
# 정렬
sort_map = {
'months_desc': 'COALESCE(months_since_use, months_since_purchase, 0) DESC',
'months_asc': 'COALESCE(months_since_use, months_since_purchase, 0) ASC',
'stock_desc': 'current_stock DESC',
'name_asc': 'drug_name ASC',
'detected_desc': 'detected_at DESC'
}
query += f" ORDER BY {sort_map.get(sort, 'detected_at DESC')}"
cursor.execute(query, params)
rows = cursor.fetchall()
items = []
for row in rows:
items.append({
'id': row['id'],
'drug_code': row['drug_code'],
'drug_name': row['drug_name'],
'current_stock': row['current_stock'],
'last_prescription_date': row['last_prescription_date'],
'months_since_use': row['months_since_use'],
'last_purchase_date': row['last_purchase_date'],
'months_since_purchase': row['months_since_purchase'],
'status': row['status'],
'decision_reason': row['decision_reason'],
'detected_at': row['detected_at'],
'updated_at': row['updated_at']
})
# 통계 계산
cursor.execute("SELECT COUNT(*) FROM return_candidates WHERE months_since_use >= 36 OR months_since_purchase >= 36")
critical = cursor.fetchone()[0]
cursor.execute("""SELECT COUNT(*) FROM return_candidates
WHERE (months_since_use >= 24 OR months_since_purchase >= 24)
AND (COALESCE(months_since_use, 0) < 36 AND COALESCE(months_since_purchase, 0) < 36)""")
warning = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM return_candidates WHERE status = 'pending'")
pending = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM return_candidates WHERE status IN ('returned', 'keep', 'disposed', 'resolved')")
processed = cursor.fetchone()[0]
cursor.execute("SELECT COUNT(*) FROM return_candidates")
total = cursor.fetchone()[0]
conn.close()
return jsonify({
'success': True,
'items': items,
'stats': {
'critical': critical,
'warning': warning,
'pending': pending,
'processed': processed,
'total': total
}
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/return-candidates/<int:item_id>', methods=['PUT'])
def api_update_return_candidate(item_id):
"""반품 후보 상태 변경 API"""
try:
data = request.get_json()
new_status = data.get('status')
reason = data.get('reason', '')
if not new_status:
return jsonify({'success': False, 'error': '상태가 지정되지 않았습니다'}), 400
valid_statuses = ['pending', 'reviewed', 'returned', 'keep', 'disposed', 'resolved']
if new_status not in valid_statuses:
return jsonify({'success': False, 'error': f'유효하지 않은 상태: {new_status}'}), 400
db_path = os.path.join(BACKEND_DIR, 'db', 'orders.db')
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute("""
UPDATE return_candidates
SET status = ?,
decision_reason = ?,
reviewed_at = datetime('now', 'localtime'),
updated_at = datetime('now', 'localtime')
WHERE id = ?
""", (new_status, reason, item_id))
if cursor.rowcount == 0:
conn.close()
return jsonify({'success': False, 'error': '항목을 찾을 수 없습니다'}), 404
conn.commit()
conn.close()
return jsonify({'success': True, 'message': '상태가 변경되었습니다'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/kims/interaction-check', methods=['POST'])
def api_kims_interaction_check():
"""

File diff suppressed because it is too large Load Diff