222 lines
8.6 KiB
Python
222 lines
8.6 KiB
Python
"""
|
||
库存管理模块 - 处理原料入库和库存查询
|
||
"""
|
||
|
||
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)}") |