feat: 입고장 관리 기능 추가
✨ 새로운 기능 - 입고장 목록 조회 (날짜/공급업체 필터링) - 입고장 상세 보기 (모달 팝업) - 입고장 삭제 (재고 미사용시만 가능) - 입고장 라인별 수정 API 📊 화면 구성 1. 입고장 목록 테이블 - 입고일, 공급업체, 품목수, 총수량, 총금액 - 상세보기, 삭제 버튼 2. 입고장 필터링 - 시작일/종료일 선택 - 공급업체별 조회 🔧 백엔드 API - GET /api/purchase-receipts - 입고장 목록 - GET /api/purchase-receipts/<id> - 입고장 상세 - PUT /api/purchase-receipts/<id>/lines/<line_id> - 라인 수정 - DELETE /api/purchase-receipts/<id> - 입고장 삭제 🛡️ 안전장치 - 이미 조제에 사용된 재고는 수정/삭제 불가 - 재고 원장에 모든 변동사항 기록 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
164
static/app.js
164
static/app.js
@@ -30,6 +30,9 @@ $(document).ready(function() {
|
||||
case 'patients':
|
||||
loadPatients();
|
||||
break;
|
||||
case 'purchase':
|
||||
loadPurchaseReceipts();
|
||||
break;
|
||||
case 'formulas':
|
||||
loadFormulas();
|
||||
break;
|
||||
@@ -490,6 +493,151 @@ $(document).ready(function() {
|
||||
});
|
||||
}
|
||||
|
||||
// 입고장 목록 로드
|
||||
function loadPurchaseReceipts() {
|
||||
const startDate = $('#purchaseStartDate').val();
|
||||
const endDate = $('#purchaseEndDate').val();
|
||||
const supplierId = $('#purchaseSupplier').val();
|
||||
|
||||
let url = '/api/purchase-receipts?';
|
||||
if (startDate) url += `start_date=${startDate}&`;
|
||||
if (endDate) url += `end_date=${endDate}&`;
|
||||
if (supplierId) url += `supplier_id=${supplierId}`;
|
||||
|
||||
$.get(url, function(response) {
|
||||
if (response.success) {
|
||||
const tbody = $('#purchaseReceiptsList');
|
||||
tbody.empty();
|
||||
|
||||
if (response.data.length === 0) {
|
||||
tbody.append('<tr><td colspan="7" class="text-center">입고장이 없습니다.</td></tr>');
|
||||
return;
|
||||
}
|
||||
|
||||
response.data.forEach(receipt => {
|
||||
tbody.append(`
|
||||
<tr>
|
||||
<td>${receipt.receipt_date}</td>
|
||||
<td>${receipt.supplier_name}</td>
|
||||
<td>${receipt.line_count}개</td>
|
||||
<td>${receipt.total_quantity ? receipt.total_quantity.toLocaleString() + 'g' : '-'}</td>
|
||||
<td>${receipt.total_amount ? formatCurrency(receipt.total_amount) : '-'}</td>
|
||||
<td>${receipt.source_file || '-'}</td>
|
||||
<td>
|
||||
<button class="btn btn-sm btn-outline-info view-receipt" data-id="${receipt.receipt_id}">
|
||||
<i class="bi bi-eye"></i> 상세
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger delete-receipt" data-id="${receipt.receipt_id}">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
|
||||
// 이벤트 바인딩
|
||||
$('.view-receipt').on('click', function() {
|
||||
const receiptId = $(this).data('id');
|
||||
viewReceiptDetail(receiptId);
|
||||
});
|
||||
|
||||
$('.delete-receipt').on('click', function() {
|
||||
const receiptId = $(this).data('id');
|
||||
if (confirm('정말 이 입고장을 삭제하시겠습니까? 사용되지 않은 재고만 삭제 가능합니다.')) {
|
||||
deleteReceipt(receiptId);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 입고장 상세 보기
|
||||
function viewReceiptDetail(receiptId) {
|
||||
$.get(`/api/purchase-receipts/${receiptId}`, function(response) {
|
||||
if (response.success) {
|
||||
const data = response.data;
|
||||
let linesHtml = '';
|
||||
|
||||
data.lines.forEach(line => {
|
||||
linesHtml += `
|
||||
<tr>
|
||||
<td>${line.herb_name}</td>
|
||||
<td>${line.insurance_code || '-'}</td>
|
||||
<td>${line.origin_country || '-'}</td>
|
||||
<td>${line.quantity_g}g</td>
|
||||
<td>${formatCurrency(line.unit_price_per_g)}</td>
|
||||
<td>${formatCurrency(line.line_total)}</td>
|
||||
<td>${line.current_stock}g</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
const modalHtml = `
|
||||
<div class="modal fade" id="receiptDetailModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">입고장 상세</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<strong>입고일:</strong> ${data.receipt_date}<br>
|
||||
<strong>공급업체:</strong> ${data.supplier_name}<br>
|
||||
<strong>총 금액:</strong> ${formatCurrency(data.total_amount)}
|
||||
</div>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>약재명</th>
|
||||
<th>보험코드</th>
|
||||
<th>원산지</th>
|
||||
<th>수량</th>
|
||||
<th>단가</th>
|
||||
<th>금액</th>
|
||||
<th>현재고</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${linesHtml}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// 기존 모달 제거
|
||||
$('#receiptDetailModal').remove();
|
||||
$('body').append(modalHtml);
|
||||
$('#receiptDetailModal').modal('show');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 입고장 삭제
|
||||
function deleteReceipt(receiptId) {
|
||||
$.ajax({
|
||||
url: `/api/purchase-receipts/${receiptId}`,
|
||||
method: 'DELETE',
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert(response.message);
|
||||
loadPurchaseReceipts();
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
alert('오류: ' + xhr.responseJSON.error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 입고장 조회 버튼
|
||||
$('#searchPurchaseBtn').on('click', function() {
|
||||
loadPurchaseReceipts();
|
||||
});
|
||||
|
||||
// 입고장 업로드
|
||||
$('#purchaseUploadForm').on('submit', function(e) {
|
||||
e.preventDefault();
|
||||
@@ -514,12 +662,28 @@ $(document).ready(function() {
|
||||
contentType: false,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
let summaryHtml = '';
|
||||
if (response.summary) {
|
||||
summaryHtml = `<br>
|
||||
<small>
|
||||
형식: ${response.summary.format}<br>
|
||||
처리: ${response.summary.processed_rows}개 라인<br>
|
||||
품목: ${response.summary.total_items}종<br>
|
||||
수량: ${response.summary.total_quantity}<br>
|
||||
금액: ${response.summary.total_amount}
|
||||
</small>`;
|
||||
}
|
||||
|
||||
$('#uploadResult').html(
|
||||
`<div class="alert alert-success">
|
||||
<i class="bi bi-check-circle"></i> ${response.message}
|
||||
${summaryHtml}
|
||||
</div>`
|
||||
);
|
||||
$('#purchaseUploadForm')[0].reset();
|
||||
|
||||
// 입고장 목록 새로고침
|
||||
loadPurchaseReceipts();
|
||||
}
|
||||
},
|
||||
error: function(xhr) {
|
||||
|
||||
Reference in New Issue
Block a user