Files
cangku/stock_dialog.py
liangweihao 6322cb0caa 实现原料逻辑删除功能
- 为fabrics表添加is_deleted字段用于标记删除状态
- 修改delete_raw方法实现逻辑删除而非物理删除
- 更新所有查询语句过滤已删除的原料数据
- 更新库存视图过滤已删除的原料和相关记录
- 保留历史数据,支持数据恢复

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-27 19:09:16 +08:00

222 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
库存管理模块 - 处理原料入库和库存查询
"""
from datetime import datetime
from PyQt5.QtWidgets import (
QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QTableWidget, QTableWidgetItem, QHeaderView,
QMessageBox, QInputDialog
)
from database import get_db_connection
class StockInDialog(QDialog):
"""独立原料入库管理"""
def __init__(self, db_path):
super().__init__()
self.db_path = db_path
self.setWindowTitle("原料入库记录")
self.resize(900, 600)
self.setup_ui()
self.load_models()
def setup_ui(self):
"""设置用户界面"""
layout = QVBoxLayout(self)
# 搜索过滤区域
filter_layout = QHBoxLayout()
filter_layout.addWidget(QLabel("搜索型号/名称:"))
self.search_input = QLineEdit()
self.search_input.textChanged.connect(self.load_models)
filter_layout.addWidget(self.search_input)
refresh_btn = QPushButton("刷新")
refresh_btn.clicked.connect(self.load_models)
filter_layout.addWidget(refresh_btn)
layout.addLayout(filter_layout)
# 数据表格
headers = ["型号/名称", "颜色", "供应商", "单位", "当前剩余库存", "操作"]
self.table = QTableWidget()
self.table.setColumnCount(len(headers))
self.table.setHorizontalHeaderLabels(headers)
self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
layout.addWidget(self.table)
def get_conn(self):
"""获取数据库连接"""
return get_db_connection(self.db_path)
def load_models(self):
"""加载面料型号列表"""
keyword = self.search_input.text().strip()
try:
with self.get_conn() as conn:
# 查询面料基础信息
query = "SELECT model, color, supplier, unit FROM fabrics WHERE (is_deleted IS NULL OR is_deleted = 0)"
params = []
if keyword:
query += " AND (model LIKE ? OR color LIKE ?)"
params = ["%" + keyword + "%", "%" + keyword + "%"]
query += " ORDER BY timestamp DESC"
cursor = conn.execute(query, params)
rows = cursor.fetchall()
# 计算库存数量
model_stock = {}
# 入库数量
cursor_in = conn.execute("SELECT model, COALESCE(SUM(quantity), 0) FROM fabric_stock_in GROUP BY model")
for model, quantity in cursor_in.fetchall():
model_stock[model] = quantity or 0
# 消耗数量
cursor_out = conn.execute("SELECT model, COALESCE(SUM(consume_quantity), 0) FROM fabric_consumption GROUP BY model")
for model, quantity in cursor_out.fetchall():
model_stock[model] = model_stock.get(model, 0) - (quantity or 0)
# 填充表格
self.table.setRowCount(len(rows))
for i, (model, color, supplier, unit) in enumerate(rows):
self.table.setItem(i, 0, QTableWidgetItem(model or ""))
self.table.setItem(i, 1, QTableWidgetItem(color or ""))
self.table.setItem(i, 2, QTableWidgetItem(supplier or ""))
self.table.setItem(i, 3, QTableWidgetItem(unit or ""))
remaining = model_stock.get(model, 0)
self.table.setItem(i, 4, QTableWidgetItem("{:.3f}".format(remaining)))
# 入库按钮
btn = QPushButton("入库")
btn.clicked.connect(lambda _, m=model, u=unit or "": self.do_stock_in(m, u))
self.table.setCellWidget(i, 5, btn)
except Exception as e:
QMessageBox.critical(self, "错误", f"加载数据失败: {str(e)}")
def do_stock_in(self, model, unit):
"""执行入库操作"""
# 输入入库数量
quantity, ok1 = QInputDialog.getDouble(
self, "入库数量", f"{model}】入库数量(单位:{unit}:",
0, 0, 1000000, 3
)
if not ok1 or quantity <= 0:
return
# 输入备注信息
note, ok2 = QInputDialog.getText(
self, "入库备注", "备注(供应商/批次/发票号等,可选):"
)
if not ok2:
note = ""
try:
with self.get_conn() as conn:
# 插入入库记录
conn.execute('''
INSERT INTO fabric_stock_in (model, quantity, unit, purchase_date, note)
VALUES (?, ?, ?, ?, ?)
''', (model, quantity, unit, datetime.now().strftime('%Y-%m-%d'), note))
conn.commit()
QMessageBox.information(self, "成功", f"已入库 {model}{quantity} {unit}")
self.load_models()
except Exception as e:
QMessageBox.critical(self, "错误", f"入库失败: {str(e)}")
class StockQueryDialog(QDialog):
"""库存查询对话框"""
def __init__(self, db_path):
super().__init__()
self.db_path = db_path
self.setWindowTitle("库存查询")
self.resize(1000, 700)
self.setup_ui()
self.load_stock_data()
def setup_ui(self):
"""设置用户界面"""
layout = QVBoxLayout(self)
# 搜索区域
search_layout = QHBoxLayout()
search_layout.addWidget(QLabel("搜索:"))
self.search_input = QLineEdit()
self.search_input.textChanged.connect(self.load_stock_data)
search_layout.addWidget(self.search_input)
refresh_btn = QPushButton("刷新")
refresh_btn.clicked.connect(self.load_stock_data)
search_layout.addWidget(refresh_btn)
layout.addLayout(search_layout)
# 库存表格
headers = ["类目", "型号", "颜色", "供应商", "单位", "入库总量", "消耗总量", "剩余库存"]
self.stock_table = QTableWidget()
self.stock_table.setColumnCount(len(headers))
self.stock_table.setHorizontalHeaderLabels(headers)
self.stock_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
layout.addWidget(self.stock_table)
def get_conn(self):
"""获取数据库连接"""
return get_db_connection(self.db_path)
def load_stock_data(self):
"""加载库存数据"""
keyword = self.search_input.text().strip()
try:
with self.get_conn() as conn:
# 查询库存汇总数据
query = """
SELECT
f.category,
f.model,
f.color,
f.supplier,
f.unit,
COALESCE(SUM(si.quantity), 0) as total_in,
COALESCE(SUM(fc.consume_quantity), 0) as total_out,
COALESCE(SUM(si.quantity), 0) - COALESCE(SUM(fc.consume_quantity), 0) as remaining
FROM fabrics f
LEFT JOIN fabric_stock_in si ON f.model = si.model
LEFT JOIN fabric_consumption fc ON f.model = fc.model
"""
params = []
if keyword:
query += " WHERE f.model LIKE ? OR f.category LIKE ? OR f.color LIKE ?"
params = [f"%{keyword}%", f"%{keyword}%", f"%{keyword}%"]
query += " GROUP BY f.model ORDER BY f.category, f.model"
cursor = conn.execute(query, params)
rows = cursor.fetchall()
# 填充表格
self.stock_table.setRowCount(len(rows))
for i, row in enumerate(rows):
category, model, color, supplier, unit, total_in, total_out, remaining = row
self.stock_table.setItem(i, 0, QTableWidgetItem(category or ""))
self.stock_table.setItem(i, 1, QTableWidgetItem(model or ""))
self.stock_table.setItem(i, 2, QTableWidgetItem(color or ""))
self.stock_table.setItem(i, 3, QTableWidgetItem(supplier or ""))
self.stock_table.setItem(i, 4, QTableWidgetItem(unit or ""))
self.stock_table.setItem(i, 5, QTableWidgetItem(f"{total_in:.3f}"))
self.stock_table.setItem(i, 6, QTableWidgetItem(f"{total_out:.3f}"))
self.stock_table.setItem(i, 7, QTableWidgetItem(f"{remaining:.3f}"))
except Exception as e:
QMessageBox.critical(self, "错误", f"加载库存数据失败: {str(e)}")