feat: 동물약만 체크 시 검색어 없이 전체 조회 가능

- 동물약은 39건뿐이라 전체 조회해도 빠름
- 동물약만 체크 + 검색어 없음 → 전체 동물약 리스트
- 쿼리 조건 동적 생성 (animal_condition, search_condition)
This commit is contained in:
thug0bin 2026-03-04 14:02:47 +09:00
parent a0cbb984e5
commit 2859dc43cc
2 changed files with 86 additions and 57 deletions

View File

@ -3313,15 +3313,26 @@ def api_products():
animal_only = request.args.get('animal_only', '0') == '1'
in_stock_only = request.args.get('in_stock_only', '0') == '1'
if not search or len(search) < 2:
# 동물약만 체크시 검색어 없어도 전체 조회 가능
if not animal_only and (not search or len(search) < 2):
return jsonify({'success': False, 'error': '검색어는 2글자 이상 입력하세요'})
try:
drug_session = db_manager.get_session('PM_DRUG')
# WHERE 조건 생성 (동물약 전체 조회 시 검색 조건 없음)
search_condition = ""
if search:
search_condition = """
AND (G.GoodsName LIKE :search_like
OR G.DrugCode LIKE :search_like
OR G.BARCODE LIKE :search_like)
"""
# 동물약만 필터 (쿼리에서 직접 처리)
animal_condition = "AND G.POS_BOON = '010103'" if animal_only else ""
# 제품 검색 쿼리 - 사용약품만 옵션에 따라 JOIN 방식 변경
# in_stock_only: INNER JOIN으로 재고 있는 제품만 (빠름)
# 그렇지 않으면: LEFT JOIN으로 모든 제품 (느림)
if in_stock_only:
# 최적화된 쿼리: 재고 있는 제품만 (IM_total INNER JOIN)
products_query = text(f"""
@ -3337,62 +3348,76 @@ def api_products():
IT.IM_QT_sale_debit as stock
FROM CD_GOODS G
INNER JOIN IM_total IT ON G.DrugCode = IT.DrugCode AND IT.IM_QT_sale_debit > 0
WHERE
G.GoodsName LIKE :search_like
OR G.DrugCode LIKE :search_like
OR G.BARCODE LIKE :search_like
WHERE 1=1
{animal_condition}
{search_condition}
ORDER BY G.GoodsName
""")
else:
# 전체 쿼리 (OUTER APPLY 포함, 느림)
products_query = text(f"""
SELECT TOP {limit}
G.DrugCode as drug_code,
G.GoodsName as product_name,
COALESCE(NULLIF(G.BARCODE, ''), U.CD_CD_BARCODE, '') as barcode,
G.Saleprice as sale_price,
G.Price as cost_price,
CASE
WHEN G.SplName IS NOT NULL AND G.SplName != '' THEN G.SplName
WHEN SET_CHK.is_set = 1 THEN N'세트상품'
ELSE ''
END as supplier,
CASE WHEN SET_CHK.is_set = 1 THEN 1 ELSE 0 END as is_set,
G.POS_BOON as pos_boon,
ISNULL(IT.IM_QT_sale_debit, 0) as stock
FROM CD_GOODS G
LEFT JOIN IM_total IT ON G.DrugCode = IT.DrugCode
OUTER APPLY (
SELECT TOP 1 CD_CD_BARCODE
FROM CD_ITEM_UNIT_MEMBER
WHERE DRUGCODE = G.DrugCode AND CD_CD_BARCODE IS NOT NULL AND CD_CD_BARCODE != ''
) U
OUTER APPLY (
SELECT TOP 1 1 as is_set
FROM CD_item_set
WHERE SetCode = G.DrugCode AND DrugCode = 'SET0000'
) SET_CHK
WHERE
G.GoodsName LIKE :search_like
OR G.DrugCode LIKE :search_like
OR G.BARCODE LIKE :search_like
OR U.CD_CD_BARCODE LIKE :search_like
ORDER BY G.GoodsName
""")
# 동물약만 조회 시 OUTER APPLY 생략 가능
if animal_only:
products_query = text(f"""
SELECT TOP {limit}
G.DrugCode as drug_code,
G.GoodsName as product_name,
COALESCE(NULLIF(G.BARCODE, ''), '') as barcode,
G.Saleprice as sale_price,
G.Price as cost_price,
ISNULL(G.SplName, '') as supplier,
0 as is_set,
G.POS_BOON as pos_boon,
ISNULL(IT.IM_QT_sale_debit, 0) as stock
FROM CD_GOODS G
LEFT JOIN IM_total IT ON G.DrugCode = IT.DrugCode
WHERE G.POS_BOON = '010103'
{search_condition}
ORDER BY G.GoodsName
""")
else:
products_query = text(f"""
SELECT TOP {limit}
G.DrugCode as drug_code,
G.GoodsName as product_name,
COALESCE(NULLIF(G.BARCODE, ''), U.CD_CD_BARCODE, '') as barcode,
G.Saleprice as sale_price,
G.Price as cost_price,
CASE
WHEN G.SplName IS NOT NULL AND G.SplName != '' THEN G.SplName
WHEN SET_CHK.is_set = 1 THEN N'세트상품'
ELSE ''
END as supplier,
CASE WHEN SET_CHK.is_set = 1 THEN 1 ELSE 0 END as is_set,
G.POS_BOON as pos_boon,
ISNULL(IT.IM_QT_sale_debit, 0) as stock
FROM CD_GOODS G
LEFT JOIN IM_total IT ON G.DrugCode = IT.DrugCode
OUTER APPLY (
SELECT TOP 1 CD_CD_BARCODE
FROM CD_ITEM_UNIT_MEMBER
WHERE DRUGCODE = G.DrugCode AND CD_CD_BARCODE IS NOT NULL AND CD_CD_BARCODE != ''
) U
OUTER APPLY (
SELECT TOP 1 1 as is_set
FROM CD_item_set
WHERE SetCode = G.DrugCode AND DrugCode = 'SET0000'
) SET_CHK
WHERE 1=1
{search_condition}
ORDER BY G.GoodsName
""")
search_like = f'%{search}%'
rows = drug_session.execute(products_query, {
'search_like': search_like
}).fetchall()
# 파라미터 설정 (검색어가 있을 때만)
params = {}
if search:
params['search_like'] = f'%{search}%'
rows = drug_session.execute(products_query, params).fetchall()
items = []
for row in rows:
is_animal = row.pos_boon == '010103'
# 동물약만 필터링
if animal_only and not is_animal:
continue
# APC 조회 (동물약인 경우)
apc = None
if is_animal:

View File

@ -695,19 +695,23 @@
function searchProducts() {
const search = document.getElementById('searchInput').value.trim();
if (!search) {
alert('검색어를 입력하세요');
return;
}
if (search.length < 2) {
alert('2글자 이상 입력하세요');
return;
const animalOnly = document.getElementById('animalOnly').checked;
// 동물약만 체크시 검색어 없어도 전체 조회 가능
if (!animalOnly) {
if (!search) {
alert('검색어를 입력하세요');
return;
}
if (search.length < 2) {
alert('2글자 이상 입력하세요');
return;
}
}
const tbody = document.getElementById('productsTableBody');
tbody.innerHTML = '<tr><td colspan="6" class="empty-state"><p>검색 중...</p></td></tr>';
const animalOnly = document.getElementById('animalOnly').checked;
const inStockOnly = document.getElementById('inStockOnly').checked;
let url = `/api/products?search=${encodeURIComponent(search)}`;
if (animalOnly) url += '&animal_only=1';