优化采购需求
This commit is contained in:
parent
50f8a07b1b
commit
23cf2ed453
@ -861,11 +861,64 @@ input[type="date"]::-webkit-calendar-picker-indicator:hover{
|
||||
.toast.show{opacity:1}
|
||||
.overlay{position:fixed;inset:0;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center}
|
||||
.overlay.hidden{display:none}
|
||||
.loader{display:flex;gap:8px}
|
||||
.loader .dot{width:10px;height:10px;border-radius:999px;background:var(--primary);animation:bounce .9s ease infinite}
|
||||
.loader .dot:nth-child(2){animation-delay:.15s}
|
||||
.loader .dot:nth-child(3){animation-delay:.3s}
|
||||
@keyframes bounce{0%,100%{transform:translateY(0);opacity:.7}50%{transform:translateY(-8px);opacity:1}}
|
||||
|
||||
/* 芯片电路板加载动画 */
|
||||
.main-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
height: 100%;
|
||||
max-height: 250px;
|
||||
}
|
||||
|
||||
.trace-bg {
|
||||
stroke: #333;
|
||||
stroke-width: 1.8;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.trace-flow {
|
||||
stroke-width: 1.8;
|
||||
fill: none;
|
||||
stroke-dasharray: 40 400;
|
||||
stroke-dashoffset: 438;
|
||||
filter: drop-shadow(0 0 6px currentColor);
|
||||
animation: flow 3s cubic-bezier(0.5, 0, 0.9, 1) infinite;
|
||||
}
|
||||
|
||||
.yellow {
|
||||
stroke: #ffea00;
|
||||
color: #ffea00;
|
||||
}
|
||||
.blue {
|
||||
stroke: #00ccff;
|
||||
color: #00ccff;
|
||||
}
|
||||
.green {
|
||||
stroke: #00ff15;
|
||||
color: #00ff15;
|
||||
}
|
||||
.purple {
|
||||
stroke: #9900ff;
|
||||
color: #9900ff;
|
||||
}
|
||||
.red {
|
||||
stroke: #ff3300;
|
||||
color: #ff3300;
|
||||
}
|
||||
|
||||
@keyframes flow {
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.three-body {
|
||||
--uib-size: 35px;
|
||||
@ -969,65 +1022,7 @@ input[type="date"]::-webkit-calendar-picker-indicator:hover{
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
position: relative;
|
||||
perspective: 800px;
|
||||
animation: spinner-y0fdc1 2s infinite ease;
|
||||
transform-style: preserve-3d;
|
||||
}
|
||||
|
||||
.spinner > div {
|
||||
background-color: rgba(0,77,255,0.2);
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
border: 2px solid #004dff;
|
||||
}
|
||||
|
||||
.spinner div:nth-of-type(1) {
|
||||
transform: translateZ(-22px) rotateY(180deg);
|
||||
}
|
||||
|
||||
.spinner div:nth-of-type(2) {
|
||||
transform: rotateY(-270deg) translateX(50%);
|
||||
transform-origin: top right;
|
||||
}
|
||||
|
||||
.spinner div:nth-of-type(3) {
|
||||
transform: rotateY(270deg) translateX(-50%);
|
||||
transform-origin: center left;
|
||||
}
|
||||
|
||||
.spinner div:nth-of-type(4) {
|
||||
transform: rotateX(90deg) translateY(-50%);
|
||||
transform-origin: top center;
|
||||
}
|
||||
|
||||
.spinner div:nth-of-type(5) {
|
||||
transform: rotateX(-90deg) translateY(50%);
|
||||
transform-origin: bottom center;
|
||||
}
|
||||
|
||||
.spinner div:nth-of-type(6) {
|
||||
transform: translateZ(22px);
|
||||
}
|
||||
|
||||
@keyframes spinner-y0fdc1 {
|
||||
0% {
|
||||
transform: rotate(45deg) rotateX(-25deg) rotateY(25deg);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(45deg) rotateX(-385deg) rotateY(25deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(45deg) rotateX(-385deg) rotateY(385deg);
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter{opacity:0;transform:translateY(8px)}
|
||||
.fade-enter-active{transition:opacity .25s ease-out,transform .25s ease-out;opacity:1;transform:translateY(0)}
|
||||
.error{color:#ffb4b4}
|
||||
|
||||
@ -279,13 +279,159 @@
|
||||
</div>
|
||||
<div id="toast" class="toast"></div>
|
||||
<div id="overlay" class="overlay hidden">
|
||||
<div class="spinner">
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div></div>
|
||||
<div class="main-container">
|
||||
<div class="loader">
|
||||
<svg viewBox="0 0 800 500" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<linearGradient id="chipGradient" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#2d2d2d"></stop>
|
||||
<stop offset="100%" stop-color="#0f0f0f"></stop>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="textGradient" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#eeeeee"></stop>
|
||||
<stop offset="100%" stop-color="#888888"></stop>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="pinGradient" x1="1" y1="0" x2="0" y2="0">
|
||||
<stop offset="0%" stop-color="#bbbbbb"></stop>
|
||||
<stop offset="50%" stop-color="#888888"></stop>
|
||||
<stop offset="100%" stop-color="#555555"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<g id="traces">
|
||||
<path d="M100 100 H200 V210 H326" class="trace-bg"></path>
|
||||
<path d="M100 100 H200 V210 H326" class="trace-flow purple"></path>
|
||||
|
||||
<path d="M80 180 H180 V230 H326" class="trace-bg"></path>
|
||||
<path d="M80 180 H180 V230 H326" class="trace-flow blue"></path>
|
||||
|
||||
<path d="M60 260 H150 V250 H326" class="trace-bg"></path>
|
||||
<path d="M60 260 H150 V250 H326" class="trace-flow yellow"></path>
|
||||
|
||||
<path d="M100 350 H200 V270 H326" class="trace-bg"></path>
|
||||
<path d="M100 350 H200 V270 H326" class="trace-flow green"></path>
|
||||
|
||||
<path d="M700 90 H560 V210 H474" class="trace-bg"></path>
|
||||
<path d="M700 90 H560 V210 H474" class="trace-flow blue"></path>
|
||||
|
||||
<path d="M740 160 H580 V230 H474" class="trace-bg"></path>
|
||||
<path d="M740 160 H580 V230 H474" class="trace-flow green"></path>
|
||||
|
||||
<path d="M720 250 H590 V250 H474" class="trace-bg"></path>
|
||||
<path d="M720 250 H590 V250 H474" class="trace-flow red"></path>
|
||||
|
||||
<path d="M680 340 H570 V270 H474" class="trace-bg"></path>
|
||||
<path d="M680 340 H570 V270 H474" class="trace-flow yellow"></path>
|
||||
</g>
|
||||
|
||||
<rect
|
||||
x="330"
|
||||
y="190"
|
||||
width="140"
|
||||
height="100"
|
||||
rx="20"
|
||||
ry="20"
|
||||
fill="url(#chipGradient)"
|
||||
stroke="#222"
|
||||
stroke-width="3"
|
||||
filter="drop-shadow(0 0 6px rgba(0,0,0,0.8))"
|
||||
></rect>
|
||||
|
||||
<g>
|
||||
<rect
|
||||
x="322"
|
||||
y="205"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
<rect
|
||||
x="322"
|
||||
y="225"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
<rect
|
||||
x="322"
|
||||
y="245"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
<rect
|
||||
x="322"
|
||||
y="265"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
</g>
|
||||
|
||||
<g>
|
||||
<rect
|
||||
x="470"
|
||||
y="205"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
<rect
|
||||
x="470"
|
||||
y="225"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
<rect
|
||||
x="470"
|
||||
y="245"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
<rect
|
||||
x="470"
|
||||
y="265"
|
||||
width="8"
|
||||
height="10"
|
||||
fill="url(#pinGradient)"
|
||||
rx="2"
|
||||
></rect>
|
||||
</g>
|
||||
|
||||
<text
|
||||
x="400"
|
||||
y="240"
|
||||
font-family="Arial, sans-serif"
|
||||
font-size="22"
|
||||
fill="url(#textGradient)"
|
||||
text-anchor="middle"
|
||||
alignment-baseline="middle"
|
||||
>
|
||||
Loading
|
||||
</text>
|
||||
|
||||
<circle cx="100" cy="100" r="5" fill="black"></circle>
|
||||
<circle cx="80" cy="180" r="5" fill="black"></circle>
|
||||
<circle cx="60" cy="260" r="5" fill="black"></circle>
|
||||
<circle cx="100" cy="350" r="5" fill="black"></circle>
|
||||
|
||||
<circle cx="700" cy="90" r="5" fill="black"></circle>
|
||||
<circle cx="740" cy="160" r="5" fill="black"></circle>
|
||||
<circle cx="720" cy="250" r="5" fill="black"></circle>
|
||||
<circle cx="680" cy="340" r="5" fill="black"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -127,15 +127,67 @@
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
#purchase-demand-page .product-tabs-wrapper {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
#purchase-demand-page .product-tab {
|
||||
border-bottom: 2px solid transparent;
|
||||
border-radius: 4px 4px 0 0;
|
||||
min-width: 100px;
|
||||
height: 51px;
|
||||
border-radius: 15px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s ease;
|
||||
background: linear-gradient(
|
||||
to bottom right,
|
||||
#2e8eff 0%,
|
||||
rgba(46, 142, 255, 0) 30%
|
||||
);
|
||||
background-color: rgba(46, 142, 255, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: none;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
#purchase-demand-page .product-tab:hover,
|
||||
#purchase-demand-page .product-tab:focus {
|
||||
background-color: rgba(46, 142, 255, 0.7);
|
||||
box-shadow: 0 0 10px rgba(46, 142, 255, 0.5);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#purchase-demand-page .product-tab.active {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
border-bottom-color: var(--primary);
|
||||
background-color: rgba(46, 142, 255, 0.9);
|
||||
box-shadow: 0 0 15px rgba(46, 142, 255, 0.7);
|
||||
}
|
||||
|
||||
#purchase-demand-page .product-tab-inner {
|
||||
width: 100%;
|
||||
height: 47px;
|
||||
border-radius: 13px;
|
||||
background-color: var(--bg);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0 20px;
|
||||
color: #66b3ff;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
text-shadow: 0 0 2px rgba(102, 179, 255, 0.5);
|
||||
}
|
||||
|
||||
[data-theme="light"] #purchase-demand-page .product-tab-inner {
|
||||
color: #0066cc;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
#purchase-demand-page .product-tab.active .product-tab-inner {
|
||||
color: #003d7a;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -153,16 +205,13 @@
|
||||
</div>
|
||||
|
||||
<div class="content-area">
|
||||
<!-- 计算说明提示 -->
|
||||
<div style="margin: 0 20px 16px 20px; padding: 8px 16px; background: linear-gradient(135deg, #e3f2fd 0%, #f3e5f5 100%); border-left: 4px solid #2196f3; border-radius: 4px; font-size: 13px; color: #424242;">
|
||||
<strong>采购需求计算公式:</strong>
|
||||
客户订单数量 × BOM单机用量 - 期初库存 = 净需求 → 按最小包装向上取整 = 实际采购数量
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 产品选择标签页 -->
|
||||
<div style="padding: 0 20px;">
|
||||
<div style="display: flex; gap: 10px; margin-bottom: 16px; border-bottom: 2px solid var(--border); padding-bottom: 10px;">
|
||||
<button class="product-tab btn btn-secondary" data-product="" onclick="PurchaseDemand.switchProduct('')">全部</button>
|
||||
<div class="product-tabs-wrapper" id="product-tabs-container">
|
||||
<button class="product-tab active" data-product="" onclick="PurchaseDemand.switchProduct('')">
|
||||
<div class="product-tab-inner">全部</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -466,6 +515,25 @@
|
||||
<option value="cancelled">已取消</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>应用范围</label>
|
||||
<div style="display: flex; gap: 20px; margin-top: 8px;">
|
||||
<label for="batch-scope-selected" style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="radio" id="batch-scope-selected" name="batch-scope" value="selected" checked style="margin-right: 8px;">
|
||||
仅当前选中的记录
|
||||
</label>
|
||||
<label for="batch-scope-all" style="display: flex; align-items: center; cursor: pointer;">
|
||||
<input type="radio" id="batch-scope-all" name="batch-scope" value="all" style="margin-right: 8px;">
|
||||
指定产品的所有记录
|
||||
</label>
|
||||
</div>
|
||||
<div id="batch-product-select-container" style="margin-top: 12px; display: none;">
|
||||
<label style="font-size: 14px; margin-bottom: 4px; display: block;">选择产品</label>
|
||||
<select id="batch-product-select" class="input" style="width: 100%;">
|
||||
<option value="">请选择产品</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>备注(可选)</label>
|
||||
<textarea id="batch-remark" class="input" rows="3" placeholder="可以为所有选中的项目添加统一的备注"></textarea>
|
||||
@ -537,14 +605,20 @@
|
||||
console.log('检查数据是否有product_code字段:', demandList.some(item => 'product_code' in item)); // 检查字段是否存在
|
||||
|
||||
// 更新标签页
|
||||
const tabsContainer = document.querySelector('.product-tab').parentElement;
|
||||
const tabsContainer = document.getElementById('product-tabs-container');
|
||||
if (!tabsContainer) return;
|
||||
|
||||
let html = '<button class="product-tab btn btn-secondary" data-product="" onclick="PurchaseDemand.switchProduct(\'\')">全部</button>';
|
||||
const productArray = Array.from(products).sort();
|
||||
|
||||
Array.from(products).sort().forEach(product => {
|
||||
let html = `<button class="product-tab ${!currentProduct ? 'active' : ''}" data-product="" onclick="PurchaseDemand.switchProduct('')">
|
||||
<div class="product-tab-inner">全部</div>
|
||||
</button>`;
|
||||
|
||||
productArray.forEach(product => {
|
||||
const isActive = product === currentProduct ? 'active' : '';
|
||||
html += `<button class="product-tab btn btn-secondary ${isActive}" data-product="${product}" onclick="PurchaseDemand.switchProduct('${product}')">${product}</button>`;
|
||||
html += `<button class="product-tab ${isActive}" data-product="${product}" onclick="PurchaseDemand.switchProduct('${product}')">
|
||||
<div class="product-tab-inner">${product}</div>
|
||||
</button>`;
|
||||
});
|
||||
|
||||
tabsContainer.innerHTML = html;
|
||||
@ -1144,22 +1218,58 @@
|
||||
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||
const selectedCount = checkboxes.length;
|
||||
|
||||
if (selectedCount === 0) {
|
||||
alert('请先选择要编辑的记录');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新选中数量显示
|
||||
document.getElementById('selected-count').textContent = selectedCount;
|
||||
|
||||
// 加载产品列表
|
||||
loadProductOptions();
|
||||
|
||||
// 重置表单
|
||||
document.getElementById('batch-status').value = '';
|
||||
document.getElementById('batch-remark').value = '';
|
||||
document.querySelector('input[name="batch-scope"][value="selected"]').checked = true;
|
||||
document.getElementById('batch-product-select-container').style.display = 'none';
|
||||
|
||||
// 添加事件监听
|
||||
document.getElementById('batch-scope-all').onchange = function() {
|
||||
document.getElementById('batch-product-select-container').style.display =
|
||||
this.checked ? 'block' : 'none';
|
||||
};
|
||||
document.getElementById('batch-scope-selected').onchange = function() {
|
||||
document.getElementById('batch-product-select-container').style.display =
|
||||
this.checked ? 'none' : 'block';
|
||||
};
|
||||
|
||||
// 显示弹窗
|
||||
document.getElementById('batch-edit-status-modal').style.display = 'flex';
|
||||
}
|
||||
|
||||
function loadProductOptions() {
|
||||
// 获取所有产品
|
||||
const products = new Set();
|
||||
demandList.forEach(item => {
|
||||
if (item.product_code) {
|
||||
products.add(item.product_code);
|
||||
}
|
||||
});
|
||||
|
||||
const productSelect = document.getElementById('batch-product-select');
|
||||
productSelect.innerHTML = '<option value="">请选择产品</option>';
|
||||
|
||||
// 添加产品选项
|
||||
Array.from(products).sort().forEach(product => {
|
||||
const option = document.createElement('option');
|
||||
option.value = product;
|
||||
option.textContent = product;
|
||||
productSelect.appendChild(option);
|
||||
});
|
||||
|
||||
// 如果当前有选中的产品,设为默认值
|
||||
if (currentProduct) {
|
||||
productSelect.value = currentProduct;
|
||||
}
|
||||
}
|
||||
|
||||
function closeBatchEditStatusModal() {
|
||||
document.getElementById('batch-edit-status-modal').style.display = 'none';
|
||||
}
|
||||
@ -1167,26 +1277,49 @@
|
||||
async function saveBatchEditStatus() {
|
||||
const status = document.getElementById('batch-status').value;
|
||||
const remark = document.getElementById('batch-remark').value.trim();
|
||||
const scope = document.querySelector('input[name="batch-scope"]:checked').value;
|
||||
|
||||
if (!status) {
|
||||
alert('请选择状态');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取选中的ID
|
||||
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||
const ids = Array.from(checkboxes).map(cb => parseInt(cb.dataset.id));
|
||||
let requestData = {
|
||||
status: status,
|
||||
remark: remark
|
||||
};
|
||||
|
||||
if (!confirm(`确定要将选中的 ${ids.length} 条记录状态更新为"${getStatusText(status)}"吗?`)) {
|
||||
let confirmMessage = '';
|
||||
|
||||
if (scope === 'all') {
|
||||
// 更新指定产品的所有记录
|
||||
const selectedProduct = document.getElementById('batch-product-select').value;
|
||||
if (!selectedProduct) {
|
||||
alert('请选择要更新的产品');
|
||||
return;
|
||||
}
|
||||
requestData.product_code = selectedProduct;
|
||||
confirmMessage = `确定要将"${selectedProduct}"的所有记录状态更新为"${getStatusText(status)}"吗?`;
|
||||
} else {
|
||||
// 仅更新选中的记录
|
||||
const checkboxes = document.querySelectorAll('.row-checkbox:checked');
|
||||
const ids = Array.from(checkboxes).map(cb => parseInt(cb.dataset.id));
|
||||
|
||||
if (ids.length === 0) {
|
||||
alert('请选择要更新的记录');
|
||||
return;
|
||||
}
|
||||
|
||||
requestData.ids = ids;
|
||||
confirmMessage = `确定要将选中的 ${ids.length} 条记录状态更新为"${getStatusText(status)}"吗?`;
|
||||
}
|
||||
|
||||
if (!confirm(confirmMessage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await API.post('/api/purchase-demand/batch-update-status', {
|
||||
ids: ids,
|
||||
status: status,
|
||||
remark: remark
|
||||
});
|
||||
const res = await API.post('/api/purchase-demand/batch-update-status', requestData);
|
||||
|
||||
if (res.ok) {
|
||||
alert(`成功更新 ${res.count} 条记录`);
|
||||
|
||||
103
server/app.py
103
server/app.py
@ -6507,16 +6507,17 @@ def delete_purchase_demand(demand_id):
|
||||
|
||||
@app.post('/api/purchase-demand/batch-update-status')
|
||||
@require_login
|
||||
@require_any_role('superadmin')
|
||||
@require_any_role('superadmin', 'admin')
|
||||
def batch_update_purchase_demand_status():
|
||||
"""批量更新采购需求状态"""
|
||||
data = request.get_json() or {}
|
||||
ids = data.get('ids', [])
|
||||
status = data.get('status', '').strip()
|
||||
remark = data.get('remark', '').strip()
|
||||
status = data.get('status')
|
||||
remark = data.get('remark', '')
|
||||
product_code = data.get('product_code', '').strip()
|
||||
|
||||
if not ids:
|
||||
return jsonify({'error': '请选择要更新的记录'}), 400
|
||||
if not ids and not product_code:
|
||||
return jsonify({'error': '请选择要更新的记录或指定产品'}), 400
|
||||
|
||||
if not status:
|
||||
return jsonify({'error': '请选择状态'}), 400
|
||||
@ -6528,9 +6529,15 @@ def batch_update_purchase_demand_status():
|
||||
c = conn.cursor()
|
||||
now = get_beijing_time()
|
||||
|
||||
# 验证ID是否存在并获取原始状态
|
||||
placeholders = ','.join(['?' for _ in ids])
|
||||
c.execute(f'SELECT id, status, material_code, material_name, actual_purchase_qty, net_demand FROM purchase_demand WHERE id IN ({placeholders})', ids)
|
||||
# 根据条件查询记录
|
||||
if product_code:
|
||||
# 按产品代码查询
|
||||
c.execute('SELECT id, status, material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock FROM purchase_demand WHERE product_code=?', (product_code,))
|
||||
else:
|
||||
# 按ID列表查询
|
||||
placeholders = ','.join(['?' for _ in ids])
|
||||
c.execute(f'SELECT id, status, material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock FROM purchase_demand WHERE id IN ({placeholders})', ids)
|
||||
|
||||
existing_records = c.fetchall()
|
||||
|
||||
if not existing_records:
|
||||
@ -6547,11 +6554,18 @@ def batch_update_purchase_demand_status():
|
||||
material_name = record['material_name']
|
||||
actual_purchase_qty = record['actual_purchase_qty']
|
||||
net_demand = record['net_demand']
|
||||
total_demand = record['total_demand']
|
||||
initial_stock = record['initial_stock']
|
||||
|
||||
# 计算之前增加的库存量:实际采购 - 净需求
|
||||
added_stock = actual_purchase_qty - net_demand
|
||||
# 根据实际采购数量计算之前的变化量
|
||||
if actual_purchase_qty > 0:
|
||||
# 如果实际采购不等于零,之前增加的库存量 = 实际采购 - 净需求
|
||||
added_stock = actual_purchase_qty - net_demand
|
||||
else:
|
||||
# 如果实际采购等于零,之前减少的库存量 = 期初库存 - 总需求
|
||||
added_stock = -(initial_stock - total_demand)
|
||||
|
||||
# 从期初库存表中减去之前增加的库存(恢复原值)
|
||||
# 从期初库存表中减去之前的变化量(恢复原值)
|
||||
c.execute('SELECT stock_qty FROM initial_stock WHERE material_code=?', (material_code,))
|
||||
stock_record = c.fetchone()
|
||||
|
||||
@ -6576,24 +6590,30 @@ def batch_update_purchase_demand_status():
|
||||
params.extend(existing_ids)
|
||||
c.execute(f'UPDATE purchase_demand SET {", ".join(updates)} WHERE id IN ({placeholders})', params)
|
||||
|
||||
# 如果状态更新为已下单,更新期初库存
|
||||
# 如果状态更新为已下单,更新期初库存(包括已经是已下单状态的情况)
|
||||
if status == 'ordered':
|
||||
for record in existing_records:
|
||||
# 只处理之前不是"已下单"状态的记录
|
||||
if record['status'] != 'ordered':
|
||||
material_code = record['material_code']
|
||||
material_name = record['material_name']
|
||||
actual_purchase_qty = record['actual_purchase_qty']
|
||||
net_demand = record['net_demand']
|
||||
|
||||
# 计算新的期初库存:实际采购 - 净需求
|
||||
# 处理所有记录(包括已经是"已下单"状态的记录)
|
||||
material_code = record['material_code']
|
||||
material_name = record['material_name']
|
||||
actual_purchase_qty = record['actual_purchase_qty']
|
||||
net_demand = record['net_demand']
|
||||
total_demand = record['total_demand']
|
||||
initial_stock = record['initial_stock']
|
||||
|
||||
# 根据实际采购数量计算新的期初库存
|
||||
if actual_purchase_qty > 0:
|
||||
# 如果实际采购不等于零,期初库存 = 实际采购 - 净需求
|
||||
new_initial_stock = actual_purchase_qty - net_demand
|
||||
|
||||
# 只更新期初库存表
|
||||
c.execute('''INSERT OR REPLACE INTO initial_stock
|
||||
(material_code, material_name, stock_qty, updated_at)
|
||||
VALUES (?, ?, ?, ?)''',
|
||||
(material_code, material_name, new_initial_stock, now))
|
||||
else:
|
||||
# 如果实际采购等于零,期初库存 = 期初库存 - 总需求
|
||||
new_initial_stock = initial_stock - total_demand
|
||||
|
||||
# 只更新期初库存表
|
||||
c.execute('''INSERT OR REPLACE INTO initial_stock
|
||||
(material_code, material_name, stock_qty, updated_at)
|
||||
VALUES (?, ?, ?, ?)''',
|
||||
(material_code, material_name, new_initial_stock, now))
|
||||
|
||||
count = c.rowcount
|
||||
conn.commit()
|
||||
@ -6881,11 +6901,18 @@ def update_purchase_demand(id):
|
||||
material_name = existing['material_name']
|
||||
actual_purchase_qty = existing['actual_purchase_qty']
|
||||
net_demand = existing['net_demand']
|
||||
total_demand = existing['total_demand']
|
||||
initial_stock = existing['initial_stock']
|
||||
|
||||
# 计算之前增加的库存量:实际采购 - 净需求
|
||||
added_stock = actual_purchase_qty - net_demand
|
||||
# 根据实际采购数量计算之前的变化量
|
||||
if actual_purchase_qty > 0:
|
||||
# 如果实际采购不等于零,之前增加的库存量 = 实际采购 - 净需求
|
||||
added_stock = actual_purchase_qty - net_demand
|
||||
else:
|
||||
# 如果实际采购等于零,之前减少的库存量 = 期初库存 - 总需求
|
||||
added_stock = -(initial_stock - total_demand)
|
||||
|
||||
# 从期初库存表中减去之前增加的库存(恢复原值)
|
||||
# 从期初库存表中减去之前的变化量(恢复原值)
|
||||
c.execute('SELECT stock_qty FROM initial_stock WHERE material_code=?', (material_code,))
|
||||
stock_record = c.fetchone()
|
||||
|
||||
@ -6903,16 +6930,22 @@ def update_purchase_demand(id):
|
||||
update_values.append(id)
|
||||
c.execute(f'UPDATE purchase_demand SET {", ".join(update_fields)} WHERE id=?', update_values)
|
||||
|
||||
# 如果状态更新为已下单,更新期初库存
|
||||
if 'status' in data and new_status == 'ordered' and old_status != 'ordered':
|
||||
# 如果状态更新为已下单,更新期初库存(包括已经是已下单状态的情况)
|
||||
if 'status' in data and new_status == 'ordered':
|
||||
# 获取更新后的记录信息
|
||||
c.execute('SELECT material_code, material_name, actual_purchase_qty, net_demand FROM purchase_demand WHERE id=?', (id,))
|
||||
c.execute('SELECT material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock FROM purchase_demand WHERE id=?', (id,))
|
||||
record = c.fetchone()
|
||||
|
||||
if record:
|
||||
material_code, material_name, actual_purchase_qty, net_demand = record
|
||||
# 计算新的期初库存:实际采购 - 净需求
|
||||
new_initial_stock = actual_purchase_qty - net_demand
|
||||
material_code, material_name, actual_purchase_qty, net_demand, total_demand, initial_stock = record
|
||||
|
||||
# 根据实际采购数量计算新的期初库存
|
||||
if actual_purchase_qty > 0:
|
||||
# 如果实际采购不等于零,期初库存 = 实际采购 - 净需求
|
||||
new_initial_stock = actual_purchase_qty - net_demand
|
||||
else:
|
||||
# 如果实际采购等于零,期初库存 = 期初库存 - 总需求
|
||||
new_initial_stock = initial_stock - total_demand
|
||||
|
||||
# 只更新期初库存表
|
||||
c.execute('''INSERT OR REPLACE INTO initial_stock
|
||||
|
||||
Loading…
Reference in New Issue
Block a user