This commit is contained in:
2025-12-23 00:30:36 +08:00
parent 192c05707a
commit 033a1acef3
16 changed files with 2870 additions and 1342 deletions

222
stock_dialog.py Normal file
View File

@@ -0,0 +1,222 @@
"""
库存管理模块 - 处理原料入库和库存查询
"""
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"
params = []
if keyword:
query += " WHERE 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)}")