feat: 재고 보정 및 보정 내역 조회 기능 추가
- 재고 보정 모달 UI 추가 (약재, 로트, 수량 관리) - 재고 보정 내역 조회 모달 추가 - 재고 보정 상세 조회 모달 추가 - 자동 델타 계산 기능 (보정 전/후 비교) - 로트별 재고 선택 및 원산지별 그룹화 - 보정 유형: 감모/손실, 발견, 재고조사, 파손, 유통기한 경과 - API 데이터 형식 수정 (items → details) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
b58e46f8fd
commit
724af5000a
360
static/app.js
360
static/app.js
@ -1467,6 +1467,366 @@ $(document).ready(function() {
|
|||||||
applyLedgerFilters();
|
applyLedgerFilters();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ==================== 재고 보정 ====================
|
||||||
|
|
||||||
|
// 재고 보정 모달 열기
|
||||||
|
$('#showStockAdjustmentBtn').on('click', function() {
|
||||||
|
// 현재 날짜 설정
|
||||||
|
$('#adjustmentDate').val(new Date().toISOString().split('T')[0]);
|
||||||
|
$('#adjustmentItemsList').empty();
|
||||||
|
$('#stockAdjustmentForm')[0].reset();
|
||||||
|
$('#stockAdjustmentModal').modal('show');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 재고 보정 내역 모달 열기
|
||||||
|
$('#showAdjustmentHistoryBtn').on('click', function() {
|
||||||
|
loadAdjustmentHistory();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 재고 보정 내역 로드
|
||||||
|
function loadAdjustmentHistory() {
|
||||||
|
$.get('/api/stock-adjustments', function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
const tbody = $('#adjustmentHistoryList');
|
||||||
|
tbody.empty();
|
||||||
|
|
||||||
|
if (response.data.length === 0) {
|
||||||
|
tbody.append(`
|
||||||
|
<tr>
|
||||||
|
<td colspan="7" class="text-center text-muted">보정 내역이 없습니다.</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
} else {
|
||||||
|
response.data.forEach(adj => {
|
||||||
|
// 보정 유형 한글 변환
|
||||||
|
let typeLabel = '';
|
||||||
|
switch(adj.adjustment_type) {
|
||||||
|
case 'LOSS': typeLabel = '감모/손실'; break;
|
||||||
|
case 'FOUND': typeLabel = '발견'; break;
|
||||||
|
case 'RECOUNT': typeLabel = '재고조사'; break;
|
||||||
|
case 'DAMAGE': typeLabel = '파손'; break;
|
||||||
|
case 'EXPIRE': typeLabel = '유통기한 경과'; break;
|
||||||
|
default: typeLabel = adj.adjustment_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody.append(`
|
||||||
|
<tr>
|
||||||
|
<td>${adj.adjustment_date}</td>
|
||||||
|
<td><code>${adj.adjustment_no}</code></td>
|
||||||
|
<td><span class="badge bg-warning">${typeLabel}</span></td>
|
||||||
|
<td>${adj.detail_count || 0}개</td>
|
||||||
|
<td>${adj.created_by || '-'}</td>
|
||||||
|
<td>${adj.notes || '-'}</td>
|
||||||
|
<td>
|
||||||
|
<button class="btn btn-sm btn-outline-info view-adjustment-detail"
|
||||||
|
data-id="${adj.adjustment_id}">
|
||||||
|
<i class="bi bi-eye"></i> 상세
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 상세보기 버튼 이벤트
|
||||||
|
$('.view-adjustment-detail').on('click', function() {
|
||||||
|
const adjustmentId = $(this).data('id');
|
||||||
|
viewAdjustmentDetail(adjustmentId);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#adjustmentHistoryModal').modal('show');
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
alert('보정 내역을 불러오는데 실패했습니다.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 재고 보정 상세 조회
|
||||||
|
function viewAdjustmentDetail(adjustmentId) {
|
||||||
|
$.get(`/api/stock-adjustments/${adjustmentId}`, function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
// 보정 정보 표시
|
||||||
|
$('#detailAdjustmentNo').text(data.adjustment_no);
|
||||||
|
$('#detailAdjustmentDate').text(data.adjustment_date);
|
||||||
|
|
||||||
|
// 보정 유형 한글 변환
|
||||||
|
let typeLabel = '';
|
||||||
|
switch(data.adjustment_type) {
|
||||||
|
case 'LOSS': typeLabel = '감모/손실'; break;
|
||||||
|
case 'FOUND': typeLabel = '발견'; break;
|
||||||
|
case 'RECOUNT': typeLabel = '재고조사'; break;
|
||||||
|
case 'DAMAGE': typeLabel = '파손'; break;
|
||||||
|
case 'EXPIRE': typeLabel = '유통기한 경과'; break;
|
||||||
|
default: typeLabel = data.adjustment_type;
|
||||||
|
}
|
||||||
|
$('#detailAdjustmentType').html(`<span class="badge bg-warning">${typeLabel}</span>`);
|
||||||
|
$('#detailAdjustmentCreatedBy').text(data.created_by || '-');
|
||||||
|
$('#detailAdjustmentNotes').text(data.notes || '-');
|
||||||
|
|
||||||
|
// 보정 상세 항목 표시
|
||||||
|
const itemsBody = $('#detailAdjustmentItems');
|
||||||
|
itemsBody.empty();
|
||||||
|
|
||||||
|
if (data.details && data.details.length > 0) {
|
||||||
|
data.details.forEach(item => {
|
||||||
|
const delta = item.quantity_delta;
|
||||||
|
let deltaHtml = '';
|
||||||
|
if (delta > 0) {
|
||||||
|
deltaHtml = `<span class="text-success">+${delta.toFixed(1)}g</span>`;
|
||||||
|
} else if (delta < 0) {
|
||||||
|
deltaHtml = `<span class="text-danger">${delta.toFixed(1)}g</span>`;
|
||||||
|
} else {
|
||||||
|
deltaHtml = '<span class="text-muted">0g</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsBody.append(`
|
||||||
|
<tr>
|
||||||
|
<td>${item.herb_name}</td>
|
||||||
|
<td>${item.insurance_code || '-'}</td>
|
||||||
|
<td>${item.origin_country || '-'}</td>
|
||||||
|
<td>#${item.lot_id}</td>
|
||||||
|
<td>${item.quantity_before.toFixed(1)}g</td>
|
||||||
|
<td>${item.quantity_after.toFixed(1)}g</td>
|
||||||
|
<td>${deltaHtml}</td>
|
||||||
|
<td>${item.reason || '-'}</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 보정 상세 모달 표시
|
||||||
|
$('#adjustmentDetailModal').modal('show');
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
alert('보정 상세 정보를 불러오는데 실패했습니다.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 보정 대상 약재 추가
|
||||||
|
let adjustmentItemCount = 0;
|
||||||
|
$('#addAdjustmentItemBtn').on('click', function() {
|
||||||
|
addAdjustmentItemRow();
|
||||||
|
});
|
||||||
|
|
||||||
|
function addAdjustmentItemRow() {
|
||||||
|
adjustmentItemCount++;
|
||||||
|
const rowId = `adj-item-${adjustmentItemCount}`;
|
||||||
|
|
||||||
|
const newRow = $(`
|
||||||
|
<tr data-row-id="${rowId}">
|
||||||
|
<td>
|
||||||
|
<select class="form-select form-select-sm adj-herb-select" required>
|
||||||
|
<option value="">약재 선택</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<select class="form-select form-select-sm adj-lot-select" disabled required>
|
||||||
|
<option value="">약재 먼저 선택</option>
|
||||||
|
</select>
|
||||||
|
</td>
|
||||||
|
<td class="before-qty text-end">-</td>
|
||||||
|
<td>
|
||||||
|
<input type="number" class="form-control form-control-sm after-qty-input"
|
||||||
|
min="0" step="0.1" placeholder="0.0" required>
|
||||||
|
</td>
|
||||||
|
<td class="delta-qty text-end">-</td>
|
||||||
|
<td>
|
||||||
|
<input type="text" class="form-control form-control-sm reason-input"
|
||||||
|
placeholder="사유">
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-sm btn-outline-danger remove-adj-item">
|
||||||
|
<i class="bi bi-x"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`);
|
||||||
|
|
||||||
|
$('#adjustmentItemsList').append(newRow);
|
||||||
|
|
||||||
|
// 약재 목록 로드
|
||||||
|
loadHerbsForSelect(newRow.find('.adj-herb-select'));
|
||||||
|
|
||||||
|
// 약재 선택 이벤트
|
||||||
|
newRow.find('.adj-herb-select').on('change', function() {
|
||||||
|
const herbId = $(this).val();
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
|
||||||
|
if (herbId) {
|
||||||
|
loadLotsForAdjustment(herbId, row);
|
||||||
|
} else {
|
||||||
|
row.find('.adj-lot-select').empty().append('<option value="">약재 먼저 선택</option>').prop('disabled', true);
|
||||||
|
row.find('.before-qty').text('-');
|
||||||
|
row.find('.after-qty-input').val('');
|
||||||
|
row.find('.delta-qty').text('-');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 로트 선택 이벤트
|
||||||
|
newRow.find('.adj-lot-select').on('change', function() {
|
||||||
|
const selectedOption = $(this).find('option:selected');
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
|
||||||
|
if (selectedOption.val()) {
|
||||||
|
const beforeQty = parseFloat(selectedOption.data('qty')) || 0;
|
||||||
|
row.find('.before-qty').text(beforeQty.toFixed(1) + 'g');
|
||||||
|
row.data('before-qty', beforeQty);
|
||||||
|
|
||||||
|
// 기존 변경후 값이 있으면 델타 재계산
|
||||||
|
const afterQty = parseFloat(row.find('.after-qty-input').val());
|
||||||
|
if (!isNaN(afterQty)) {
|
||||||
|
updateDelta(row, beforeQty, afterQty);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row.find('.before-qty').text('-');
|
||||||
|
row.find('.after-qty-input').val('');
|
||||||
|
row.find('.delta-qty').text('-');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 변경후 수량 입력 이벤트
|
||||||
|
newRow.find('.after-qty-input').on('input', function() {
|
||||||
|
const row = $(this).closest('tr');
|
||||||
|
const beforeQty = row.data('before-qty') || 0;
|
||||||
|
const afterQty = parseFloat($(this).val()) || 0;
|
||||||
|
|
||||||
|
updateDelta(row, beforeQty, afterQty);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 삭제 버튼
|
||||||
|
newRow.find('.remove-adj-item').on('click', function() {
|
||||||
|
$(this).closest('tr').remove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 약재별 로트 목록 로드
|
||||||
|
function loadLotsForAdjustment(herbId, row) {
|
||||||
|
$.get(`/api/inventory/detail/${herbId}`, function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
const lotSelect = row.find('.adj-lot-select');
|
||||||
|
lotSelect.empty();
|
||||||
|
lotSelect.append('<option value="">로트/원산지 선택</option>');
|
||||||
|
|
||||||
|
const data = response.data;
|
||||||
|
|
||||||
|
// 원산지별로 로트 표시
|
||||||
|
data.origins.forEach(origin => {
|
||||||
|
const optgroup = $(`<optgroup label="${origin.origin_country}">`);
|
||||||
|
|
||||||
|
origin.lots.forEach(lot => {
|
||||||
|
optgroup.append(`
|
||||||
|
<option value="${lot.lot_id}"
|
||||||
|
data-qty="${lot.quantity_onhand}"
|
||||||
|
data-origin="${origin.origin_country}">
|
||||||
|
로트#${lot.lot_id} - ${lot.quantity_onhand.toFixed(1)}g (${lot.received_date})
|
||||||
|
</option>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
lotSelect.append(optgroup);
|
||||||
|
});
|
||||||
|
|
||||||
|
lotSelect.prop('disabled', false);
|
||||||
|
}
|
||||||
|
}).fail(function() {
|
||||||
|
alert('재고 정보를 불러오는데 실패했습니다.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 델타 계산 및 표시
|
||||||
|
function updateDelta(row, beforeQty, afterQty) {
|
||||||
|
const delta = afterQty - beforeQty;
|
||||||
|
const deltaElement = row.find('.delta-qty');
|
||||||
|
|
||||||
|
if (delta > 0) {
|
||||||
|
deltaElement.html(`<span class="text-success">+${delta.toFixed(1)}g</span>`);
|
||||||
|
} else if (delta < 0) {
|
||||||
|
deltaElement.html(`<span class="text-danger">${delta.toFixed(1)}g</span>`);
|
||||||
|
} else {
|
||||||
|
deltaElement.html('<span class="text-muted">0g</span>');
|
||||||
|
}
|
||||||
|
|
||||||
|
row.data('delta', delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 재고 보정 저장 버튼
|
||||||
|
$('#saveAdjustmentBtn').on('click', function() {
|
||||||
|
saveStockAdjustment();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 재고 보정 저장
|
||||||
|
$('#stockAdjustmentForm').on('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
saveStockAdjustment();
|
||||||
|
});
|
||||||
|
|
||||||
|
function saveStockAdjustment() {
|
||||||
|
const items = [];
|
||||||
|
let hasError = false;
|
||||||
|
|
||||||
|
$('#adjustmentItemsList tr').each(function() {
|
||||||
|
const herbId = $(this).find('.adj-herb-select').val();
|
||||||
|
const lotId = $(this).find('.adj-lot-select').val();
|
||||||
|
const beforeQty = $(this).data('before-qty');
|
||||||
|
const afterQty = parseFloat($(this).find('.after-qty-input').val());
|
||||||
|
const delta = $(this).data('delta');
|
||||||
|
const reason = $(this).find('.reason-input').val();
|
||||||
|
|
||||||
|
if (!herbId || !lotId) {
|
||||||
|
hasError = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({
|
||||||
|
herb_item_id: parseInt(herbId),
|
||||||
|
lot_id: parseInt(lotId),
|
||||||
|
quantity_before: beforeQty,
|
||||||
|
quantity_after: afterQty,
|
||||||
|
quantity_delta: delta,
|
||||||
|
reason: reason
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasError) {
|
||||||
|
alert('모든 항목의 약재와 로트를 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (items.length === 0) {
|
||||||
|
alert('보정할 항목을 추가해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const adjustmentData = {
|
||||||
|
adjustment_date: $('#adjustmentDate').val(),
|
||||||
|
adjustment_type: $('#adjustmentType').val(),
|
||||||
|
created_by: $('#adjustmentCreatedBy').val() || 'SYSTEM',
|
||||||
|
notes: $('#adjustmentNotes').val(),
|
||||||
|
details: items // API expects 'details', not 'items'
|
||||||
|
};
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: '/api/stock-adjustments',
|
||||||
|
method: 'POST',
|
||||||
|
contentType: 'application/json',
|
||||||
|
data: JSON.stringify(adjustmentData),
|
||||||
|
success: function(response) {
|
||||||
|
if (response.success) {
|
||||||
|
alert(`재고 보정이 완료되었습니다.\n보정번호: ${response.adjustment_no}\n항목 수: ${items.length}개`);
|
||||||
|
$('#stockAdjustmentModal').modal('hide');
|
||||||
|
|
||||||
|
// 재고 목록 새로고침
|
||||||
|
loadInventory();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
alert('오류: ' + (xhr.responseJSON?.error || '재고 보정 실패'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function formatCurrency(amount) {
|
function formatCurrency(amount) {
|
||||||
if (amount === null || amount === undefined) return '0원';
|
if (amount === null || amount === undefined) return '0원';
|
||||||
return new Intl.NumberFormat('ko-KR', {
|
return new Intl.NumberFormat('ko-KR', {
|
||||||
|
|||||||
@ -589,6 +589,9 @@
|
|||||||
<button class="btn btn-warning me-2" id="showStockAdjustmentBtn">
|
<button class="btn btn-warning me-2" id="showStockAdjustmentBtn">
|
||||||
<i class="bi bi-sliders"></i> 재고 보정
|
<i class="bi bi-sliders"></i> 재고 보정
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-outline-warning me-2" id="showAdjustmentHistoryBtn">
|
||||||
|
<i class="bi bi-clock-history"></i> 보정 내역
|
||||||
|
</button>
|
||||||
<button class="btn btn-outline-info" id="showStockLedgerBtn">
|
<button class="btn btn-outline-info" id="showStockLedgerBtn">
|
||||||
<i class="bi bi-journal-text"></i> 입출고 원장
|
<i class="bi bi-journal-text"></i> 입출고 원장
|
||||||
</button>
|
</button>
|
||||||
@ -698,6 +701,200 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 재고 보정 모달 -->
|
||||||
|
<div class="modal fade" id="stockAdjustmentModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-xl">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-warning text-dark">
|
||||||
|
<h5 class="modal-title"><i class="bi bi-sliders"></i> 재고 보정</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<form id="stockAdjustmentForm">
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">보정일자 *</label>
|
||||||
|
<input type="date" class="form-control" id="adjustmentDate" required>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">보정 유형 *</label>
|
||||||
|
<select class="form-control" id="adjustmentType" required>
|
||||||
|
<option value="">선택하세요</option>
|
||||||
|
<option value="LOSS">감모/손실</option>
|
||||||
|
<option value="FOUND">발견</option>
|
||||||
|
<option value="RECOUNT">재고조사</option>
|
||||||
|
<option value="DAMAGE">파손</option>
|
||||||
|
<option value="EXPIRE">유통기한 경과</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-4">
|
||||||
|
<label class="form-label">담당자</label>
|
||||||
|
<input type="text" class="form-control" id="adjustmentCreatedBy" placeholder="담당자 이름">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<label class="form-label">비고</label>
|
||||||
|
<textarea class="form-control" id="adjustmentNotes" rows="2" placeholder="보정 사유를 입력하세요"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h6><i class="bi bi-list-check"></i> 보정 대상 약재</h6>
|
||||||
|
<button type="button" class="btn btn-sm btn-primary" id="addAdjustmentItemBtn">
|
||||||
|
<i class="bi bi-plus-circle"></i> 약재 추가
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th width="200">약재명</th>
|
||||||
|
<th width="250">로트/원산지</th>
|
||||||
|
<th width="100">보정 전 재고</th>
|
||||||
|
<th width="100">보정 후 재고</th>
|
||||||
|
<th width="80">증감량</th>
|
||||||
|
<th>보정 사유</th>
|
||||||
|
<th width="60">작업</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="adjustmentItemsList">
|
||||||
|
<!-- Dynamic content -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="alert alert-info mt-3">
|
||||||
|
<i class="bi bi-info-circle"></i>
|
||||||
|
<strong>안내:</strong> 보정 전 재고는 현재 시스템 재고가 자동으로 표시됩니다.
|
||||||
|
실사 재고를 "보정 후 재고"에 입력하면 증감량이 자동 계산됩니다.
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">취소</button>
|
||||||
|
<button type="button" class="btn btn-warning" id="saveAdjustmentBtn">
|
||||||
|
<i class="bi bi-check-circle"></i> 보정 실행
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 재고 보정 내역 모달 -->
|
||||||
|
<div class="modal fade" id="adjustmentHistoryModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-xl">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-warning text-dark">
|
||||||
|
<h5 class="modal-title"><i class="bi bi-clock-history"></i> 재고 보정 내역</h5>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="table-dark">
|
||||||
|
<tr>
|
||||||
|
<th width="120">보정일자</th>
|
||||||
|
<th width="150">보정번호</th>
|
||||||
|
<th width="100">보정 유형</th>
|
||||||
|
<th width="80">항목 수</th>
|
||||||
|
<th width="100">담당자</th>
|
||||||
|
<th>비고</th>
|
||||||
|
<th width="120">작업</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="adjustmentHistoryList">
|
||||||
|
<!-- Dynamic content -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 재고 보정 상세 모달 -->
|
||||||
|
<div class="modal fade" id="adjustmentDetailModal" tabindex="-1">
|
||||||
|
<div class="modal-dialog modal-xl">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header bg-info text-white">
|
||||||
|
<h5 class="modal-title"><i class="bi bi-file-text"></i> 재고 보정 상세</h5>
|
||||||
|
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<!-- 보정 헤더 정보 -->
|
||||||
|
<div class="row mb-4">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="card-title">보정 정보</h6>
|
||||||
|
<table class="table table-sm table-borderless">
|
||||||
|
<tr>
|
||||||
|
<th width="100">보정번호:</th>
|
||||||
|
<td id="detailAdjustmentNo"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>보정일자:</th>
|
||||||
|
<td id="detailAdjustmentDate"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>보정 유형:</th>
|
||||||
|
<td id="detailAdjustmentType"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>담당자:</th>
|
||||||
|
<td id="detailAdjustmentCreatedBy"></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h6 class="card-title">비고</h6>
|
||||||
|
<p id="detailAdjustmentNotes" class="mb-0"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 보정 상세 항목 -->
|
||||||
|
<h6><i class="bi bi-list-check"></i> 보정 상세 내역</h6>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-sm table-bordered">
|
||||||
|
<thead class="table-light">
|
||||||
|
<tr>
|
||||||
|
<th>약재명</th>
|
||||||
|
<th>보험코드</th>
|
||||||
|
<th>원산지</th>
|
||||||
|
<th>로트ID</th>
|
||||||
|
<th>보정 전</th>
|
||||||
|
<th>보정 후</th>
|
||||||
|
<th>증감량</th>
|
||||||
|
<th>사유</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="detailAdjustmentItems">
|
||||||
|
<!-- Dynamic content -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Herbs Page -->
|
<!-- Herbs Page -->
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user