diff --git a/inventory-backend/app/api/v1/stock/adjustment.py b/inventory-backend/app/api/v1/stock/adjustment.py index 8cc99ec..a319d9e 100644 --- a/inventory-backend/app/api/v1/stock/adjustment.py +++ b/inventory-backend/app/api/v1/stock/adjustment.py @@ -225,40 +225,121 @@ def get_stocks(): # -------------------------------------------------------- -# 5. 一键引入盘点差异 -# POST /api/v1/stock/adjustment/import-from-stocktake +# 5. 获取盘点差异列表 +# GET /api/v1/stock/adjustment/stocktake-discrepancies # -------------------------------------------------------- -@adjustment_bp.route('/import-from-stocktake', methods=['POST']) +@adjustment_bp.route('/stocktake-discrepancies', methods=['GET']) @jwt_required() -@permission_required('stock_adjustment:operation') -def import_from_stocktake(): - """从盘点差异记录导入为盘盈盘亏单""" - identity = get_jwt_identity() - operator = identity.get('username', 'system') if isinstance(identity, dict) else str(identity) - +@permission_required('stock_adjustment:list') +def get_stocktake_discrepancies(): + """获取所有有差异的盘点记录""" try: # 查询所有有差异的盘点记录 drafts = StocktakeDraft.query.filter(StocktakeDraft.diff_qty != 0).all() - if not drafts: - return jsonify({'code': 200, 'msg': '暂无盘点差异记录', 'data': {'count': 0}}) - - count = 0 + items = [] for draft in drafts: - # 判断盘盈/盘亏 diff = float(draft.diff_qty or 0) if diff == 0: continue - adjust_type = 'profit' if diff > 0 else 'loss' - adjust_quantity = abs(diff) - # 获取物料基础信息 base_id = None + material_name = '' + spec_model = '' sku = '' warehouse_location = '' # 根据source_table获取对应的库存记录 + stock_model = get_stock_model(draft.source_table) + if stock_model and draft.stock_id: + stock = stock_model.query.get(draft.stock_id) + if stock: + base_id = getattr(stock, 'base_id', None) + sku = getattr(stock, 'sku', None) or getattr(stock, 'SKU', '') + warehouse_location = getattr(stock, 'warehouse_location', '') + + # 联表查询 MaterialBase + if base_id: + material = MaterialBase.query.get(base_id) + if material: + material_name = material.name + spec_model = material.spec_model + + items.append({ + 'draft_id': draft.id, + 'source_table': draft.source_table, + 'stock_id': draft.stock_id, + 'base_id': base_id, + 'sku': sku, + 'material_name': material_name, + 'spec_model': spec_model, + 'warehouse_location': warehouse_location, + 'stock_qty': float(draft.stock_qty or 0), + 'quantity': float(draft.quantity or 0), + 'diff_qty': diff, + 'adjust_type': 'profit' if diff > 0 else 'loss', + 'remark': draft.remark or '' + }) + + return jsonify({ + 'code': 200, + 'data': { + 'items': items, + 'total': len(items) + } + }) + + except Exception as e: + return jsonify({'code': 500, 'msg': f'获取盘点差异失败: {str(e)}'}), 500 + + +# -------------------------------------------------------- +# 6. 批量导入盘点差异(按需勾选) +# POST /api/v1/stock/adjustment/import-from-stocktake +# -------------------------------------------------------- +@adjustment_bp.route('/import-from-stocktake', methods=['POST']) +@jwt_required() +@permission_required('stock_adjustment:operation') +def import_from_stocktake(): + """批量导入选中的盘点差异记录""" + identity = get_jwt_identity() + # 修复操作人保存为0的Bug,确保保存真实的用户名 + operator = identity.get('username', 'system') if isinstance(identity, dict) else str(identity) + if not operator or operator == '0': + operator = identity if identity else 'system' + + data = request.get_json() + if not data or 'records' not in data: + return jsonify({'code': 400, 'msg': '缺少records参数'}), 400 + + records = data.get('records', []) + if not records: + return jsonify({'code': 400, 'msg': '请选择要导入的记录'}), 400 + + try: + count = 0 + for item in records: + draft_id = item.get('draft_id') + reason = item.get('reason', '盘点差异导入') + + # 获取对应的盘点记录 + draft = StocktakeDraft.query.get(draft_id) + if not draft: + continue + + diff = float(draft.diff_qty or 0) + if diff == 0: + continue + + adjust_type = 'profit' if diff > 0 else 'loss' + adjust_quantity = abs(diff) + + # 获取物料基础信息 + base_id = None + sku = '' + warehouse_location = '' + stock_model = get_stock_model(draft.source_table) if stock_model and draft.stock_id: stock = stock_model.query.get(draft.stock_id) @@ -270,9 +351,6 @@ def import_from_stocktake(): # 生成调整单号 order_no = generate_order_no() - # 使用备注或默认原因 - reason = draft.remark if draft.remark else '盘点差异自动生成' - # 创建调整单 adjustment = StockAdjustment( order_no=order_no, @@ -291,7 +369,7 @@ def import_from_stocktake(): count += 1 db.session.commit() - return jsonify({'code': 200, 'msg': '导入成功', 'data': {'count': count}}) + return jsonify({'code': 200, 'msg': f'成功导入 {count} 条记录', 'data': {'count': count}}) except Exception as e: db.session.rollback() diff --git a/inventory-web/src/views/stock/adjustment/index.vue b/inventory-web/src/views/stock/adjustment/index.vue index c9da0cd..8a95a73 100644 --- a/inventory-web/src/views/stock/adjustment/index.vue +++ b/inventory-web/src/views/stock/adjustment/index.vue @@ -130,6 +130,49 @@ style="margin-top: 15px; justify-content: center" /> + + + +
+ + + + + + + + + + + + + + + + + + +
+ 暂无盘点差异记录 +
+
+ +
@@ -182,6 +225,80 @@ const stockLimit = ref(20) const stockKeyword = ref('') const selectedStock = ref(null) +// 盘点差异审核 +const showReviewDialog = ref(false) +const reviewLoading = ref(false) +const reviewList = ref([]) +const selectedReviewRows = ref([]) +const reviewTableRef = ref() +const importLoading = ref(false) + +// 获取盘点差异列表 +async function fetchReviewList() { + reviewLoading.value = true + try { + const res = await request({ + url: '/v1/stock/adjustment/stocktake-discrepancies', + method: 'get' + }) + if (res.code === 200) { + // 为每条记录设置默认原因 + reviewList.value = (res.data.items || []).map((item: any) => ({ + ...item, + reason: item.remark || '盘点差异导入' + })) + } + } catch (e) { + ElMessage.error('获取盘点差异失败') + } finally { + reviewLoading.value = false + } +} + +// 打开审核弹窗 +async function openReviewDialog() { + showReviewDialog.value = true + selectedReviewRows.value = [] + await fetchReviewList() +} + +// 勾选变化 +function handleReviewSelectionChange(rows: any[]) { + selectedReviewRows.value = rows +} + +// 导入选中的记录 +async function handleImportSelected() { + if (selectedReviewRows.value.length === 0) { + ElMessage.warning('请选择要导入的记录') + return + } + + importLoading.value = true + try { + const records = selectedReviewRows.value.map(row => ({ + draft_id: row.draft_id, + reason: row.reason || '盘点差异导入' + })) + const res = await request({ + url: '/v1/stock/adjustment/import-from-stocktake', + method: 'post', + data: { records } + }) + if (res.code === 200) { + ElMessage.success(res.msg || '导入成功') + showReviewDialog.value = false + fetchData() + } else { + ElMessage.error(res.msg || '导入失败') + } + } catch (e) { + ElMessage.error('导入失败') + } finally { + importLoading.value = false + } +} + // 获取列表 async function fetchData() { loading.value = true @@ -297,29 +414,9 @@ async function submitForm() { } } -// 一键引入盘点差异 +// 一键引入盘点差异 - 打开审核弹窗 async function handleImportStocktake() { - try { - await ElMessageBox.confirm('确定要将当前所有的盘点差异导入为盘盈盘亏单吗?', '提示', { - confirmButtonText: '确定', - cancelButtonText: '取消', - type: 'warning' - }) - const res = await request({ - url: '/v1/stock/adjustment/import-from-stocktake', - method: 'post' - }) - if (res.code === 200) { - ElMessage.success(`成功导入 ${res.data.count} 条盘点差异记录`) - fetchData() - } else { - ElMessage.error(res.msg || '导入失败') - } - } catch (e) { - if (e !== 'cancel') { - ElMessage.error('导入失败') - } - } + await openReviewDialog() } onMounted(() => {