/** * 의약품 마스터 검색 + 입고 장바구니 모듈 */ (function() { 'use strict'; // 장바구니 데이터 (세션 메모리) let cart = []; const ORIGIN_OPTIONS = ['한국','중국','베트남','인도','태국','페루','일본','기타']; // ─── 검색 ─────────────────────────────────────────────── function searchMedicine() { const query = $('#medSearchInput').val().trim(); const category = $('#medCategoryFilter').val(); const packageType = $('#medPackageFilter').val(); if (query.length < 2) { alert('검색어는 2자 이상 입력하세요.'); return; } const params = new URLSearchParams({ q: query, limit: 100 }); if (category) params.append('category', category); if (packageType) params.append('package_type', packageType); $('#medSearchResults').html('
검색중...'); $.get(`/api/medicine-master/search?${params}`, function(response) { if (!response.success) { $('#medSearchResults').html(`${response.error}`); return; } const tbody = $('#medSearchResults'); tbody.empty(); $('#medResultCount').text(response.count); if (response.data.length === 0) { tbody.html('검색 결과가 없습니다.'); return; } response.data.forEach(item => { let categoryBadge = ''; switch(item.category) { case '일반의약품': categoryBadge = '일반'; break; case '전문의약품': categoryBadge = '전문'; break; case '한약재': categoryBadge = '한약재'; break; case '원료의약품': categoryBadge = '원료'; break; default: categoryBadge = `${item.category || '-'}`; } const cleanName = item.product_name.replace(/ /g, ' ').trim(); const notes = item.notes ? item.notes.replace(/ /g, ' ').trim() : ''; const inCart = cart.some(c => c.standard_code === item.standard_code); const itemJson = JSON.stringify(item).replace(/'/g, "'"); tbody.append(` ${cleanName} ${item.form_type ? `
${item.form_type}` : ''} ${item.company_name || '-'} ${item.spec || '-'} ${item.package_type || '-'} ${categoryBadge} ${item.standard_code || '-'} ${notes.length > 30 ? notes.substring(0, 30) + '...' : notes} `); }); // 상세보기 이벤트 $('.med-detail-btn').off('click').on('click', function() { const item = JSON.parse($(this).attr('data-item')); showMedicineDetail(item); }); // 장바구니 담기 이벤트 $('.med-add-cart-btn').off('click').on('click', function() { const item = JSON.parse($(this).attr('data-item')); addToCart(item); $(this).prop('disabled', true); }); }).fail(function(xhr) { $('#medSearchResults').html(`검색 실패: ${xhr.responseJSON?.error || '서버 오류'}`); }); } // ─── 상세보기 모달 ───────────────────────────────────── function showMedicineDetail(item) { const cleanName = item.product_name.replace(/ /g, ' ').trim(); $('#medDetailTitle').text(cleanName); const fields = [ { label: '상품명', value: cleanName }, { label: '업체명', value: item.company_name }, { label: '규격', value: item.spec }, { label: '제형구분', value: item.form_type }, { label: '포장형태', value: item.package_type }, { label: '전문일반구분', value: item.category }, { label: '품목기준코드', value: item.item_std_code }, { label: '대표코드', value: item.representative_code }, { label: '표준코드', value: item.standard_code }, { label: '일반명코드', value: item.ingredient_name_code }, { label: 'ATC코드', value: item.atc_code }, { label: '비고', value: item.notes?.replace(/ /g, ' ') }, ]; let html = ''; fields.forEach(f => { if (f.value) { html += ``; } }); html += '
${f.label}${f.value}
'; $('#medDetailBody').html(html); $('#medDetailModal').modal('show'); } // ─── 규격 파싱 ─────────────────────────────────────────── // 규격 문자열에서 그램 수 추출 (예: "500그램"→500, "1000그램"→1000) function parseSpecToGrams(spec) { if (!spec) return 0; const s = spec.trim(); // "500그램", "1000그램", "1252.5그램" let m = s.match(/^([\d.]+)\s*그램$/); if (m) return parseFloat(m[1]); // "500g", "1000G" m = s.match(/^([\d.]+)\s*[gG]$/); if (m) return parseFloat(m[1]); // "1kg", "1.5Kg", "1킬로그램" m = s.match(/^([\d.]+)\s*(kg|킬로그램)$/i); if (m) return parseFloat(m[1]) * 1000; // "500밀리그램" → 0.5g m = s.match(/^([\d.]+)\s*밀리그램$/); if (m) return parseFloat(m[1]) / 1000; // "500mg" m = s.match(/^([\d.]+)\s*mg$/i); if (m) return parseFloat(m[1]) / 1000; return 0; // 파싱 불가 ("없음" 등) } // ─── 장바구니 기능 ───────────────────────────────────── function addToCart(item) { // 중복 체크 if (cart.some(c => c.standard_code === item.standard_code)) { alert('이미 장바구니에 있는 항목입니다.'); return; } const cleanName = item.product_name.replace(/ /g, ' ').trim(); const specGrams = parseSpecToGrams(item.spec); cart.push({ standard_code: item.standard_code, product_name: cleanName, company_name: item.company_name || '', spec: item.spec || '', spec_grams: specGrams, // 규격에서 파싱한 g 수 qty: 1, // 수량 (포장 단위) unit_price: 0, // 단가 (종이 입고장 가격) origin_country: '한국', _raw: item }); renderCart(); } function removeFromCart(index) { const removed = cart.splice(index, 1)[0]; if (removed) { $(`.med-add-cart-btn[data-code="${removed.standard_code}"]`).prop('disabled', false); } renderCart(); } function clearCart() { if (cart.length === 0) return; if (!confirm('장바구니를 비우시겠습니까?')) return; const codes = cart.map(c => c.standard_code); cart = []; codes.forEach(code => { $(`.med-add-cart-btn[data-code="${code}"]`).prop('disabled', false); }); renderCart(); } function renderCart() { const panel = $('#cartPanel'); const tbody = $('#cartBody'); if (cart.length === 0) { panel.hide(); return; } panel.show(); $('#cartCount').text(cart.length); tbody.empty(); let totalQty = 0; let totalAmt = 0; cart.forEach((item, idx) => { const amt = (item.qty || 0) * (item.unit_price || 0); const pricePerG = (item.spec_grams && item.unit_price) ? (item.unit_price / item.spec_grams) : 0; totalQty += (item.qty || 0); totalAmt += amt; const originOptions = ORIGIN_OPTIONS.map(o => `` ).join(''); const specDisplay = item.spec_grams ? `${item.spec}
${item.spec_grams.toLocaleString()}g` : `${item.spec || '-'}
수동입력`; tbody.append(` ${item.product_name} ${item.company_name || '-'} ${specDisplay} ${amt ? amt.toLocaleString() : '-'} ${pricePerG ? pricePerG.toFixed(1) : '-'} `); }); $('#cartTotalQty').text(totalQty ? totalQty.toLocaleString() : '0'); $('#cartTotalAmt').text(totalAmt ? totalAmt.toLocaleString() + '원' : '0'); // 이벤트 바인딩 tbody.find('.cart-qty').off('input').on('input', function() { const idx = $(this).data('idx'); cart[idx].qty = parseInt($(this).val()) || 0; updateCartRow(idx); }); tbody.find('.cart-unit-price').off('input').on('input', function() { const idx = $(this).data('idx'); cart[idx].unit_price = parseFloat($(this).val()) || 0; updateCartRow(idx); }); tbody.find('.cart-origin').off('change').on('change', function() { const idx = $(this).data('idx'); cart[idx].origin_country = $(this).val(); }); tbody.find('.cart-remove-btn').off('click').on('click', function() { removeFromCart($(this).data('idx')); }); } function updateCartRow(idx) { const item = cart[idx]; const amt = (item.qty || 0) * (item.unit_price || 0); const pricePerG = (item.spec_grams && item.unit_price) ? (item.unit_price / item.spec_grams) : 0; $(`.cart-amt[data-idx="${idx}"]`).text(amt ? amt.toLocaleString() : '-'); $(`.cart-ppg[data-idx="${idx}"]`).html(`${pricePerG ? pricePerG.toFixed(1) : '-'}`); updateCartTotals(); } function updateCartTotals() { let totalQty = 0; let totalAmt = 0; cart.forEach(item => { totalQty += (item.qty || 0); totalAmt += (item.qty || 0) * (item.unit_price || 0); }); $('#cartTotalQty').text(totalQty ? totalQty.toLocaleString() : '0'); $('#cartTotalAmt').text(totalAmt ? totalAmt.toLocaleString() + '원' : '0'); } // ─── 입고장 생성 ─────────────────────────────────────── function createReceipt() { // 검증 const supplierId = $('#cartSupplier').val(); const receiptDate = $('#cartReceiptDate').val(); const notes = $('#cartNotes').val().trim(); if (!supplierId) { alert('도매상을 선택해주세요.'); $('#cartSupplier').focus(); return; } if (!receiptDate) { alert('입고일을 입력해주세요.'); $('#cartReceiptDate').focus(); return; } if (cart.length === 0) { alert('장바구니가 비어있습니다.'); return; } // 단가 미입력 체크 const incomplete = cart.filter(c => !c.unit_price); if (incomplete.length > 0) { alert(`단가가 입력되지 않은 항목이 ${incomplete.length}건 있습니다.\n모든 항목의 단가를 입력해주세요.`); return; } // 규격 미파싱 경고 (spec_grams=0이면 g 환산 불가) const noSpec = cart.filter(c => !c.spec_grams); if (noSpec.length > 0) { const ok = confirm( `규격(g)을 파싱할 수 없는 항목이 ${noSpec.length}건 있습니다.\n` + `해당 항목은 g당단가가 계산되지 않습니다.\n\n` + noSpec.map(c => '- ' + c.product_name + ' (' + c.spec + ')').join('\n') + '\n\n그래도 진행하시겠습니까?' ); if (!ok) return; } // 확인 요약 const supplierName = $('#cartSupplier option:selected').text(); let totalAmt = 0; cart.forEach(item => { totalAmt += (item.qty || 0) * (item.unit_price || 0); }); const summary = [ `도매상: ${supplierName}`, `입고일: ${receiptDate}`, `품목 수: ${cart.length}건`, `총 금액: ${totalAmt.toLocaleString()}원`, ].join('\n'); if (!confirm(`입고장을 생성하시겠습니까?\n\n${summary}`)) return; // API 요청 데이터 구성 const payload = { supplier_id: parseInt(supplierId), receipt_date: receiptDate, notes: notes, lines: cart.map(c => ({ standard_code: c.standard_code, product_name: c.product_name, company_name: c.company_name, spec: c.spec, spec_grams: c.spec_grams, qty: c.qty, unit_price: c.unit_price, origin_country: c.origin_country })) }; // 버튼 비활성화 const btn = $('#createReceiptBtn'); btn.prop('disabled', true).html(' 처리중...'); $.ajax({ url: '/api/purchase-receipts/from-cart', method: 'POST', contentType: 'application/json', data: JSON.stringify(payload), success: function(response) { if (response.success) { alert( `입고 완료!\n\n` + `입고장 번호: ${response.receipt_no}\n` + `품목: ${response.summary.item_count}건\n` + `총 금액: ${response.summary.total_amount}` ); // 장바구니 초기화 cart = []; renderCart(); // 검색결과 버튼 전부 재활성화 $('.med-add-cart-btn').prop('disabled', false); } else { alert('입고 실패: ' + response.error); } }, error: function(xhr) { const msg = xhr.responseJSON?.error || '서버 오류'; alert('입고 실패: ' + msg); }, complete: function() { btn.prop('disabled', false).html(' 입고장 생성'); } }); } // ─── 도매상 로드 ─────────────────────────────────────── function loadSuppliers() { $.get('/api/suppliers', function(response) { if (!response.success) return; const sel = $('#cartSupplier'); sel.find('option:not(:first)').remove(); response.data.forEach(s => { sel.append(``); }); }); } // ─── 초기화 ──────────────────────────────────────────── function init() { // 검색 $('#medSearchBtn').off('click').on('click', searchMedicine); $('#medSearchInput').off('keypress').on('keypress', function(e) { if (e.which === 13) searchMedicine(); }); $('#medCategoryFilter, #medPackageFilter').off('change').on('change', function() { if ($('#medSearchInput').val().trim().length >= 2) { searchMedicine(); } }); // 장바구니 $('#cartClearBtn').off('click').on('click', clearCart); $('#createReceiptBtn').off('click').on('click', createReceipt); // 입고일 기본값: 오늘 $('#cartReceiptDate').val(new Date().toISOString().split('T')[0]); // 도매상 목록 로드 loadSuppliers(); // 이전 장바구니 상태 복원 (없으면 숨김) renderCart(); } // 글로벌 로드 함수 등록 window.loadMedicineMaster = function() { init(); }; })();