From 79d4a365e00423d5bf69daff9510826138db8e1f Mon Sep 17 00:00:00 2001 From: DXC Date: Wed, 18 Mar 2026 10:41:19 +0800 Subject: [PATCH] feat: add partial return support with returned_quantity tracking --- inventory-backend/app/models/transaction.py | 8 +++- .../app/services/trans_service.py | 47 ++++++++++++++----- .../src/views/transaction/records.vue | 22 +++++++-- .../src/views/transaction/return.vue | 29 ++++++++++++ 4 files changed, 91 insertions(+), 15 deletions(-) diff --git a/inventory-backend/app/models/transaction.py b/inventory-backend/app/models/transaction.py index 8bce544..2cc3bcb 100644 --- a/inventory-backend/app/models/transaction.py +++ b/inventory-backend/app/models/transaction.py @@ -13,6 +13,7 @@ class TransBorrow(db.Model): stock_id = db.Column(db.Integer) barcode = db.Column(db.String(100)) quantity = db.Column(db.Numeric(19, 4)) + returned_quantity = db.Column(db.Numeric(19, 4), default=0) borrower_name = db.Column(db.String(100)) borrow_time = db.Column(db.DateTime, default=beijing_time) borrow_signature = db.Column(db.Text) @@ -26,6 +27,9 @@ class TransBorrow(db.Model): remark = db.Column(db.Text) def to_dict(self): + returned_qty = float(self.returned_quantity) if self.returned_quantity is not None else 0 + total_qty = float(self.quantity) if self.quantity is not None else 0 + pending_qty = total_qty - returned_qty return { 'id': self.id, 'borrow_no': self.borrow_no, @@ -33,7 +37,9 @@ class TransBorrow(db.Model): 'source_table': self.source_table, 'stock_id': self.stock_id, 'barcode': self.barcode, - 'quantity': float(self.quantity) if self.quantity is not None else None, + 'quantity': total_qty, + 'returned_quantity': returned_qty, + 'pending_quantity': pending_qty, 'borrower_name': self.borrower_name, 'borrow_time': self.borrow_time.strftime('%Y-%m-%d %H:%M') if self.borrow_time else None, 'borrow_signature': self.borrow_signature, diff --git a/inventory-backend/app/services/trans_service.py b/inventory-backend/app/services/trans_service.py index 4e426a6..2dee1c1 100644 --- a/inventory-backend/app/services/trans_service.py +++ b/inventory-backend/app/services/trans_service.py @@ -113,10 +113,12 @@ class TransService: @staticmethod def process_return(data, operator_name): """ - 还库逻辑: - 1. 恢复可用库存 - 2. 更新库位 (如果有变动) - 3. 记录库管签字 + 还库逻辑(支持部分归还): + 1. 校验本次归还数量不能大于待还数量 + 2. 恢复可用库存(按本次归还数量) + 3. 更新库位 (如果有变动) + 4. 记录库管签字 + 5. 更新归还数量和状态(部分归还/全部归还) """ items = data.get('items', []) signature = data.get('signature_path') # 库管签字 @@ -129,32 +131,55 @@ class TransService: try: for item in items: borrow_id = item.get('id') + # 前端传入的本次归还数量 + return_qty = float(item.get('return_qty', 0)) # 前端如果没有填 return_location,应该在提交前处理好,或者这里做 fallback # 这里假设前端传来的 return_location 就是最终要保存的库位 final_location = item.get('return_location') record = TransBorrow.query.with_for_update().get(borrow_id) - if not record or record.is_returned: + if not record: continue + # 计算待还数量 + returned_qty = float(record.returned_quantity) if record.returned_quantity else 0 + total_qty = float(record.quantity) if record.quantity else 0 + pending_qty = total_qty - returned_qty + + # 校验归还数量 + if return_qty <= 0: + raise ValueError(f"归还数量必须大于0") + if return_qty > pending_qty: + raise ValueError(f"本次归还数量({return_qty})不能大于待还数量({pending_qty})") + ModelClass = model_map.get(record.source_table) if ModelClass: stock = ModelClass.query.with_for_update().get(record.stock_id) if stock: - # 1. 恢复可用库存 - stock.available_quantity = float(stock.available_quantity) + float(record.quantity) + # 1. 恢复可用库存(按本次归还数量) + stock.available_quantity = float(stock.available_quantity) + return_qty # 2. 更新库位 (如果提供了有效值) if final_location: stock.warehouse_location = final_location - # 3. 更新借用单状态 - record.is_returned = True - record.status = 'returned' + # 3. 更新归还数量 + new_returned_qty = returned_qty + return_qty + record.returned_quantity = new_returned_qty + + # 4. 更新状态 + if new_returned_qty >= total_qty: + record.is_returned = True + record.status = 'returned' + else: + record.is_returned = False + record.status = 'partial_returned' + record.return_time = datetime.now() record.return_operator = operator_name record.return_signature = signature - record.return_location = final_location + if final_location: + record.return_location = final_location db.session.commit() except Exception as e: diff --git a/inventory-web/src/views/transaction/records.vue b/inventory-web/src/views/transaction/records.vue index 50dcb07..581b2fe 100644 --- a/inventory-web/src/views/transaction/records.vue +++ b/inventory-web/src/views/transaction/records.vue @@ -22,6 +22,22 @@ + + + + + + + + + @@ -42,9 +58,9 @@ diff --git a/inventory-web/src/views/transaction/return.vue b/inventory-web/src/views/transaction/return.vue index c98519d..c1ccfe0 100644 --- a/inventory-web/src/views/transaction/return.vue +++ b/inventory-web/src/views/transaction/return.vue @@ -47,6 +47,33 @@ + + + + + + + + + + + + +