feat: 반품관리 페이지 추가
This commit is contained in:
parent
09948c234f
commit
d6cf4c2cc1
152
backend/app.py
152
backend/app.py
@ -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():
|
||||
"""
|
||||
|
||||
1130
backend/templates/admin_return_management.html
Normal file
1130
backend/templates/admin_return_management.html
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user