diff --git a/backend/app.py b/backend/app.py index 0a40727..fa9de43 100644 --- a/backend/app.py +++ b/backend/app.py @@ -3306,10 +3306,12 @@ def api_products(): 제품 검색 API - 상품명, 상품코드, 바코드로 검색 - 세트상품 바코드도 CD_ITEM_UNIT_MEMBER에서 조회 + - in_stock_only: 사용약품만 (IM_total에 재고 있는 제품) """ search = request.args.get('search', '').strip() limit = int(request.args.get('limit', 100)) 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: return jsonify({'success': False, 'error': '검색어는 2글자 이상 입력하세요'}) @@ -3317,43 +3319,66 @@ def api_products(): try: drug_session = db_manager.get_session('PM_DRUG') - # 제품 검색 쿼리 - # CD_GOODS.BARCODE가 없으면 CD_ITEM_UNIT_MEMBER.CD_CD_BARCODE 사용 (세트상품) - # 세트상품 여부 확인: CD_item_set에 SetCode로 존재하면 세트상품 - 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 - """) + # 제품 검색 쿼리 - 사용약품만 옵션에 따라 JOIN 방식 변경 + # in_stock_only: INNER JOIN으로 재고 있는 제품만 (빠름) + # 그렇지 않으면: LEFT JOIN으로 모든 제품 (느림) + if in_stock_only: + # 최적화된 쿼리: 재고 있는 제품만 (IM_total INNER JOIN) + 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, + 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 + 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 + """) search_like = f'%{search}%' rows = drug_session.execute(products_query, { diff --git a/backend/templates/admin_products.html b/backend/templates/admin_products.html index 14e6a20..12e6b6f 100644 --- a/backend/templates/admin_products.html +++ b/backend/templates/admin_products.html @@ -581,12 +581,20 @@
예시 타이레놀, 벤포파워, 8806418067510, LB000001423
- +
+ + +
@@ -700,7 +708,11 @@ tbody.innerHTML = '

검색 중...

'; const animalOnly = document.getElementById('animalOnly').checked; - fetch(`/api/products?search=${encodeURIComponent(search)}${animalOnly ? '&animal_only=1' : ''}`) + const inStockOnly = document.getElementById('inStockOnly').checked; + let url = `/api/products?search=${encodeURIComponent(search)}`; + if (animalOnly) url += '&animal_only=1'; + if (inStockOnly) url += '&in_stock_only=1'; + fetch(url) .then(res => res.json()) .then(data => { if (data.success) {