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