feat: 제품 검색에 분류 뱃지 + 도매상 재고 추가 (PostgreSQL 방어적 lazy fetch)

This commit is contained in:
thug0bin 2026-02-28 12:48:58 +09:00
parent 4c93ee038a
commit 6a786ff042
2 changed files with 67 additions and 4 deletions

View File

@ -3125,6 +3125,23 @@ def api_products():
if animal_only and not is_animal:
continue
# APC 조회 (동물약인 경우)
apc = None
if is_animal:
try:
apc_result = drug_session.execute(text("""
SELECT TOP 1 CD_CD_BARCODE
FROM CD_ITEM_UNIT_MEMBER
WHERE DRUGCODE = :drug_code AND CD_CD_BARCODE LIKE '023%'
"""), {'drug_code': row.drug_code})
apc_row = apc_result.fetchone()
if apc_row:
apc = apc_row[0]
elif row.barcode:
apc = row.barcode # 바코드=APC 케이스
except:
pass
items.append({
'drug_code': row.drug_code or '',
'product_name': row.product_name or '',
@ -3134,9 +3151,44 @@ def api_products():
'supplier': row.supplier or '',
'is_set': bool(row.is_set),
'is_animal_drug': is_animal,
'stock': int(row.stock) if row.stock else 0
'stock': int(row.stock) if row.stock else 0,
'apc': apc,
'category': None, # PostgreSQL에서 lazy fetch
'wholesaler_stock': None
})
# 동물약 분류 Lazy Fetch (PostgreSQL) - 실패해도 무시
animal_items = [i for i in items if i['is_animal_drug'] and i['apc']]
if animal_items:
try:
from sqlalchemy import create_engine
pg_engine = create_engine('postgresql://admin:trajet6640@192.168.0.87:5432/apdb_master',
connect_args={'connect_timeout': 3}) # 3초 타임아웃
with pg_engine.connect() as conn:
apc_list = [i['apc'] for i in animal_items if i['apc']]
if apc_list:
placeholders = ','.join([f"'{a}'" for a in apc_list])
# 분류 + 도매상 재고 조회
result = conn.execute(text(f"""
SELECT
A.apc,
A.llm_pharm->>'분류' as category,
COALESCE(SUM(I.quantity), 0) as wholesaler_stock
FROM apc A
LEFT JOIN inventory I ON I.apdb_id = A.idx
WHERE A.apc IN ({placeholders})
GROUP BY A.apc, A.llm_pharm
"""))
pg_map = {row.apc: {'category': row.category, 'ws': int(row.wholesaler_stock)} for row in result}
for item in items:
if item['apc'] and item['apc'] in pg_map:
item['category'] = pg_map[item['apc']]['category']
item['wholesaler_stock'] = pg_map[item['apc']]['ws']
except Exception as pg_err:
logging.warning(f"PostgreSQL 분류 조회 실패 (무시): {pg_err}")
# PostgreSQL 실패해도 MSSQL 데이터는 정상 반환
return jsonify({
'success': True,
'items': items,

View File

@ -725,12 +725,23 @@
return;
}
tbody.innerHTML = productsData.map((item, idx) => `
tbody.innerHTML = productsData.map((item, idx) => {
// 분류 뱃지 (동물약만)
const categoryBadge = item.category
? `<span style="display:inline-block;background:#8b5cf6;color:#fff;font-size:10px;padding:2px 5px;border-radius:3px;margin-left:4px;">${escapeHtml(item.category)}</span>`
: '';
// 도매상 재고 표시 (동물약만)
const wsStock = (item.wholesaler_stock && item.wholesaler_stock > 0)
? `<span style="color:#3b82f6;font-size:11px;margin-left:4px;">(도매 ${item.wholesaler_stock})</span>`
: '';
return `
<tr>
<td>
<div class="product-name">
${escapeHtml(item.product_name)}
${item.is_animal_drug ? '<span style="display:inline-block;background:#10b981;color:#fff;font-size:11px;padding:2px 6px;border-radius:4px;margin-left:6px;">🐾 동물약</span>' : ''}
${categoryBadge}
</div>
<div class="product-supplier ${item.is_set ? 'set' : ''}">${escapeHtml(item.supplier) || ''}</div>
</td>
@ -738,13 +749,13 @@
<td>${item.barcode
? `<span class="code code-barcode">${item.barcode}</span>`
: `<span class="code code-na">없음</span>`}</td>
<td class="stock ${(item.stock || 0) > 0 ? 'in-stock' : 'out-stock'}">${item.stock || 0}</td>
<td class="stock ${(item.stock || 0) > 0 ? 'in-stock' : 'out-stock'}">${item.stock || 0}${wsStock}</td>
<td class="price">${formatPrice(item.sale_price)}</td>
<td>
<button class="btn-qr" onclick="printQR(${idx})">🏷️ QR</button>
</td>
</tr>
`).join('');
`}).join('');
}
// ── QR 인쇄 관련 ──