fix: rx-usage 쿼리에 PS_Type!=9 조건 추가 (실제 조제된 약만 집계)
- patient_query: 대체조제 원본 처방 제외 - rx_query: 대체조제 원본 처방 제외 - PS_Type=9는 대체조제시 원래 처방된 약(조제 안됨) - 기타 배치 스크립트 및 문서 추가
This commit is contained in:
@@ -939,7 +939,7 @@
|
||||
loadOrderData(); // 수인약품 주문량 로드
|
||||
});
|
||||
|
||||
// ──────────────── 도매상 주문량 조회 (지오영 + 수인 + 백제 합산) ────────────────
|
||||
// ──────────────── 도매상 주문량 조회 (지오영 + 수인 + 백제 + 동원 합산) ────────────────
|
||||
async function loadOrderData() {
|
||||
const startDate = document.getElementById('startDate').value;
|
||||
const endDate = document.getElementById('endDate').value;
|
||||
@@ -948,11 +948,12 @@
|
||||
orderDataByKd = {};
|
||||
|
||||
try {
|
||||
// 지오영 + 수인 + 백제 병렬 조회
|
||||
const [geoRes, sooinRes, baekjeRes] = await Promise.all([
|
||||
// 지오영 + 수인 + 백제 + 동원 병렬 조회
|
||||
const [geoRes, sooinRes, baekjeRes, dongwonRes] = await Promise.all([
|
||||
fetch(`/api/geoyoung/orders/summary-by-kd?start_date=${startDate}&end_date=${endDate}`).then(r => r.json()).catch(() => ({ success: false })),
|
||||
fetch(`/api/sooin/orders/summary-by-kd?start_date=${startDate}&end_date=${endDate}`).then(r => r.json()).catch(() => ({ success: false })),
|
||||
fetch(`/api/baekje/orders/summary-by-kd?start_date=${startDate}&end_date=${endDate}`).then(r => r.json()).catch(() => ({ success: false }))
|
||||
fetch(`/api/baekje/orders/summary-by-kd?start_date=${startDate}&end_date=${endDate}`).then(r => r.json()).catch(() => ({ success: false })),
|
||||
fetch(`/api/dongwon/orders/summary-by-kd?start_date=${startDate}&end_date=${endDate}`).then(r => r.json()).catch(() => ({ success: false }))
|
||||
]);
|
||||
|
||||
let totalOrders = 0;
|
||||
@@ -999,7 +1000,21 @@
|
||||
console.log('💉 백제 주문량:', Object.keys(baekjeRes.by_kd_code).length, '품목,', baekjeRes.order_count, '건');
|
||||
}
|
||||
|
||||
console.log('📦 3사 합산 주문량:', Object.keys(orderDataByKd).length, '품목,', totalOrders, '건 주문');
|
||||
// 동원 데이터 합산
|
||||
if (dongwonRes.success && dongwonRes.by_kd_code) {
|
||||
for (const [kd, data] of Object.entries(dongwonRes.by_kd_code)) {
|
||||
if (!orderDataByKd[kd]) {
|
||||
orderDataByKd[kd] = { product_name: data.product_name, spec: data.spec, boxes: 0, units: 0, sources: [] };
|
||||
}
|
||||
orderDataByKd[kd].boxes += data.boxes || 0;
|
||||
orderDataByKd[kd].units += data.units || 0;
|
||||
orderDataByKd[kd].sources.push('동원');
|
||||
}
|
||||
totalOrders += dongwonRes.order_count || 0;
|
||||
console.log('🟠 동원 주문량:', Object.keys(dongwonRes.by_kd_code).length, '품목,', dongwonRes.order_count, '건');
|
||||
}
|
||||
|
||||
console.log('📦 4사 합산 주문량:', Object.keys(orderDataByKd).length, '품목,', totalOrders, '건 주문');
|
||||
|
||||
} catch(err) {
|
||||
console.warn('주문량 조회 실패:', err);
|
||||
@@ -1269,6 +1284,16 @@
|
||||
gradient: 'linear-gradient(135deg, #d97706, #f59e0b)',
|
||||
filterFn: (item) => item.supplier === '백제약품' || item.wholesaler === 'baekje',
|
||||
getCode: (item) => item.baekje_code || item.drug_code
|
||||
},
|
||||
dongwon: {
|
||||
id: 'dongwon',
|
||||
name: '동원약품',
|
||||
icon: '🏥',
|
||||
logo: '/static/img/logo_dongwon.png',
|
||||
color: '#22c55e',
|
||||
gradient: 'linear-gradient(135deg, #16a34a, #22c55e)',
|
||||
filterFn: (item) => item.supplier === '동원약품' || item.wholesaler === 'dongwon',
|
||||
getCode: (item) => item.dongwon_code || item.internal_code || item.drug_code
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2043,9 +2068,9 @@
|
||||
if (e.key === 'Enter') loadUsageData();
|
||||
});
|
||||
|
||||
// ──────────────── 도매상 재고 조회 (지오영 + 수인 + 백제) ────────────────
|
||||
// ──────────────── 도매상 재고 조회 (지오영 + 수인 + 백제 + 동원) ────────────────
|
||||
let currentWholesaleItem = null;
|
||||
window.wholesaleItems = { geoyoung: [], sooin: [], baekje: [] };
|
||||
window.wholesaleItems = { geoyoung: [], sooin: [], baekje: [], dongwon: [] };
|
||||
|
||||
function openWholesaleModal(idx) {
|
||||
const item = usageData[idx];
|
||||
@@ -2065,7 +2090,7 @@
|
||||
document.getElementById('geoResultBody').innerHTML = `
|
||||
<div class="geo-loading">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>도매상 재고 조회 중... (지오영 + 수인 + 백제)</div>
|
||||
<div>도매상 재고 조회 중... (지오영 + 수인 + 백제 + 동원)</div>
|
||||
</div>`;
|
||||
document.getElementById('geoSearchKeyword').style.display = 'none';
|
||||
|
||||
@@ -2081,22 +2106,24 @@
|
||||
async function searchAllWholesalers(kdCode, productName) {
|
||||
const resultBody = document.getElementById('geoResultBody');
|
||||
|
||||
// 세 도매상 동시 호출
|
||||
const [geoResult, sooinResult, baekjeResult] = await Promise.all([
|
||||
// 네 도매상 동시 호출
|
||||
const [geoResult, sooinResult, baekjeResult, dongwonResult] = await Promise.all([
|
||||
searchGeoyoungAPI(kdCode, productName),
|
||||
searchSooinAPI(kdCode),
|
||||
searchBaekjeAPI(kdCode)
|
||||
searchBaekjeAPI(kdCode),
|
||||
searchDongwonAPI(kdCode, productName)
|
||||
]);
|
||||
|
||||
// 결과 저장
|
||||
window.wholesaleItems = {
|
||||
geoyoung: geoResult.items || [],
|
||||
sooin: sooinResult.items || [],
|
||||
baekje: baekjeResult.items || []
|
||||
baekje: baekjeResult.items || [],
|
||||
dongwon: dongwonResult.items || []
|
||||
};
|
||||
|
||||
// 통합 렌더링
|
||||
renderWholesaleResults(geoResult, sooinResult, baekjeResult);
|
||||
renderWholesaleResults(geoResult, sooinResult, baekjeResult, dongwonResult);
|
||||
}
|
||||
|
||||
async function searchGeoyoungAPI(kdCode, productName) {
|
||||
@@ -2136,18 +2163,42 @@
|
||||
return { success: false, error: err.message, items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
async function searchDongwonAPI(kdCode, productName) {
|
||||
try {
|
||||
// 1차: KD코드(보험코드)로 검색 (searchType=0)
|
||||
let response = await fetch(`/api/dongwon/stock?keyword=${encodeURIComponent(kdCode)}`);
|
||||
let data = await response.json();
|
||||
|
||||
// 결과 없으면 제품명으로 재검색
|
||||
if (data.success && data.count === 0 && productName) {
|
||||
// 제품명 정제: "휴니즈레바미피드정_(0.1g/1정)" → "휴니즈레바미피드정"
|
||||
let cleanName = productName.split('_')[0].split('(')[0].trim();
|
||||
if (cleanName) {
|
||||
response = await fetch(`/api/dongwon/stock?keyword=${encodeURIComponent(cleanName)}`);
|
||||
data = await response.json();
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
} catch (err) {
|
||||
return { success: false, error: err.message, items: [] };
|
||||
}
|
||||
}
|
||||
|
||||
function renderWholesaleResults(geoResult, sooinResult, baekjeResult) {
|
||||
function renderWholesaleResults(geoResult, sooinResult, baekjeResult, dongwonResult) {
|
||||
const resultBody = document.getElementById('geoResultBody');
|
||||
|
||||
const geoItems = geoResult.items || [];
|
||||
const sooinItems = sooinResult.items || [];
|
||||
const baekjeItems = (baekjeResult && baekjeResult.items) || [];
|
||||
const dongwonItems = (dongwonResult && dongwonResult.items) || [];
|
||||
|
||||
// 재고 있는 것 먼저 정렬
|
||||
geoItems.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock);
|
||||
sooinItems.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock);
|
||||
baekjeItems.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock);
|
||||
dongwonItems.sort((a, b) => (b.stock > 0 ? 1 : 0) - (a.stock > 0 ? 1 : 0) || b.stock - a.stock);
|
||||
|
||||
let html = '';
|
||||
|
||||
@@ -2260,6 +2311,44 @@
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
// ═══════ 동원약품 섹션 ═══════
|
||||
html += `<div class="ws-section">
|
||||
<div class="ws-header dongwon">
|
||||
<span class="ws-logo">🏥</span>
|
||||
<span class="ws-name">동원약품</span>
|
||||
<span class="ws-count">${dongwonItems.length}건</span>
|
||||
</div>`;
|
||||
|
||||
if (dongwonItems.length > 0) {
|
||||
html += `<table class="geo-table">
|
||||
<thead><tr><th>제품명</th><th>규격</th><th>단가</th><th>재고</th><th></th></tr></thead>
|
||||
<tbody>`;
|
||||
|
||||
dongwonItems.forEach((item, idx) => {
|
||||
const hasStock = item.stock > 0;
|
||||
// 동원: code=KD코드(보험코드), internal_code=내부코드(주문용)
|
||||
const displayCode = item.code || item.internal_code || '';
|
||||
html += `
|
||||
<tr class="${hasStock ? '' : 'no-stock'}">
|
||||
<td>
|
||||
<div class="geo-product">
|
||||
<span class="geo-name">${escapeHtml(item.name)}</span>
|
||||
<span class="geo-code">${displayCode} · ${item.manufacturer || ''}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="geo-spec">${item.spec || '-'}</td>
|
||||
<td class="geo-price">${item.price ? item.price.toLocaleString() + '원' : '-'}</td>
|
||||
<td class="geo-stock ${hasStock ? 'in-stock' : 'out-stock'}">${item.stock}</td>
|
||||
<td>${hasStock ? `<button class="geo-add-btn dongwon" onclick="addToCartFromWholesale('dongwon', ${idx})">담기</button>` : ''}</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
html += '</tbody></table>';
|
||||
} else {
|
||||
html += `<div class="ws-empty">📭 검색 결과 없음</div>`;
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
resultBody.innerHTML = html;
|
||||
}
|
||||
|
||||
@@ -2277,7 +2366,7 @@
|
||||
const needed = currentWholesaleItem.total_dose;
|
||||
const suggestedQty = Math.ceil(needed / specQty);
|
||||
|
||||
const supplierNames = { geoyoung: '지오영', sooin: '수인약품', baekje: '백제약품' };
|
||||
const supplierNames = { geoyoung: '지오영', sooin: '수인약품', baekje: '백제약품', dongwon: '동원약품' };
|
||||
const supplierName = supplierNames[wholesaler] || wholesaler;
|
||||
const productName = wholesaler === 'geoyoung' ? item.product_name : item.name;
|
||||
|
||||
@@ -2298,6 +2387,7 @@
|
||||
geoyoung_code: wholesaler === 'geoyoung' ? item.insurance_code : null,
|
||||
sooin_code: wholesaler === 'sooin' ? item.code : null,
|
||||
baekje_code: wholesaler === 'baekje' ? item.internal_code : null,
|
||||
dongwon_code: wholesaler === 'dongwon' ? item.internal_code : null, // 동원: 내부코드로 주문
|
||||
unit_price: unitPrice // 💰 단가 추가
|
||||
};
|
||||
|
||||
@@ -2542,6 +2632,12 @@
|
||||
.geo-add-btn.baekje:hover {
|
||||
background: #d97706;
|
||||
}
|
||||
.geo-add-btn.dongwon {
|
||||
background: #22c55e;
|
||||
}
|
||||
.geo-add-btn.dongwon:hover {
|
||||
background: #16a34a;
|
||||
}
|
||||
.geo-price {
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
font-size: 11px;
|
||||
@@ -2576,6 +2672,10 @@
|
||||
background: linear-gradient(135deg, rgba(245, 158, 11, 0.2), rgba(217, 119, 6, 0.1));
|
||||
border-left: 3px solid var(--accent-amber);
|
||||
}
|
||||
.ws-header.dongwon {
|
||||
background: linear-gradient(135deg, rgba(34, 197, 94, 0.2), rgba(22, 163, 74, 0.1));
|
||||
border-left: 3px solid #22c55e;
|
||||
}
|
||||
.ws-logo {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
@@ -2778,6 +2878,9 @@
|
||||
.multi-ws-card.baekje {
|
||||
border-left: 3px solid var(--accent-amber);
|
||||
}
|
||||
.multi-ws-card.dongwon {
|
||||
border-left: 3px solid #22c55e;
|
||||
}
|
||||
.multi-ws-card.other {
|
||||
border-left: 3px solid var(--text-muted);
|
||||
opacity: 0.7;
|
||||
@@ -3077,9 +3180,16 @@
|
||||
color: '#a855f7',
|
||||
balanceApi: '/api/sooin/balance',
|
||||
salesApi: '/api/sooin/monthly-sales'
|
||||
},
|
||||
dongwon: {
|
||||
id: 'dongwon', name: '동원약품', icon: '🏥',
|
||||
logo: '/static/img/logo_dongwon.png',
|
||||
color: '#22c55e',
|
||||
balanceApi: '/api/dongwon/balance',
|
||||
salesApi: '/api/dongwon/monthly-orders'
|
||||
}
|
||||
};
|
||||
const WHOLESALER_ORDER = ['baekje', 'geoyoung', 'sooin'];
|
||||
const WHOLESALER_ORDER = ['baekje', 'geoyoung', 'sooin', 'dongwon'];
|
||||
|
||||
async function loadBalances() {
|
||||
const content = document.getElementById('balanceContent');
|
||||
|
||||
Reference in New Issue
Block a user