refactor: formula_ingredients를 ingredient_code 기반으로 변경
- formula_ingredients 테이블이 herb_item_id 대신 ingredient_code 사용하도록 변경 - GET /api/formulas/<id>/ingredients API 개선 - ingredient_code 기반 조회로 변경 - available_products 배열 추가 (재고 있는 모든 제품 포함) - total_available_stock, product_count 필드 추가 - 같은 주성분을 가진 모든 제품의 재고 정보를 반환하도록 수정 이제 처방에서 특정 제품이 아닌 주성분을 지정하여 재고가 있는 대체 제품을 자동으로 선택 가능
This commit is contained in:
parent
dbd6f4f841
commit
9fa1f7a031
265
app.py
265
app.py
@ -64,6 +64,11 @@ def init_db():
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/survey/<survey_token>')
|
||||
def survey_page(survey_token):
|
||||
"""문진표 페이지 (모바일)"""
|
||||
return render_template('survey.html')
|
||||
|
||||
# ==================== 환자 관리 API ====================
|
||||
|
||||
@app.route('/api/patients', methods=['GET'])
|
||||
@ -320,18 +325,57 @@ def create_formula():
|
||||
|
||||
@app.route('/api/formulas/<int:formula_id>/ingredients', methods=['GET'])
|
||||
def get_formula_ingredients(formula_id):
|
||||
"""처방 구성 약재 조회"""
|
||||
"""처방 구성 약재 조회 (ingredient_code 기반, 사용 가능한 모든 제품 포함)"""
|
||||
try:
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 처방 구성 약재 조회 (ingredient_code 기반)
|
||||
cursor.execute("""
|
||||
SELECT fi.*, h.herb_name, h.insurance_code
|
||||
SELECT
|
||||
fi.ingredient_id,
|
||||
fi.formula_id,
|
||||
fi.ingredient_code,
|
||||
fi.grams_per_cheop,
|
||||
fi.notes,
|
||||
fi.sort_order,
|
||||
hm.herb_name,
|
||||
hm.herb_name_hanja
|
||||
FROM formula_ingredients fi
|
||||
JOIN herb_items h ON fi.herb_item_id = h.herb_item_id
|
||||
LEFT JOIN herb_masters hm ON fi.ingredient_code = hm.ingredient_code
|
||||
WHERE fi.formula_id = ?
|
||||
ORDER BY fi.sort_order
|
||||
""", (formula_id,))
|
||||
ingredients = [dict(row) for row in cursor.fetchall()]
|
||||
|
||||
ingredients = []
|
||||
for row in cursor.fetchall():
|
||||
ingredient = dict(row)
|
||||
ingredient_code = ingredient['ingredient_code']
|
||||
|
||||
# 해당 주성분을 가진 사용 가능한 모든 제품 찾기
|
||||
cursor.execute("""
|
||||
SELECT
|
||||
h.herb_item_id,
|
||||
h.herb_name,
|
||||
h.insurance_code,
|
||||
h.specification,
|
||||
COALESCE(SUM(il.quantity_onhand), 0) as stock,
|
||||
COALESCE(AVG(il.unit_price_per_g), 0) as avg_price
|
||||
FROM herb_items h
|
||||
LEFT JOIN inventory_lots il ON h.herb_item_id = il.herb_item_id AND il.is_depleted = 0
|
||||
WHERE h.ingredient_code = ?
|
||||
GROUP BY h.herb_item_id
|
||||
HAVING stock > 0
|
||||
ORDER BY stock DESC
|
||||
""", (ingredient_code,))
|
||||
|
||||
available_products = [dict(row) for row in cursor.fetchall()]
|
||||
ingredient['available_products'] = available_products
|
||||
ingredient['total_available_stock'] = sum(p['stock'] for p in available_products)
|
||||
ingredient['product_count'] = len(available_products)
|
||||
|
||||
ingredients.append(ingredient)
|
||||
|
||||
return jsonify({'success': True, 'data': ingredients})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
@ -1599,6 +1643,219 @@ def create_stock_adjustment():
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
# ==================== 문진표 API ====================
|
||||
|
||||
@app.route('/api/surveys/templates', methods=['GET'])
|
||||
def get_survey_templates():
|
||||
"""문진표 템플릿 조회"""
|
||||
try:
|
||||
category = request.args.get('category')
|
||||
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
if category:
|
||||
cursor.execute("""
|
||||
SELECT * FROM survey_templates
|
||||
WHERE category = ? AND is_active = 1
|
||||
ORDER BY sort_order
|
||||
""", (category,))
|
||||
else:
|
||||
cursor.execute("""
|
||||
SELECT * FROM survey_templates
|
||||
WHERE is_active = 1
|
||||
ORDER BY sort_order
|
||||
""")
|
||||
|
||||
templates = [dict(row) for row in cursor.fetchall()]
|
||||
|
||||
# JSON 파싱
|
||||
for template in templates:
|
||||
if template['options']:
|
||||
template['options'] = json.loads(template['options'])
|
||||
|
||||
return jsonify({'success': True, 'data': templates})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/surveys/categories', methods=['GET'])
|
||||
def get_survey_categories():
|
||||
"""문진표 카테고리 목록"""
|
||||
try:
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
SELECT DISTINCT category, category_name,
|
||||
MIN(sort_order) as min_order,
|
||||
COUNT(*) as question_count
|
||||
FROM survey_templates
|
||||
WHERE is_active = 1
|
||||
GROUP BY category
|
||||
ORDER BY min_order
|
||||
""")
|
||||
|
||||
categories = [dict(row) for row in cursor.fetchall()]
|
||||
return jsonify({'success': True, 'data': categories})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/surveys', methods=['POST'])
|
||||
def create_survey():
|
||||
"""새 문진표 생성"""
|
||||
try:
|
||||
data = request.json
|
||||
patient_id = data.get('patient_id')
|
||||
|
||||
# 고유 토큰 생성
|
||||
import secrets
|
||||
survey_token = secrets.token_urlsafe(16)
|
||||
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("""
|
||||
INSERT INTO patient_surveys (patient_id, survey_token, status)
|
||||
VALUES (?, ?, 'PENDING')
|
||||
""", (patient_id, survey_token))
|
||||
|
||||
survey_id = cursor.lastrowid
|
||||
conn.commit()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'survey_id': survey_id,
|
||||
'survey_token': survey_token,
|
||||
'survey_url': f'/survey/{survey_token}'
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/surveys/<survey_token>', methods=['GET'])
|
||||
def get_survey(survey_token):
|
||||
"""문진표 조회 (토큰으로)"""
|
||||
try:
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 문진표 기본 정보
|
||||
cursor.execute("""
|
||||
SELECT s.*, p.name as patient_name, p.phone as patient_phone
|
||||
FROM patient_surveys s
|
||||
LEFT JOIN patients p ON s.patient_id = p.patient_id
|
||||
WHERE s.survey_token = ?
|
||||
""", (survey_token,))
|
||||
|
||||
survey_row = cursor.fetchone()
|
||||
if not survey_row:
|
||||
return jsonify({'success': False, 'error': '문진표를 찾을 수 없습니다'}), 404
|
||||
|
||||
survey = dict(survey_row)
|
||||
|
||||
# 진행 상태 조회
|
||||
cursor.execute("""
|
||||
SELECT * FROM survey_progress
|
||||
WHERE survey_id = ?
|
||||
""", (survey['survey_id'],))
|
||||
|
||||
progress = [dict(row) for row in cursor.fetchall()]
|
||||
survey['progress'] = progress
|
||||
|
||||
# 기존 응답 조회
|
||||
cursor.execute("""
|
||||
SELECT * FROM survey_responses
|
||||
WHERE survey_id = ?
|
||||
""", (survey['survey_id'],))
|
||||
|
||||
responses = [dict(row) for row in cursor.fetchall()]
|
||||
survey['responses'] = responses
|
||||
|
||||
return jsonify({'success': True, 'data': survey})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/surveys/<survey_token>/responses', methods=['POST'])
|
||||
def save_survey_responses(survey_token):
|
||||
"""문진 응답 저장"""
|
||||
try:
|
||||
data = request.json
|
||||
responses = data.get('responses', [])
|
||||
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
# 문진표 확인
|
||||
cursor.execute("""
|
||||
SELECT survey_id FROM patient_surveys
|
||||
WHERE survey_token = ?
|
||||
""", (survey_token,))
|
||||
|
||||
survey_row = cursor.fetchone()
|
||||
if not survey_row:
|
||||
return jsonify({'success': False, 'error': '문진표를 찾을 수 없습니다'}), 404
|
||||
|
||||
survey_id = survey_row['survey_id']
|
||||
|
||||
# 기존 응답 삭제 후 새로 저장 (upsert 방식)
|
||||
for response in responses:
|
||||
# 기존 응답 삭제
|
||||
cursor.execute("""
|
||||
DELETE FROM survey_responses
|
||||
WHERE survey_id = ? AND question_code = ?
|
||||
""", (survey_id, response['question_code']))
|
||||
|
||||
# 새 응답 저장
|
||||
cursor.execute("""
|
||||
INSERT INTO survey_responses
|
||||
(survey_id, category, question_code, question_text, answer_value, answer_type)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
survey_id,
|
||||
response['category'],
|
||||
response['question_code'],
|
||||
response.get('question_text'),
|
||||
json.dumps(response['answer_value'], ensure_ascii=False) if isinstance(response['answer_value'], (list, dict)) else response['answer_value'],
|
||||
response.get('answer_type', 'SINGLE')
|
||||
))
|
||||
|
||||
# 상태 업데이트
|
||||
cursor.execute("""
|
||||
UPDATE patient_surveys
|
||||
SET status = 'IN_PROGRESS',
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE survey_id = ?
|
||||
""", (survey_id,))
|
||||
|
||||
conn.commit()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': f'{len(responses)}개 응답 저장 완료'
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/surveys/<survey_token>/complete', methods=['POST'])
|
||||
def complete_survey(survey_token):
|
||||
"""문진표 제출 완료"""
|
||||
try:
|
||||
with get_db() as conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE patient_surveys
|
||||
SET status = 'COMPLETED',
|
||||
completed_at = CURRENT_TIMESTAMP
|
||||
WHERE survey_token = ?
|
||||
""", (survey_token,))
|
||||
|
||||
conn.commit()
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'message': '문진표가 제출되었습니다'
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({'success': False, 'error': str(e)}), 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
# 데이터베이스 초기화
|
||||
if not os.path.exists(app.config['DATABASE']):
|
||||
|
||||
Loading…
Reference in New Issue
Block a user