feat: 동물약 APC 일괄 매핑 (7개 완료)
This commit is contained in:
parent
8ee148abe4
commit
dfbc6e4761
18
backend/ecosystem.config.js
Normal file
18
backend/ecosystem.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'pharmacy-flask',
|
||||
script: 'python',
|
||||
args: 'app.py',
|
||||
cwd: 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend',
|
||||
interpreter: 'none',
|
||||
watch: false,
|
||||
autorestart: true,
|
||||
max_restarts: 10,
|
||||
env: {
|
||||
FLASK_ENV: 'production',
|
||||
PYTHONIOENCODING: 'utf-8'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
82
backend/scripts/batch_apc_matching.py
Normal file
82
backend/scripts/batch_apc_matching.py
Normal file
@ -0,0 +1,82 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
동물약 일괄 APC 매칭 - 후보 찾기
|
||||
"""
|
||||
import sys, io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text, create_engine
|
||||
|
||||
# 1. MSSQL 동물약 (APC 없는 것만)
|
||||
session = get_db_session('PM_DRUG')
|
||||
result = session.execute(text("""
|
||||
SELECT
|
||||
G.DrugCode,
|
||||
G.GoodsName,
|
||||
G.Saleprice,
|
||||
(
|
||||
SELECT TOP 1 U.CD_CD_BARCODE
|
||||
FROM CD_ITEM_UNIT_MEMBER U
|
||||
WHERE U.DRUGCODE = G.DrugCode
|
||||
AND U.CD_CD_BARCODE LIKE '023%'
|
||||
) AS APC_CODE
|
||||
FROM CD_GOODS G
|
||||
WHERE G.POS_BOON = '010103'
|
||||
AND G.GoodsSelCode = 'B'
|
||||
ORDER BY G.GoodsName
|
||||
"""))
|
||||
|
||||
no_apc = []
|
||||
for row in result:
|
||||
if not row.APC_CODE:
|
||||
no_apc.append({
|
||||
'code': row.DrugCode,
|
||||
'name': row.GoodsName,
|
||||
'price': row.Saleprice
|
||||
})
|
||||
|
||||
session.close()
|
||||
|
||||
print(f'=== APC 없는 동물약: {len(no_apc)}개 ===\n')
|
||||
|
||||
# 2. PostgreSQL에서 매칭 후보 찾기
|
||||
pg = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master').connect()
|
||||
|
||||
matches = []
|
||||
for drug in no_apc:
|
||||
name = drug['name']
|
||||
# 제품명에서 검색 키워드 추출
|
||||
# (판) 제거, 괄호 내용 제거
|
||||
search_name = name.replace('(판)', '').split('(')[0].strip()
|
||||
|
||||
# PostgreSQL 검색
|
||||
result = pg.execute(text("""
|
||||
SELECT apc, product_name,
|
||||
llm_pharm->>'사용가능 동물' as target,
|
||||
llm_pharm->>'분류' as category
|
||||
FROM apc
|
||||
WHERE product_name ILIKE :pattern
|
||||
ORDER BY LENGTH(product_name)
|
||||
LIMIT 5
|
||||
"""), {'pattern': f'%{search_name}%'})
|
||||
|
||||
candidates = list(result)
|
||||
if candidates:
|
||||
matches.append({
|
||||
'mssql': drug,
|
||||
'candidates': candidates
|
||||
})
|
||||
print(f'✅ {name}')
|
||||
for c in candidates[:2]:
|
||||
print(f' → {c.apc}: {c.product_name[:40]}... [{c.target or "?"}]')
|
||||
else:
|
||||
print(f'❌ {name} - 매칭 없음')
|
||||
|
||||
pg.close()
|
||||
|
||||
print(f'\n=== 요약 ===')
|
||||
print(f'APC 없는 제품: {len(no_apc)}개')
|
||||
print(f'매칭 후보 있음: {len(matches)}개')
|
||||
print(f'매칭 없음: {len(no_apc) - len(matches)}개')
|
||||
75
backend/scripts/batch_insert_apc.py
Normal file
75
backend/scripts/batch_insert_apc.py
Normal file
@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
확실한 매칭만 일괄 등록
|
||||
"""
|
||||
import sys, io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text
|
||||
from datetime import datetime
|
||||
|
||||
# 확실한 매칭 목록 (MSSQL 제품명, DrugCode, APC)
|
||||
MAPPINGS = [
|
||||
# 파라캅
|
||||
('파라캅L(5kg이상)', 'LB000003159', '0230338510101'), # 파라캅 L 정 10정
|
||||
('파라캅S(5kg이하)', 'LB000003160', '0230347110106'), # 파라캅 에스 정 10정
|
||||
# 세레니아
|
||||
('세레니아정16mg(개멀미약)', 'LB000003353', '0231884610109'), # 세레니아 정 16mg / 4정
|
||||
('세레니아정24mg(개멀미약)', 'LB000003354', '0231884620107'), # 세레니아 정 24mg / 4정
|
||||
]
|
||||
|
||||
session = get_db_session('PM_DRUG')
|
||||
today = datetime.now().strftime('%Y%m%d')
|
||||
|
||||
print('=== 일괄 APC 매핑 ===\n')
|
||||
|
||||
for name, drugcode, apc in MAPPINGS:
|
||||
# 기존 가격 조회
|
||||
existing = session.execute(text("""
|
||||
SELECT TOP 1 CD_MY_UNIT, CD_IN_UNIT
|
||||
FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = :dc
|
||||
ORDER BY SN DESC
|
||||
"""), {'dc': drugcode}).fetchone()
|
||||
|
||||
if not existing:
|
||||
print(f'❌ {name}: 기존 레코드 없음')
|
||||
continue
|
||||
|
||||
# 이미 APC 있는지 확인
|
||||
check = session.execute(text("""
|
||||
SELECT 1 FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = :dc AND CD_CD_BARCODE = :apc
|
||||
"""), {'dc': drugcode, 'apc': apc}).fetchone()
|
||||
|
||||
if check:
|
||||
print(f'⏭️ {name}: 이미 등록됨')
|
||||
continue
|
||||
|
||||
# INSERT
|
||||
try:
|
||||
session.execute(text("""
|
||||
INSERT INTO CD_ITEM_UNIT_MEMBER (
|
||||
DRUGCODE, CD_CD_UNIT, CD_NM_UNIT, CD_MY_UNIT, CD_IN_UNIT,
|
||||
CD_CD_BARCODE, CD_CD_POS, CHANGE_DATE
|
||||
) VALUES (
|
||||
:drugcode, '015', 1.0, :my_unit, :in_unit,
|
||||
:barcode, '', :change_date
|
||||
)
|
||||
"""), {
|
||||
'drugcode': drugcode,
|
||||
'my_unit': existing.CD_MY_UNIT,
|
||||
'in_unit': existing.CD_IN_UNIT,
|
||||
'barcode': apc,
|
||||
'change_date': today
|
||||
})
|
||||
session.commit()
|
||||
print(f'✅ {name} → {apc}')
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f'❌ {name}: {e}')
|
||||
|
||||
session.close()
|
||||
print('\n완료!')
|
||||
51
backend/scripts/debug_matching.py
Normal file
51
backend/scripts/debug_matching.py
Normal file
@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
|
||||
# 테스트 AI 응답 (실제 응답 시뮬레이션)
|
||||
ai_response = """
|
||||
네, 안텔민은 개와 고양이 모두 사용 가능합니다!
|
||||
|
||||
**안텔민 킹** - 체중 5kg 이상 반려동물용
|
||||
**안텔민 뽀삐** - 체중 5kg 이하 소형 반려동물용
|
||||
|
||||
두 제품 모두 개와 고양이의 내부 기생충 구제에 효과적입니다.
|
||||
"""
|
||||
|
||||
animal_drugs = [
|
||||
{'name': '안텔민킹(5kg이상)', 'code': 'LB000003157'},
|
||||
{'name': '안텔민뽀삐(5kg이하)', 'code': 'LB000003158'},
|
||||
{'name': '다이로하트정M(12~22kg)', 'code': 'LB000003151'},
|
||||
]
|
||||
|
||||
print('=== 현재 매칭 로직 테스트 ===\n')
|
||||
print(f'AI 응답:\n{ai_response}\n')
|
||||
print('=' * 50)
|
||||
|
||||
ai_response_lower = ai_response.lower()
|
||||
|
||||
for drug in animal_drugs:
|
||||
drug_name = drug['name']
|
||||
base_name = drug_name.split('(')[0].split('/')[0].strip()
|
||||
|
||||
# suffix 제거
|
||||
original_base = base_name
|
||||
for suffix in ['정', '액', 'L', 'M', 'S', 'XL', 'XS', 'SS', 'mini']:
|
||||
if base_name.endswith(suffix):
|
||||
base_name = base_name[:-len(suffix)]
|
||||
base_name = base_name.strip()
|
||||
|
||||
matched = base_name.lower() in ai_response_lower
|
||||
|
||||
print(f'\n제품: {drug_name}')
|
||||
print(f' 괄호 앞: {original_base}')
|
||||
print(f' suffix 제거 후: {base_name}')
|
||||
print(f' 매칭 결과: {"✅ 매칭됨" if matched else "❌ 매칭 안됨"}')
|
||||
|
||||
if not matched:
|
||||
# 왜 안 됐는지 확인
|
||||
print(f' → "{base_name.lower()}" in 응답? {base_name.lower() in ai_response_lower}')
|
||||
# 띄어쓰기 변형 체크
|
||||
spaced = base_name.replace('킹', ' 킹').replace('뽀삐', ' 뽀삐')
|
||||
print(f' → 띄어쓰기 변형 "{spaced.lower()}" in 응답? {spaced.lower() in ai_response_lower}')
|
||||
48
backend/scripts/debug_matching2.py
Normal file
48
backend/scripts/debug_matching2.py
Normal file
@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
|
||||
# 실제 AI 응답
|
||||
ai_response = """안텔민은 개와 고양이 모두에게 사용할 수 있습니다만, 체중에 따라 복용할 용량이 다릅니다. 🐾
|
||||
|
||||
- **안텔민**: 5kg 이상 개와 고양이에게 복용 가능.
|
||||
- **안텔민 뽀삐**: 5kg 미만 소형 반려동물에게 복용 가능.
|
||||
|
||||
따라서, 반려동물의 체중에 맞는 적절한 제품을 선택해야 해요! 🐶 체중을 알려주시면 더 구체적으로 안내해 드릴 수 있어요."""
|
||||
|
||||
animal_drugs = [
|
||||
{'name': '안텔민', 'code': 'S0000001', 'apc': None},
|
||||
{'name': '안텔민킹(5kg이상)', 'code': 'LB000003157', 'apc': '0230237810109'},
|
||||
{'name': '안텔민뽀삐(5kg이하)', 'code': 'LB000003158', 'apc': '0230237010107'},
|
||||
]
|
||||
|
||||
print('=== 매칭 테스트 ===\n')
|
||||
print(f'AI 응답:\n{ai_response}\n')
|
||||
print('=' * 50)
|
||||
|
||||
ai_response_lower = ai_response.lower()
|
||||
ai_response_nospace = ai_response_lower.replace(' ', '')
|
||||
|
||||
for drug in animal_drugs:
|
||||
drug_name = drug['name']
|
||||
base_name = drug_name.split('(')[0].split('/')[0].strip()
|
||||
|
||||
for suffix in ['정', '액', 'L', 'M', 'S', 'XL', 'XS', 'SS', 'mini']:
|
||||
if base_name.endswith(suffix):
|
||||
base_name = base_name[:-len(suffix)]
|
||||
base_name = base_name.strip()
|
||||
|
||||
base_lower = base_name.lower()
|
||||
base_nospace = base_lower.replace(' ', '')
|
||||
|
||||
in_normal = base_lower in ai_response_lower
|
||||
in_nospace = base_nospace in ai_response_nospace
|
||||
matched = len(base_name) >= 2 and (in_normal or in_nospace)
|
||||
|
||||
print(f'\n제품: {drug_name}')
|
||||
print(f' base_name: "{base_name}"')
|
||||
print(f' base_nospace: "{base_nospace}"')
|
||||
print(f' 일반매칭: {in_normal}')
|
||||
print(f' 공백제거매칭: {in_nospace}')
|
||||
print(f' 최종: {"✅" if matched else "❌"}')
|
||||
43
backend/scripts/debug_prompt.py
Normal file
43
backend/scripts/debug_prompt.py
Normal file
@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text
|
||||
|
||||
# _get_animal_drugs 로직 복제
|
||||
drug_session = get_db_session('PM_DRUG')
|
||||
query = text("""
|
||||
SELECT
|
||||
G.DrugCode,
|
||||
G.GoodsName,
|
||||
G.Saleprice,
|
||||
(
|
||||
SELECT TOP 1 U.CD_CD_BARCODE
|
||||
FROM CD_ITEM_UNIT_MEMBER U
|
||||
WHERE U.DRUGCODE = G.DrugCode
|
||||
AND U.CD_CD_BARCODE LIKE '023%'
|
||||
ORDER BY U.CHANGE_DATE DESC
|
||||
) AS APC_CODE
|
||||
FROM CD_GOODS G
|
||||
WHERE G.POS_BOON = '010103'
|
||||
AND G.GoodsSelCode = 'B'
|
||||
ORDER BY G.GoodsName
|
||||
""")
|
||||
rows = drug_session.execute(query).fetchall()
|
||||
|
||||
print('=== AI에 전달되는 보유 제품 목록 ===\n')
|
||||
for r in rows:
|
||||
apc = r.APC_CODE
|
||||
rag_info = ""
|
||||
if apc:
|
||||
rag_info = f" [대상: 개, 고양이]" # RAG 정보 시뮬레이션
|
||||
|
||||
print(f"- {r.GoodsName} ({r.Saleprice:,.0f}원){rag_info}")
|
||||
|
||||
print('\n=== 안텔민 관련 제품만 ===')
|
||||
for r in rows:
|
||||
if '안텔민' in r.GoodsName:
|
||||
print(f" {r.GoodsName} - APC: {r.APC_CODE}")
|
||||
42
backend/scripts/debug_rag.py
Normal file
42
backend/scripts/debug_rag.py
Normal file
@ -0,0 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
pg = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master').connect()
|
||||
|
||||
# 안텔민킹 RAG 정보
|
||||
apc = '0230237810109'
|
||||
print(f'=== 안텔민킹 ({apc}) RAG 정보 ===\n')
|
||||
|
||||
result = pg.execute(text(f"""
|
||||
SELECT
|
||||
product_name,
|
||||
llm_pharm->>'사용가능 동물' as target_animals,
|
||||
llm_pharm->>'분류' as category,
|
||||
llm_pharm->>'체중/부위' as dosage_weight,
|
||||
llm_pharm->>'월령금기' as age_restriction
|
||||
FROM apc
|
||||
WHERE apc = '{apc}'
|
||||
"""))
|
||||
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
print(f'제품명: {row.product_name}')
|
||||
print(f'사용가능 동물: {row.target_animals}')
|
||||
print(f'분류: {row.category}')
|
||||
print(f'체중/용량: {row.dosage_weight}')
|
||||
print(f'월령금기: {row.age_restriction}')
|
||||
|
||||
# efficacy_effect도 확인
|
||||
result2 = pg.execute(text(f"""
|
||||
SELECT efficacy_effect FROM apc WHERE apc = '{apc}'
|
||||
"""))
|
||||
row2 = result2.fetchone()
|
||||
if row2 and row2.efficacy_effect:
|
||||
print(f'\n효능/효과 (원문 일부):')
|
||||
print(row2.efficacy_effect[:500])
|
||||
|
||||
pg.close()
|
||||
86
backend/scripts/debug_rag_prompt.py
Normal file
86
backend/scripts/debug_rag_prompt.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text, create_engine
|
||||
|
||||
# 1. _get_animal_drugs 시뮬레이션
|
||||
drug_session = get_db_session('PM_DRUG')
|
||||
query = text("""
|
||||
SELECT
|
||||
G.DrugCode,
|
||||
G.GoodsName,
|
||||
G.Saleprice,
|
||||
(
|
||||
SELECT TOP 1 U.CD_CD_BARCODE
|
||||
FROM CD_ITEM_UNIT_MEMBER U
|
||||
WHERE U.DRUGCODE = G.DrugCode
|
||||
AND U.CD_CD_BARCODE LIKE '023%'
|
||||
ORDER BY U.CHANGE_DATE DESC
|
||||
) AS APC_CODE
|
||||
FROM CD_GOODS G
|
||||
WHERE G.POS_BOON = '010103'
|
||||
AND G.GoodsSelCode = 'B'
|
||||
ORDER BY G.GoodsName
|
||||
""")
|
||||
rows = drug_session.execute(query).fetchall()
|
||||
|
||||
animal_drugs = []
|
||||
for r in rows:
|
||||
animal_drugs.append({
|
||||
'code': r.DrugCode,
|
||||
'name': r.GoodsName,
|
||||
'price': float(r.Saleprice) if r.Saleprice else 0,
|
||||
'apc': r.APC_CODE
|
||||
})
|
||||
|
||||
# 2. _get_animal_drug_rag 시뮬레이션
|
||||
apc_codes = [d['apc'] for d in animal_drugs if d.get('apc')]
|
||||
print(f'APC 코드 목록: {apc_codes}\n')
|
||||
|
||||
rag_data = {}
|
||||
if apc_codes:
|
||||
pg = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master').connect()
|
||||
placeholders = ','.join([f"'{apc}'" for apc in apc_codes])
|
||||
result = pg.execute(text(f"""
|
||||
SELECT apc, product_name,
|
||||
llm_pharm->>'사용가능 동물' as target_animals,
|
||||
llm_pharm->>'분류' as category,
|
||||
llm_pharm->>'체중/부위' as dosage_weight,
|
||||
llm_pharm->>'기간/용법' as usage_period,
|
||||
llm_pharm->>'월령금기' as age_restriction
|
||||
FROM apc
|
||||
WHERE apc IN ({placeholders})
|
||||
"""))
|
||||
for row in result:
|
||||
rag_data[row.apc] = {
|
||||
'target_animals': row.target_animals or '정보 없음',
|
||||
'category': row.category or '',
|
||||
'dosage_weight': row.dosage_weight or '',
|
||||
'usage_period': row.usage_period or '',
|
||||
'age_restriction': row.age_restriction or ''
|
||||
}
|
||||
pg.close()
|
||||
|
||||
print(f'RAG 데이터: {rag_data}\n')
|
||||
|
||||
# 3. available_products_text 생성
|
||||
print('=== AI에 전달되는 제품 목록 (RAG 포함) ===\n')
|
||||
for d in animal_drugs:
|
||||
if '안텔민' in d['name']:
|
||||
line = f"- {d['name']} ({d['price']:,.0f}원)"
|
||||
if d.get('apc') and d['apc'] in rag_data:
|
||||
info = rag_data[d['apc']]
|
||||
details = []
|
||||
if info.get('target_animals'):
|
||||
details.append(f"대상: {info['target_animals']}")
|
||||
if info.get('dosage_weight'):
|
||||
details.append(f"용량: {info['dosage_weight']}")
|
||||
if info.get('age_restriction'):
|
||||
details.append(f"금기: {info['age_restriction']}")
|
||||
if details:
|
||||
line += f" [{', '.join(details)}]"
|
||||
print(line)
|
||||
45
backend/scripts/detailed_search.py
Normal file
45
backend/scripts/detailed_search.py
Normal file
@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys, io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
pg = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master').connect()
|
||||
|
||||
# 약국 제품 → PostgreSQL 매칭 (체중/용량 포함)
|
||||
mappings = [
|
||||
# (약국제품명, 검색키워드)
|
||||
('제스타제(10정)', '제스타제', '10'),
|
||||
('파라캅L(5kg이상)', '파라캅', 'L'),
|
||||
('파라캅S(5kg이하)', '파라캅', 'S'),
|
||||
('하트캅츄어블(11kg이하)', '하트캅', '11'),
|
||||
('넥스가드L(15~30kg)', '넥스가드', '15'),
|
||||
('넥스가드xs(2~3.5kg)', '넥스가드', '2'),
|
||||
('다이로하트정M(12~22kg)', '다이로하트', '12'),
|
||||
('다이로하트정S(5.6~11kg)', '다이로하트', '5.6'),
|
||||
('다이로하트정SS(5.6kg이하)', '다이로하트', 'SS'),
|
||||
('세레니아정16mg(개멀미약)', '세레니아', '16'),
|
||||
('세레니아정24mg(개멀미약)', '세레니아', '24'),
|
||||
('하트세이버츄어블M(12~22kg)', '하트세이버', '12'),
|
||||
('하트세이버츄어블S(5.6~11kg)', '하트세이버', '5.6'),
|
||||
('하트웜솔루션츄어블M(12~22kg)', '하트웜', '12'),
|
||||
('하트웜솔루션츄어블S(11kg이하)', '하트웜', '11'),
|
||||
]
|
||||
|
||||
print('=== 상세 매칭 검색 ===\n')
|
||||
|
||||
for pharm_name, keyword, size in mappings:
|
||||
result = pg.execute(text("""
|
||||
SELECT apc, product_name, packaging,
|
||||
llm_pharm->>'사용가능 동물' as target
|
||||
FROM apc
|
||||
WHERE product_name ILIKE :kw
|
||||
ORDER BY product_name
|
||||
LIMIT 10
|
||||
"""), {'kw': f'%{keyword}%'})
|
||||
|
||||
print(f'\n📦 {pharm_name} (검색: {keyword}, 사이즈: {size})')
|
||||
for r in result:
|
||||
mark = '⭐' if size.lower() in r.product_name.lower() else ' '
|
||||
print(f'{mark} {r.apc}: {r.product_name[:50]}')
|
||||
|
||||
pg.close()
|
||||
75
backend/scripts/insert_apc_gesidin.py
Normal file
75
backend/scripts/insert_apc_gesidin.py
Normal file
@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys, io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text
|
||||
from datetime import datetime
|
||||
|
||||
session = get_db_session('PM_DRUG')
|
||||
|
||||
# 1. 기존 데이터에서 가격 정보 가져오기
|
||||
print('1. 기존 레코드에서 가격 정보 조회...')
|
||||
existing = session.execute(text("""
|
||||
SELECT TOP 1 CD_MY_UNIT, CD_IN_UNIT
|
||||
FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = 'LB000003140'
|
||||
ORDER BY SN DESC
|
||||
""")).fetchone()
|
||||
|
||||
sale_price = existing.CD_MY_UNIT
|
||||
purchase_price = existing.CD_IN_UNIT
|
||||
print(f' 판매가: {sale_price:,.0f}원')
|
||||
print(f' 입고가: {purchase_price:,.0f}원')
|
||||
|
||||
# 2. 오늘 날짜
|
||||
today = datetime.now().strftime('%Y%m%d')
|
||||
print(f'\n2. 날짜: {today}')
|
||||
|
||||
# 3. INSERT 실행
|
||||
print('\n3. INSERT 실행...')
|
||||
apc_code = '0231093520106' # 복합개시딘 10g
|
||||
|
||||
try:
|
||||
session.execute(text("""
|
||||
INSERT INTO CD_ITEM_UNIT_MEMBER (
|
||||
DRUGCODE, CD_CD_UNIT, CD_NM_UNIT, CD_MY_UNIT, CD_IN_UNIT,
|
||||
CD_CD_BARCODE, CD_CD_POS, CHANGE_DATE
|
||||
) VALUES (
|
||||
:drugcode, :unit, :nm_unit, :my_unit, :in_unit,
|
||||
:barcode, :pos, :change_date
|
||||
)
|
||||
"""), {
|
||||
'drugcode': 'LB000003140',
|
||||
'unit': '015',
|
||||
'nm_unit': 1.0,
|
||||
'my_unit': sale_price,
|
||||
'in_unit': purchase_price,
|
||||
'barcode': apc_code,
|
||||
'pos': '',
|
||||
'change_date': today
|
||||
})
|
||||
|
||||
session.commit()
|
||||
print(f' ✅ 성공! APC {apc_code} 추가됨')
|
||||
|
||||
# 4. 확인
|
||||
print('\n4. 결과 확인...')
|
||||
result = session.execute(text("""
|
||||
SELECT DRUGCODE, CD_CD_BARCODE, CD_MY_UNIT, SN
|
||||
FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = 'LB000003140' AND CD_CD_BARCODE = :apc
|
||||
"""), {'apc': apc_code})
|
||||
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
print(f' DRUGCODE: {row.DRUGCODE}')
|
||||
print(f' BARCODE: {row.CD_CD_BARCODE}')
|
||||
print(f' SN: {row.SN}')
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f' ❌ 실패: {e}')
|
||||
|
||||
session.close()
|
||||
90
backend/scripts/insert_apc_poppy.py
Normal file
90
backend/scripts/insert_apc_poppy.py
Normal file
@ -0,0 +1,90 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
안텔민뽀삐 APC 추가 실행 (SN 자동 생성)
|
||||
"""
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text
|
||||
from datetime import datetime
|
||||
|
||||
session = get_db_session('PM_DRUG')
|
||||
|
||||
# 1. 기존 데이터에서 가격 정보 가져오기
|
||||
print('1. 기존 레코드에서 가격 정보 조회...')
|
||||
existing = session.execute(text("""
|
||||
SELECT TOP 1 CD_MY_UNIT, CD_IN_UNIT
|
||||
FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = 'LB000003158'
|
||||
ORDER BY SN DESC
|
||||
""")).fetchone()
|
||||
|
||||
sale_price = existing.CD_MY_UNIT
|
||||
purchase_price = existing.CD_IN_UNIT
|
||||
print(f' 판매가: {sale_price:,.0f}원')
|
||||
print(f' 입고가: {purchase_price:,.0f}원')
|
||||
|
||||
# 2. 오늘 날짜
|
||||
today = datetime.now().strftime('%Y%m%d')
|
||||
print(f'\n2. 날짜: {today}')
|
||||
|
||||
# 3. INSERT 실행 (SN은 IDENTITY 자동 생성)
|
||||
print('\n3. INSERT 실행...')
|
||||
apc_code = '0230237010107' # 안텔민뽀삐 10정
|
||||
|
||||
try:
|
||||
session.execute(text("""
|
||||
INSERT INTO CD_ITEM_UNIT_MEMBER (
|
||||
DRUGCODE,
|
||||
CD_CD_UNIT,
|
||||
CD_NM_UNIT,
|
||||
CD_MY_UNIT,
|
||||
CD_IN_UNIT,
|
||||
CD_CD_BARCODE,
|
||||
CD_CD_POS,
|
||||
CHANGE_DATE
|
||||
) VALUES (
|
||||
:drugcode,
|
||||
:unit,
|
||||
:nm_unit,
|
||||
:my_unit,
|
||||
:in_unit,
|
||||
:barcode,
|
||||
:pos,
|
||||
:change_date
|
||||
)
|
||||
"""), {
|
||||
'drugcode': 'LB000003158',
|
||||
'unit': '015',
|
||||
'nm_unit': 1.0,
|
||||
'my_unit': sale_price,
|
||||
'in_unit': purchase_price,
|
||||
'barcode': apc_code,
|
||||
'pos': '',
|
||||
'change_date': today
|
||||
})
|
||||
|
||||
session.commit()
|
||||
print(f' ✅ 성공! APC {apc_code} 추가됨')
|
||||
|
||||
# 4. 확인
|
||||
print('\n4. 결과 확인...')
|
||||
result = session.execute(text("""
|
||||
SELECT * FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = 'LB000003158' AND CD_CD_BARCODE = :apc
|
||||
"""), {'apc': apc_code})
|
||||
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
print(' --- 추가된 레코드 ---')
|
||||
for col in result.keys():
|
||||
print(f' {col}: {getattr(row, col)}')
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f' ❌ 실패: {e}')
|
||||
|
||||
session.close()
|
||||
89
backend/scripts/prepare_apc_insert.py
Normal file
89
backend/scripts/prepare_apc_insert.py
Normal file
@ -0,0 +1,89 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
안텔민뽀삐 APC 추가 준비 스크립트
|
||||
- CD_ITEM_UNIT_MEMBER 구조 확인
|
||||
- 안텔민킹 레코드 참고
|
||||
- INSERT 쿼리 생성 (실행 안 함)
|
||||
"""
|
||||
import sys
|
||||
import io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text
|
||||
|
||||
session = get_db_session('PM_DRUG')
|
||||
|
||||
print('=' * 60)
|
||||
print('1. CD_ITEM_UNIT_MEMBER 테이블 구조')
|
||||
print('=' * 60)
|
||||
result = session.execute(text("""
|
||||
SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, CHARACTER_MAXIMUM_LENGTH
|
||||
FROM INFORMATION_SCHEMA.COLUMNS
|
||||
WHERE TABLE_NAME = 'CD_ITEM_UNIT_MEMBER'
|
||||
ORDER BY ORDINAL_POSITION
|
||||
"""))
|
||||
for r in result:
|
||||
nullable = 'NULL' if r.IS_NULLABLE == 'YES' else 'NOT NULL'
|
||||
length = f'({r.CHARACTER_MAXIMUM_LENGTH})' if r.CHARACTER_MAXIMUM_LENGTH else ''
|
||||
print(f' {r.COLUMN_NAME}: {r.DATA_TYPE}{length} {nullable}')
|
||||
|
||||
print('\n' + '=' * 60)
|
||||
print('2. 안텔민킹 APC 레코드 (참고용)')
|
||||
print('=' * 60)
|
||||
result = session.execute(text("""
|
||||
SELECT * FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = 'LB000003157'
|
||||
AND CD_CD_BARCODE LIKE '023%'
|
||||
"""))
|
||||
row = result.fetchone()
|
||||
if row:
|
||||
cols = result.keys()
|
||||
for col in cols:
|
||||
val = getattr(row, col)
|
||||
print(f' {col}: {val}')
|
||||
|
||||
print('\n' + '=' * 60)
|
||||
print('3. 안텔민뽀삐 현재 레코드')
|
||||
print('=' * 60)
|
||||
result2 = session.execute(text("""
|
||||
SELECT * FROM CD_ITEM_UNIT_MEMBER
|
||||
WHERE DRUGCODE = 'LB000003158'
|
||||
ORDER BY SN DESC
|
||||
"""))
|
||||
rows = list(result2)
|
||||
print(f' 총 {len(rows)}개 레코드')
|
||||
for row in rows[:3]:
|
||||
print(f'\n --- SN: {row.SN} ---')
|
||||
cols = result2.keys()
|
||||
for col in cols:
|
||||
val = getattr(row, col)
|
||||
print(f' {col}: {val}')
|
||||
|
||||
print('\n' + '=' * 60)
|
||||
print('4. 다음 SN 값 확인')
|
||||
print('=' * 60)
|
||||
result3 = session.execute(text("SELECT MAX(SN) as max_sn FROM CD_ITEM_UNIT_MEMBER"))
|
||||
max_sn = result3.fetchone().max_sn
|
||||
print(f' 현재 MAX(SN): {max_sn}')
|
||||
print(f' 다음 SN: {max_sn + 1}')
|
||||
|
||||
session.close()
|
||||
|
||||
print('\n' + '=' * 60)
|
||||
print('5. PostgreSQL에서 안텔민뽀삐 APC 확인')
|
||||
print('=' * 60)
|
||||
from sqlalchemy import create_engine
|
||||
pg = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master').connect()
|
||||
result4 = pg.execute(text("""
|
||||
SELECT apc, product_name
|
||||
FROM apc
|
||||
WHERE product_name ILIKE '%안텔민%뽀삐%' OR product_name ILIKE '%안텔민%5kg%이하%'
|
||||
ORDER BY apc
|
||||
"""))
|
||||
for r in result4:
|
||||
print(f' APC: {r.apc}')
|
||||
print(f' 제품명: {r.product_name}')
|
||||
print()
|
||||
pg.close()
|
||||
27
backend/scripts/show_llm_pharm.py
Normal file
27
backend/scripts/show_llm_pharm.py
Normal file
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys, io, json
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
from sqlalchemy import create_engine, text
|
||||
|
||||
pg = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master').connect()
|
||||
|
||||
# 안텔민킹 llm_pharm 전체 확인
|
||||
result = pg.execute(text("""
|
||||
SELECT product_name, llm_pharm FROM apc WHERE apc = '0230237810109'
|
||||
"""))
|
||||
row = result.fetchone()
|
||||
|
||||
print('=== 안텔민킹 llm_pharm 전체 키 ===\n')
|
||||
data = row.llm_pharm
|
||||
for k in sorted(data.keys()):
|
||||
val = str(data[k])
|
||||
if len(val) > 60:
|
||||
val = val[:60] + '...'
|
||||
print(f' {k}: {val}')
|
||||
|
||||
# 동물약 전체 개수
|
||||
print('\n=== PostgreSQL 동물약 전체 개수 ===')
|
||||
result2 = pg.execute(text("SELECT COUNT(*) FROM apc"))
|
||||
print(f' 전체: {result2.fetchone()[0]}개')
|
||||
|
||||
pg.close()
|
||||
43
backend/scripts/update_gesidin_category.py
Normal file
43
backend/scripts/update_gesidin_category.py
Normal file
@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import sys, io
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
sys.path.insert(0, 'c:\\Users\\청춘약국\\source\\pharmacy-pos-qr-system\\backend')
|
||||
|
||||
from db.dbsetup import get_db_session
|
||||
from sqlalchemy import text
|
||||
|
||||
session = get_db_session('PM_DRUG')
|
||||
|
||||
print('1. 현재 상태 확인...')
|
||||
result = session.execute(text("""
|
||||
SELECT DrugCode, GoodsName, POS_BOON
|
||||
FROM CD_GOODS
|
||||
WHERE DrugCode = 'LB000003140'
|
||||
"""))
|
||||
row = result.fetchone()
|
||||
print(f' {row.GoodsName}: POS_BOON = {row.POS_BOON}')
|
||||
|
||||
print('\n2. POS_BOON을 동물약(010103)으로 업데이트...')
|
||||
try:
|
||||
session.execute(text("""
|
||||
UPDATE CD_GOODS
|
||||
SET POS_BOON = '010103'
|
||||
WHERE DrugCode = 'LB000003140'
|
||||
"""))
|
||||
session.commit()
|
||||
print(' ✅ 성공!')
|
||||
|
||||
# 확인
|
||||
result2 = session.execute(text("""
|
||||
SELECT DrugCode, GoodsName, POS_BOON
|
||||
FROM CD_GOODS
|
||||
WHERE DrugCode = 'LB000003140'
|
||||
"""))
|
||||
row2 = result2.fetchone()
|
||||
print(f' {row2.GoodsName}: POS_BOON = {row2.POS_BOON}')
|
||||
|
||||
except Exception as e:
|
||||
session.rollback()
|
||||
print(f' ❌ 실패: {e}')
|
||||
|
||||
session.close()
|
||||
Loading…
Reference in New Issue
Block a user