diff --git a/routes/purchase.py b/routes/purchase.py index 6fb8914..e4264ef 100644 --- a/routes/purchase.py +++ b/routes/purchase.py @@ -2580,16 +2580,11 @@ def _optional_int(data, key, label): def _arrival_batch_quantities(data, order_type='domestic'): - """Parse quantities; packaging defective quantity may be any integer.""" + """Parse quantities; defective quantity may be any integer for all order types.""" arrival_qty, arrival_qty_filled = _optional_int(data, 'arrival_qty', '到货数量') defective_qty, defective_qty_filled = _optional_int(data, 'defective_qty', '不良品数量') if arrival_qty_filled and arrival_qty < 0: raise ValueError('到货数量不能为负数') - if order_type != 'packaging' and defective_qty_filled: - if defective_qty < 0: - raise ValueError('不良品数量不能为负数') - if defective_qty > arrival_qty: - raise ValueError('不良品数量不能大于到货数量') return arrival_qty, defective_qty, arrival_qty_filled, defective_qty_filled @@ -2817,18 +2812,10 @@ def domestic_orders_update_batch(): requested_defective = int(data.get('defective_qty')) except (TypeError, ValueError): return jsonify({"code": 400, "msg": "不良品数量必须为整数"}), 400 - if order_type != 'packaging' and requested_defective < 0: - return jsonify({"code": 400, "msg": "不良品数量不能为负数"}), 400 - effective_arrival_qty = ( - requested_qty if 'requested_qty' in locals() and data.get('arrival_qty') not in (None, '') - else int(current.get('arrival_qty') or 0) - ) - if order_type != 'packaging' and requested_defective > effective_arrival_qty: - return jsonify({"code": 400, "msg": "不良品数量不能大于到货数量"}), 400 - defective_locked = order_type != 'packaging' or current.get('defective_qty_filled') + defective_locked = current.get('defective_qty_filled') if defective_locked and requested_defective != int(current.get('defective_qty') or 0): return jsonify({"code": 400, "msg": "不良品数量保存后不允许修改"}), 400 - if order_type == 'packaging' and not current.get('defective_qty_filled'): + if not current.get('defective_qty_filled'): update_fields.extend(['defective_qty=%s', 'defective_qty_filled=1']) update_params.append(requested_defective) supplemented.append(f'不良品数量={requested_defective}') diff --git a/static/js/app.js b/static/js/app.js index e09f96a..df3b093 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -21755,7 +21755,7 @@ function showOrderDetail(encodedStr, title) { html += '
'; html += '
'; html += '
'; - var showDefectiveQty = orderType === 'packaging'; + var showDefectiveQty = true; html += ''; html += ''; html += ''; @@ -21859,7 +21859,7 @@ function showOrderDetail(encodedStr, title) { .then(function(res) { if (res.code !== 0) { var abBody = overlay.querySelector('#arrivalBatchBody'); - if (abBody) abBody.innerHTML = ''; + if (abBody) abBody.innerHTML = ''; var pmBody = overlay.querySelector('#packagingMaterialBody'); if (pmBody) pmBody.innerHTML = ''; return; @@ -21872,7 +21872,7 @@ function showOrderDetail(encodedStr, title) { var abHtml = ''; var totalQty = 0; var totalDefectiveQty = 0; - var showDefectiveQty = orderType === 'packaging'; + var showDefectiveQty = true; var batchCount = data.arrival_batches ? data.arrival_batches.length : 0; // 数据行 data.arrival_batches.forEach(function(b, idx) { @@ -21892,7 +21892,7 @@ function showOrderDetail(encodedStr, title) { abHtml += ''; abHtml += renderArrivalBatchStoredCell('date', 'batch-date', dateVal, dateFilled, allowBlankFill, '到货日期') + renderArrivalBatchStoredCell('number', 'batch-qty', qtyFilled ? qty : '', qtyFilled, allowBlankFill, '到货数量', true) + - (showDefectiveQty ? renderArrivalBatchStoredCell('number', 'batch-defective-qty', defectiveFilled ? defectiveQty : '', defectiveFilled, true, '不良品数量', false) : '') + + renderArrivalBatchStoredCell('number', 'batch-defective-qty', defectiveFilled ? defectiveQty : '', defectiveFilled, true, '不良品数量', false) + '' + ''; abHtml += ''; abHtml += ''; - if (showDefectiveQty) abHtml += ''; + abHtml += ''; abHtml += ''; abHtml += ''; abHtml += ''; @@ -21946,7 +21946,7 @@ function showOrderDetail(encodedStr, title) { .catch(function(err) { console.error('加载详情额外数据失败:', err); var abBody = overlay.querySelector('#arrivalBatchBody'); - if (abBody) abBody.innerHTML = ''; + if (abBody) abBody.innerHTML = ''; var pmBody = overlay.querySelector('#packagingMaterialBody'); if (pmBody) pmBody.innerHTML = ''; }); @@ -21996,7 +21996,7 @@ function appendArrivalBatchEditingRow(btn) { '' + '' + '' + - (orderType === 'packaging' ? '' : '') + + '' + '' + '' + renderArrivalBatchStoredCell('date', 'batch-date', date, !!(res.data && res.data.arrival_date_filled), orderType === 'packaging', '到货日期') + renderArrivalBatchStoredCell('number', 'batch-qty', qty, !!(res.data && res.data.arrival_qty_filled), orderType === 'packaging', '到货数量', true) + - (orderType === 'packaging' ? renderArrivalBatchStoredCell('number', 'batch-defective-qty', defectiveQty, !!(res.data && res.data.defective_qty_filled), true, '不良品数量', false) : '') + + renderArrivalBatchStoredCell('number', 'batch-defective-qty', defectiveQty, !!(res.data && res.data.defective_qty_filled), true, '不良品数量', false) + '' + ''; recalcArrivalUnfinished(); @@ -22153,7 +22152,6 @@ function saveArrivalBatch(btn, batchId, orderId, orderType) { var remark = tr.querySelector('.batch-remark')?.value || ''; if (qtyRaw !== '' && (!Number.isInteger(qty) || qty < 0)) { alert('到货数量必须为非负整数'); return; } if (defectiveRaw !== '' && !Number.isInteger(defectiveQty)) { alert('不良品数量必须为整数'); return; } - if (orderType !== 'packaging' && defectiveRaw !== '' && (defectiveQty < 0 || defectiveQty > (qty || 0))) { alert('不良品数量不能为负数或大于到货数量'); return; } btn.disabled = true; btn.textContent = '⋯'; fetch('/api/domestic/orders/update_batch', { @@ -22182,11 +22180,11 @@ function saveArrivalBatch(btn, batchId, orderId, orderType) { if (orderType === 'packaging') { var dateCell = dd && dd.closest('td'); var qtyCell = dq && dq.closest('td'); - var defectiveCell = df && df.closest('td'); if (dateCell && res.data && res.data.arrival_date_filled) dateCell.outerHTML = renderArrivalBatchStoredCell('date', 'batch-date', date, true, false, '到货日期'); if (qtyCell && res.data && res.data.arrival_qty_filled) qtyCell.outerHTML = renderArrivalBatchStoredCell('number', 'batch-qty', qty, true, false, '到货数量', true); - if (defectiveCell && res.data && res.data.defective_qty_filled) defectiveCell.outerHTML = renderArrivalBatchStoredCell('number', 'batch-defective-qty', defectiveQty, true, false, '不良品数量', false); } + var defectiveCell = df && df.closest('td'); + if (defectiveCell && res.data && res.data.defective_qty_filled) defectiveCell.outerHTML = renderArrivalBatchStoredCell('number', 'batch-defective-qty', defectiveQty, true, false, '不良品数量', false); recalcArrivalUnfinished(); refreshOrderListFromArrivalModal(btn); setTimeout(function() { btn.textContent = '✅'; }, 500); @@ -22370,11 +22368,10 @@ function saveDetailChanges(btn) { var invalidBatch = batchAdds.concat(batchUpdates).some(function(b) { if (b.arrival_qty !== '' && (!Number.isInteger(b.arrival_qty) || b.arrival_qty < 0)) return true; if (b.defective_qty !== '' && !Number.isInteger(b.defective_qty)) return true; - return orderType !== 'packaging' && b.defective_qty !== '' && - (b.defective_qty < 0 || b.defective_qty > (b.arrival_qty || 0)); + return false; }); if (invalidBatch) { - showCenteredAlert('提示', orderType === 'packaging' ? '到货数量必须为非负整数,不良品数量必须为整数' : '数量格式错误,且不良品数量不能为负数或大于到货数量'); + showCenteredAlert('提示', '到货数量必须为非负整数,不良品数量必须为整数'); return; } diff --git a/tests/test_packaging_arrival_defective.py b/tests/test_packaging_arrival_defective.py index a190584..b88bede 100644 --- a/tests/test_packaging_arrival_defective.py +++ b/tests/test_packaging_arrival_defective.py @@ -18,21 +18,26 @@ class PackagingArrivalDefectiveTest(unittest.TestCase): self.assertEqual((10, 0, True, False), _arrival_batch_quantities( {'arrival_qty': '10', 'defective_qty': ''}, 'packaging')) - def test_other_order_types_keep_existing_validation(self): + def test_domestic_and_overseas_use_same_defective_rules(self): from routes.purchase import _arrival_batch_quantities - with self.assertRaisesRegex(ValueError, '不能为负数'): - _arrival_batch_quantities({'arrival_qty': '10', 'defective_qty': '-1'}, 'domestic') - with self.assertRaisesRegex(ValueError, '不能大于到货数量'): - _arrival_batch_quantities({'arrival_qty': '10', 'defective_qty': '11'}, 'overseas') + self.assertEqual((10, -1, True, True), _arrival_batch_quantities( + {'arrival_qty': '10', 'defective_qty': '-1'}, 'domestic')) + self.assertEqual((10, 11, True, True), _arrival_batch_quantities( + {'arrival_qty': '10', 'defective_qty': '11'}, 'overseas')) def test_frontend_keeps_blank_and_only_validates_non_packaging_range(self): source = Path(__file__).resolve().parents[1].joinpath('static/js/app.js').read_text(encoding='utf-8') self.assertIn("defectiveRaw === '' ? ''", source) - self.assertIn("orderType !== 'packaging' && defectiveRaw !== ''", source) + self.assertNotIn("orderType !== 'packaging' && defectiveRaw !== ''", source) self.assertIn("renderArrivalBatchStoredCell('number', 'batch-defective-qty'", source) self.assertNotIn('min="0" class="batch-defective-qty"', source) + def test_defective_column_is_visible_for_all_three_order_types(self): + source = Path(__file__).resolve().parents[1].joinpath('static/js/app.js').read_text(encoding='utf-8') + self.assertIn('var showDefectiveQty = true;', source) + self.assertIn("renderArrivalBatchStoredCell('number', 'batch-defective-qty'", source) + if __name__ == '__main__': unittest.main()
批次编号操作人
暂无数据
暂无数据
暂无数据
' + escHtml(b.operated_at || '-') + '0
' + '' + @@ -21909,7 +21909,7 @@ function showOrderDetail(encodedStr, title) { abHtml += '
--
加载失败
加载失败
加载失败
-
' + '' + @@ -22102,7 +22102,6 @@ function saveNewArrivalBatch(btn, orderId, orderType) { if (!date && qtyRaw === '') { alert('请输入到货日期或数量'); return; } if (qtyRaw !== '' && (!Number.isInteger(qty) || qty < 0)) { alert('到货数量必须为非负整数'); return; } if (defectiveRaw !== '' && !Number.isInteger(defectiveQty)) { alert('不良品数量必须为整数'); return; } - if (orderType !== 'packaging' && defectiveRaw !== '' && (defectiveQty < 0 || defectiveQty > (qty || 0))) { alert('不良品数量不能为负数或大于到货数量'); return; } btn.disabled = true; btn.textContent = '⋯'; fetch('/api/domestic/orders/add_batch', { @@ -22123,7 +22122,7 @@ function saveNewArrivalBatch(btn, orderId, orderType) { '
' + escHtml(res.data && res.data.operated_at || '-') + '0