当前位置: 首页 > article >正文

通用仓库管理系统开发书 Pyside6 + Sqlite3

通用仓库管理系统开发说明书(包含供应商和客户管理)

1. 项目概述

1.1 项目背景

随着企业规模的扩大和业务的复杂化,仓库管理变得越来越重要。为了提高仓库管理的效率和准确性,开发一个通用的仓库管理系统显得尤为重要。该系统将帮助企业实现库存的自动化管理,减少人为错误,提高工作效率。

1.2 项目目标

本项目旨在开发一个基于PySide6和SQLite3的通用仓库管理系统,主要功能包括:

  • 商品信息管理
  • 库存管理
  • 入库和出库操作
  • 供应商管理
  • 客户管理
  • 报表生成
  • 用户权限管理

2. 技术选型

2.1 前端框架

  • PySide6: PySide6是Qt for Python的官方库,提供了丰富的GUI组件和工具,适合开发跨平台的桌面应用程序。

2.2 数据库

  • SQLite3: SQLite3是一个轻量级的嵌入式数据库,适合小型应用程序,无需单独的数据库服务器。

2.3 开发语言

  • Python: Python是一种简单易学、功能强大的编程语言,适合快速开发。

3. 系统设计

3.1 数据库设计

3.1.1 数据库表结构
  • 商品表 (Products)
    • id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
    • name (TEXT, NOT NULL)
    • description (TEXT)
    • price (REAL, NOT NULL)
    • quantity (INTEGER, NOT NULL)
  • 供应商表 (Suppliers)
    • id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
    • name (TEXT, NOT NULL)
    • contact (TEXT)
    • phone (TEXT)
    • address (TEXT)
  • 客户表 (Customers)
    • id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
    • name (TEXT, NOT NULL)
    • contact (TEXT)
    • phone (TEXT)
    • address (TEXT)
  • 入库表 (StockIn)
    • id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
    • product_id (INTEGER, FOREIGN KEY REFERENCES Products(id))
    • supplier_id (INTEGER, FOREIGN KEY REFERENCES Suppliers(id))
    • quantity (INTEGER, NOT NULL)
    • date (TEXT, NOT NULL)
  • 出库表 (StockOut)
    • id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
    • product_id (INTEGER, FOREIGN KEY REFERENCES Products(id))
    • customer_id (INTEGER, FOREIGN KEY REFERENCES Customers(id))
    • quantity (INTEGER, NOT NULL)
    • date (TEXT, NOT NULL)
  • 用户表 (Users)
    • id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
    • username (TEXT, NOT NULL, UNIQUE)
    • password (TEXT, NOT NULL)
    • role (TEXT, NOT NULL)

3.2 功能模块设计

3.2.1 商品管理模块
  • 添加商品
  • 编辑商品信息
  • 删除商品
  • 查询商品
3.2.2 库存管理模块
  • 查看库存
  • 库存预警
  • 库存调整
3.2.3 入库管理模块
  • 添加入库记录
  • 查看入库历史
3.2.4 出库管理模块
  • 添加出库记录
  • 查看出库历史
3.2.5 供应商管理模块
  • 添加供应商
  • 编辑供应商信息
  • 删除供应商
  • 查询供应商
3.2.6 客户管理模块
  • 添加客户
  • 编辑客户信息
  • 删除客户
  • 查询客户
3.2.7 报表生成模块
  • 生成库存报表
  • 生成出入库报表
3.2.8 用户管理模块
  • 用户登录
  • 用户注册
  • 权限管理

4. 系统实现

4.1 环境搭建

4.1.1 安装依赖
pip install PySide6
4.1.2 创建数据库
import sqlite3

def create_database():
    conn = sqlite3.connect('warehouse.db')
    cursor = conn.cursor()
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS Products (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            description TEXT,
            price REAL NOT NULL,
            quantity INTEGER NOT NULL
        )
    ''')
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS Suppliers (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            contact TEXT,
            phone TEXT,
            address TEXT
        )
    ''')
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS Customers (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            contact TEXT,
            phone TEXT,
            address TEXT
        )
    ''')
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS StockIn (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            product_id INTEGER NOT NULL,
            supplier_id INTEGER NOT NULL,
            quantity INTEGER NOT NULL,
            date TEXT NOT NULL,
            FOREIGN KEY (product_id) REFERENCES Products(id),
            FOREIGN KEY (supplier_id) REFERENCES Suppliers(id)
        )
    ''')
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS StockOut (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            product_id INTEGER NOT NULL,
            customer_id INTEGER NOT NULL,
            quantity INTEGER NOT NULL,
            date TEXT NOT NULL,
            FOREIGN KEY (product_id) REFERENCES Products(id),
            FOREIGN KEY (customer_id) REFERENCES Customers(id)
        )
    ''')
    
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS Users (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            username TEXT NOT NULL UNIQUE,
            password TEXT NOT NULL,
            role TEXT NOT NULL
        )
    ''')
    
    conn.commit()
    conn.close()

create_database()

4.2 前端界面设计

4.2.1 主界面
  • 使用PySide6的QMainWindow作为主窗口,包含菜单栏、工具栏和状态栏。
  • 主界面包含多个选项卡,分别对应不同的功能模块。
4.2.2 商品管理界面
  • 使用QTableWidget显示商品列表。
  • 提供添加、编辑、删除按钮。
4.2.3 库存管理界面
  • 使用QTableWidget显示库存信息。
  • 提供库存预警功能。
4.2.4 入库管理界面
  • 提供表单用于添加入库记录。
  • 使用QTableWidget显示入库历史。
4.2.5 出库管理界面
  • 提供表单用于添加出库记录。
  • 使用QTableWidget显示出库历史。
4.2.6 供应商管理界面
  • 使用QTableWidget显示供应商列表。
  • 提供添加、编辑、删除按钮。
4.2.7 客户管理界面
  • 使用QTableWidget显示客户列表。
  • 提供添加、编辑、删除按钮。
4.2.8 报表生成界面
  • 提供按钮生成库存报表和出入库报表。
  • 使用QTextEdit显示报表内容。
4.2.9 用户管理界面
  • 提供登录和注册表单。
  • 使用QTableWidget显示用户列表。

4.3 后端逻辑实现

4.3.1 商品管理逻辑
  • 添加商品:将商品信息插入到Products表中。
  • 编辑商品:更新Products表中的记录。
  • 删除商品:从Products表中删除记录。
  • 查询商品:根据条件查询Products表中的记录。
4.3.2 库存管理逻辑
  • 查看库存:查询Products表中的库存信息。
  • 库存预警:检查库存数量是否低于预设阈值。
  • 库存调整:更新Products表中的库存数量。
4.3.3 入库管理逻辑
  • 添加入库记录:将入库信息插入到StockIn表中,并更新Products表中的库存数量。
  • 查看入库历史:查询StockIn表中的记录。
4.3.4 出库管理逻辑
  • 添加出库记录:将出库信息插入到StockOut表中,并更新Products表中的库存数量。
  • 查看出库历史:查询StockOut表中的记录。
4.3.5 供应商管理逻辑
  • 添加供应商:将供应商信息插入到Suppliers表中。
  • 编辑供应商:更新Suppliers表中的记录。
  • 删除供应商:从Suppliers表中删除记录。
  • 查询供应商:根据条件查询Suppliers表中的记录。
4.3.6 客户管理逻辑
  • 添加客户:将客户信息插入到Customers表中。
  • 编辑客户:更新Customers表中的记录。
  • 删除客户:从Customers表中删除记录。
  • 查询客户:根据条件查询Customers表中的记录。
4.3.7 报表生成逻辑
  • 生成库存报表:查询Products表中的库存信息并生成报表。
  • 生成出入库报表:查询StockInStockOut表中的记录并生成报表。
4.3.8 用户管理逻辑
  • 用户登录:验证用户名和密码。
  • 用户注册:将用户信息插入到Users表中。
  • 权限管理:根据用户角色控制功能访问权限。

5. 系统测试

5.1 单元测试

  • 对每个功能模块进行单元测试,确保每个功能都能正常工作。

5.2 集成测试

  • 对整个系统进行集成测试,确保各个模块之间的协作没有问题。

5.3 用户验收测试

  • 邀请最终用户进行验收测试,确保系统满足用户需求。

6. 部署与维护

6.1 部署

  • 将系统打包为可执行文件,方便用户安装和使用。

6.2 维护

  • 定期备份数据库,防止数据丢失。
  • 根据用户反馈进行系统优化和功能更新。

7. 总结

本项目通过使用PySide6和SQLite3,成功开发了一个通用的仓库管理系统。该系统功能完善,操作简便,能够有效提高仓库管理的效率和准确性。未来可以根据实际需求进一步扩展系统功能,如增加多仓库管理、支持更多报表类型等。

以下是 通用仓库管理系统 的开发文件目录结构,基于 PySide6 和 SQLite3 实现。该目录结构清晰划分了前端、后端、数据库、资源文件等模块,便于开发和维护。


开发文件目录结构

warehouse_management_system/  
├── main.py                      # 程序入口文件
├── requirements.txt             # 项目依赖文件
├── README.md                    # 项目说明文档
├── database/                    # 数据库相关文件
│   ├── db.py                    # 数据库连接与初始化
│   ├── models.py                # 数据库表结构定义
│   └── queries.py               # 数据库查询语句封装
├── ui/                          # 前端界面文件
│   ├── main_window.py           # 主窗口界面
│   ├── product_ui.py            # 商品管理界面
│   ├── stock_ui.py              # 库存管理界面
│   ├── supplier_ui.py           # 供应商管理界面
│   ├── customer_ui.py           # 客户管理界面
│   ├── report_ui.py             # 报表生成界面
│   └── user_ui.py               # 用户管理界面
├── logic/                       # 后端业务逻辑
│   ├── product_logic.py         # 商品管理逻辑
│   ├── stock_logic.py           # 库存管理逻辑
│   ├── supplier_logic.py        # 供应商管理逻辑
│   ├── customer_logic.py        # 客户管理逻辑
│   ├── report_logic.py          # 报表生成逻辑
│   └── user_logic.py            # 用户管理逻辑
├── resources/                   # 资源文件
│   ├── icons/                   # 图标资源
│   └── styles/                  # 样式表文件
├── tests/                       # 测试文件
│   ├── test_product.py          # 商品管理测试
│   ├── test_stock.py            # 库存管理测试
│   ├── test_supplier.py         # 供应商管理测试
│   ├── test_customer.py         # 客户管理测试
│   ├── test_report.py           # 报表生成测试
│   └── test_user.py             # 用户管理测试
└── utils/                       # 工具类
    ├── logger.py                # 日志工具
    └── helpers.py               # 通用工具函数

目录说明

  1. main.py
    • 程序入口文件,负责启动应用程序并加载主窗口。
  1. requirements.txt
    • 项目依赖文件,列出所有需要安装的 Python 库,例如:
PySide6==6.5.0
sqlite3
  1. database/
    • db.py: 数据库连接与初始化,包括创建数据库和表的逻辑。
    • models.py: 定义数据库表结构(如商品、供应商、客户等)。
    • queries.py: 封装常用的 SQL 查询语句,便于复用。
  1. ui/
    • 存放所有前端界面文件,每个界面文件对应一个功能模块。
    • 使用 PySide6 的 QMainWindowQDialogQWidget 等组件构建界面。
  1. logic/
    • 存放后端业务逻辑文件,每个文件对应一个功能模块的逻辑处理。
    • 例如:商品管理逻辑、库存管理逻辑、供应商管理逻辑等。
  1. resources/
    • 存放项目所需的资源文件,如图标、样式表等。
  1. tests/
    • 存放单元测试文件,用于测试各个功能模块的正确性。
  1. utils/
    • 存放工具类文件,如日志工具、通用工具函数等。

示例代码片段

main.py
import sys
from PySide6.QtWidgets import QApplication
from ui.main_window import MainWindow

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())
database/db.py
import sqlite3

def create_database():
    conn = sqlite3.connect('warehouse.db')
    cursor = conn.cursor()
    
    # 创建商品表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS Products (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            description TEXT,
            price REAL NOT NULL,
            quantity INTEGER NOT NULL
        )
    ''')
    
    # 创建供应商表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS Suppliers (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            name TEXT NOT NULL,
            contact TEXT,
            phone TEXT,
            address TEXT
        )
    ''')
    
    conn.commit()
    conn.close()

if __name__ == "__main__":
    create_database()
ui/main_window.py
from PySide6.QtWidgets import QMainWindow, QTabWidget
from ui.product_ui import ProductUI
from ui.stock_ui import StockUI

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("仓库管理系统")
        self.setGeometry(100, 100, 800, 600)
        
        # 创建选项卡
        self.tabs = QTabWidget()
        self.setCentralWidget(self.tabs)
        
        # 添加商品管理界面
        self.product_ui = ProductUI()
        self.tabs.addTab(self.product_ui, "商品管理")
        
        # 添加库存管理界面
        self.stock_ui = StockUI()
        self.tabs.addTab(self.stock_ui, "库存管理")

总结

以上目录结构清晰划分了项目的各个模块,便于团队协作开发和维护。通过模块化的设计,可以快速扩展功能(如添加新的管理模块)或修复问题。

为了支持通过 CSS 文档 来动态调整 UI 样式,我们可以将 PySide6 的界面设计与 CSS 样式分离。PySide6 支持使用 QSS(Qt Style Sheets),这是一种类似于 CSS 的样式表语言,可以通过加载外部 CSS 文件或直接在代码中设置样式来实现 UI 样式的动态调整。

以下是实现方案和目录结构调整:


调整后的目录结构

warehouse_management_system/  
├── main.py                      # 程序入口文件
├── requirements.txt             # 项目依赖文件
├── README.md                    # 项目说明文档
├── database/                    # 数据库相关文件
│   ├── db.py                    # 数据库连接与初始化
│   ├── models.py                # 数据库表结构定义
│   └── queries.py               # 数据库查询语句封装
├── ui/                          # 前端界面文件
│   ├── main_window.py           # 主窗口界面
│   ├── product_ui.py            # 商品管理界面
│   ├── stock_ui.py              # 库存管理界面
│   ├── supplier_ui.py           # 供应商管理界面
│   ├── customer_ui.py           # 客户管理界面
│   ├── report_ui.py             # 报表生成界面
│   └── user_ui.py               # 用户管理界面
├── logic/                       # 后端业务逻辑
│   ├── product_logic.py         # 商品管理逻辑
│   ├── stock_logic.py           # 库存管理逻辑
│   ├── supplier_logic.py        # 供应商管理逻辑
│   ├── customer_logic.py        # 客户管理逻辑
│   ├── report_logic.py          # 报表生成逻辑
│   └── user_logic.py            # 用户管理逻辑
├── resources/                   # 资源文件
│   ├── icons/                   # 图标资源
│   └── styles/                  # 样式表文件
│       ├── main_style.qss       # 主窗口样式表
│       ├── product_style.qss    # 商品管理界面样式表
│       └── button_style.qss     # 按钮通用样式表
├── tests/                       # 测试文件
│   ├── test_product.py          # 商品管理测试
│   ├── test_stock.py            # 库存管理测试
│   ├── test_supplier.py         # 供应商管理测试
│   ├── test_customer.py         # 客户管理测试
│   ├── test_report.py           # 报表生成测试
│   └── test_user.py             # 用户管理测试
└── utils/                       # 工具类
    ├── logger.py                # 日志工具
    ├── helpers.py               # 通用工具函数
    └── style_loader.py          # 样式加载工具

实现步骤

1. 创建样式表文件

resources/styles/ 目录下创建 .qss 文件,例如:

main_style.qss
/* 主窗口样式 */
QMainWindow {
    background-color: #f0f0f0;
    font-family: "Arial";
    font-size: 14px;
}

/* 选项卡样式 */
QTabWidget::pane {
    border: 1px solid #ccc;
    background-color: #fff;
}

QTabBar::tab {
    padding: 10px;
    background-color: #e0e0e0;
    border: 1px solid #ccc;
}

QTabBar::tab:selected {
    background-color: #fff;
    border-bottom-color: #fff;
}
button_style.qss
/* 按钮通用样式 */
QPushButton {
    background-color: #4CAF50;
    color: white;
    border: none;
    padding: 10px;
    border-radius: 5px;
}

QPushButton:hover {
    background-color: #45a049;
}

QPushButton:pressed {
    background-color: #3d8b40;
}

2. 加载样式表

utils/style_loader.py 中编写样式加载工具:

from PySide6.QtWidgets import QApplication

def load_style(file_path):
    """加载指定的 QSS 样式表文件"""
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            style = f.read()
            QApplication.instance().setStyleSheet(style)
    except Exception as e:
        print(f"加载样式表失败: {e}")

3. 在界面中应用样式

main.py 中加载全局样式:

import sys
from PySide6.QtWidgets import QApplication
from ui.main_window import MainWindow
from utils.style_loader import load_style

if __name__ == "__main__":
    app = QApplication(sys.argv)
    
    # 加载全局样式
    load_style("resources/styles/main_style.qss")
    
    window = MainWindow()
    window.show()
    sys.exit(app.exec())

在具体的界面文件中,可以加载局部样式。例如,在 ui/product_ui.py 中:

from PySide6.QtWidgets import QWidget, QVBoxLayout, QPushButton
from utils.style_loader import load_style

class ProductUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.load_styles()

    def init_ui(self):
        self.layout = QVBoxLayout()
        self.button = QPushButton("添加商品")
        self.layout.addWidget(self.button)
        self.setLayout(self.layout)

    def load_styles(self):
        # 加载按钮样式
        load_style("resources/styles/button_style.qss")

4. 动态切换样式

可以通过配置文件或用户设置动态切换样式。例如:

def change_theme(theme_name):
    if theme_name == "light":
        load_style("resources/styles/light_theme.qss")
    elif theme_name == "dark":
        load_style("resources/styles/dark_theme.qss")

5. 示例样式表

dark_theme.qss
/* 深色主题 */
QMainWindow {
    background-color: #333;
    color: #fff;
}

QPushButton {
    background-color: #555;
    color: #fff;
    border: 1px solid #777;
}

QPushButton:hover {
    background-color: #666;
}

QPushButton:pressed {
    background-color: #444;
}

总结

通过将样式表与界面逻辑分离,可以实现以下优势:

  1. 样式与逻辑分离:便于维护和扩展。
  2. 动态切换主题:通过加载不同的 .qss 文件,实现主题切换。
  3. 统一管理样式:将所有样式集中存放在 resources/styles/ 目录下,便于管理。

这种方法非常适合需要频繁调整 UI 样式的项目,同时也能提高开发效率。

为了支持将打印功能改为基于 HTML 模板,并且允许用户通过修改外部 HTML 文件来自定义打印内容,我们可以将 HTML 模板文件与代码分离。通过加载外部 HTML 文件并动态填充数据,可以实现灵活的打印功能。

以下是实现方案和目录结构调整:


调整后的目录结构

warehouse_management_system/  
├── main.py                      # 程序入口文件
├── requirements.txt             # 项目依赖文件
├── README.md                    # 项目说明文档
├── database/                    # 数据库相关文件
│   ├── db.py                    # 数据库连接与初始化
│   ├── models.py                # 数据库表结构定义
│   └── queries.py               # 数据库查询语句封装
├── ui/                          # 前端界面文件
│   ├── main_window.py           # 主窗口界面
│   ├── product_ui.py            # 商品管理界面
│   ├── stock_ui.py              # 库存管理界面
│   ├── supplier_ui.py           # 供应商管理界面
│   ├── customer_ui.py           # 客户管理界面
│   ├── report_ui.py             # 报表生成界面
│   └── user_ui.py               # 用户管理界面
├── logic/                       # 后端业务逻辑
│   ├── product_logic.py         # 商品管理逻辑
│   ├── stock_logic.py           # 库存管理逻辑
│   ├── supplier_logic.py        # 供应商管理逻辑
│   ├── customer_logic.py        # 客户管理逻辑
│   ├── report_logic.py          # 报表生成逻辑
│   └── user_logic.py            # 用户管理逻辑
├── resources/                   # 资源文件
│   ├── icons/                   # 图标资源
│   ├── styles/                  # 样式表文件
│   └── templates/               # HTML 模板文件
│       ├── product_report.html  # 商品报表模板
│       ├── stock_report.html    # 库存报表模板
│       └── invoice_template.html# 发票模板
├── tests/                       # 测试文件
│   ├── test_product.py          # 商品管理测试
│   ├── test_stock.py            # 库存管理测试
│   ├── test_supplier.py         # 供应商管理测试
│   ├── test_customer.py         # 客户管理测试
│   ├── test_report.py           # 报表生成测试
│   └── test_user.py             # 用户管理测试
└── utils/                       # 工具类
    ├── logger.py                # 日志工具
    ├── helpers.py               # 通用工具函数
    ├── style_loader.py          # 样式加载工具
    └── template_loader.py       # HTML 模板加载工具

实现步骤

1. 创建 HTML 模板文件

resources/templates/ 目录下创建 HTML 模板文件,例如:

product_report.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>商品报表</title>

    <style>
        body {
            font-family: Arial, sans-serif;
        }
        h1 {
            text-align: center;
            color: #333;
        }
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }
        th, td {
            border: 1px solid #ddd;
            padding: 8px;
            text-align: left;
        }
        th {
            background-color: #f2f2f2;
        }
    </style>

</head>

<body>
    <h1>商品报表</h1>

    <table>
        <thead>
            <tr>
                <th>商品名称</th>

                <th>描述</th>

                <th>价格</th>

                <th>库存数量</th>

            </tr>

        </thead>

        <tbody>
            {{ products }}
        </tbody>

    </table>

</body>

</html>

2. 编写模板加载工具

utils/template_loader.py 中编写 HTML 模板加载工具:

def load_template(file_path, data):
    """
    加载 HTML 模板并填充数据
    :param file_path: 模板文件路径
    :param data: 填充的数据(字典格式)
    :return: 渲染后的 HTML 内容
    """
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            template = f.read()
            for key, value in data.items():
                template = template.replace("{{ " + key + " }}", value)
            return template
    except Exception as e:
        print(f"加载模板失败: {e}")
        return None

3. 在报表生成逻辑中使用模板

logic/report_logic.py 中编写报表生成逻辑:

from utils.template_loader import load_template
from database.queries import get_all_products

def generate_product_report():
    """
    生成商品报表
    :return: 渲染后的 HTML 内容
    """
    # 从数据库获取商品数据
    products = get_all_products()
    
    # 将数据格式化为 HTML 表格行
    product_rows = ""
    for product in products:
        product_rows += f"""
        <tr>
            <td>{product['name']}</td>

            <td>{product['description']}</td>

            <td>{product['price']}</td>

            <td>{product['quantity']}</td>

        </tr>

        """
    
    # 加载模板并填充数据
    template_data = {
        "products": product_rows
    }
    html_content = load_template("resources/templates/product_report.html", template_data)
    
    return html_content

4. 打印 HTML 内容

ui/report_ui.py 中实现打印功能:

from PySide6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QTextEdit, QPrintDialog, QPrinter
from PySide6.QtPrintSupport import QPrintDialog
from PySide6.QtWebEngineWidgets import QWebEngineView
from logic.report_logic import generate_product_report

class ReportUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()
        
        # 生成报表按钮
        self.generate_button = QPushButton("生成商品报表")
        self.generate_button.clicked.connect(self.generate_report)
        self.layout.addWidget(self.generate_button)
        
        # 显示 HTML 内容
        self.web_view = QWebEngineView()
        self.layout.addWidget(self.web_view)
        
        # 打印按钮
        self.print_button = QPushButton("打印报表")
        self.print_button.clicked.connect(self.print_report)
        self.layout.addWidget(self.print_button)
        
        self.setLayout(self.layout)

    def generate_report(self):
        """生成并显示商品报表"""
        html_content = generate_product_report()
        if html_content:
            self.web_view.setHtml(html_content)

    def print_report(self):
        """打印报表"""
        printer = QPrinter()
        dialog = QPrintDialog(printer, self)
        if dialog.exec() == QPrintDialog.Accepted:
            self.web_view.page().print(printer, lambda success: print("打印成功" if success else "打印失败"))

5. 动态修改模板

用户可以直接修改 resources/templates/ 目录下的 HTML 文件,例如调整样式或添加新的字段。系统会在每次生成报表时加载最新的模板。


总结

通过将打印功能改为基于 HTML 模板,并允许用户通过修改外部 HTML 文件来自定义打印内容,可以实现以下优势:

  1. 灵活定制:用户可以直接修改 HTML 文件,无需修改代码。
  2. 样式与数据分离:HTML 模板负责样式,Python 代码负责数据填充。
  3. 支持复杂布局:HTML 和 CSS 可以轻松实现复杂的报表布局。

这种方法非常适合需要频繁调整打印格式的项目,同时也能提高开发效率。

为了支持 添加入库记录 时能够记录 多个明细商品,我们需要对数据库设计和表单逻辑进行调整。以下是详细的实现方案:


1. 数据库设计调整

1.1 数据库表结构

入库主表 (StockIn)
  • id (INTEGER, PRIMARY KEY, AUTOINCREMENT): 入库记录的唯一标识。
  • supplier_id (INTEGER, FOREIGN KEY REFERENCES Suppliers(id)): 供应商 ID。
  • date (TEXT, NOT NULL): 入库日期。
  • total_quantity (INTEGER, NOT NULL): 总入库数量。
  • total_amount (REAL, NOT NULL): 总入库金额。
入库明细表 (StockInDetails)
  • id (INTEGER, PRIMARY KEY, AUTOINCREMENT): 明细记录的唯一标识。
  • stock_in_id (INTEGER, FOREIGN KEY REFERENCES StockIn(id)): 关联的入库记录 ID。
  • product_id (INTEGER, FOREIGN KEY REFERENCES Products(id)): 商品 ID。
  • quantity (INTEGER, NOT NULL): 入库数量。
  • price (REAL, NOT NULL): 商品单价。
  • amount (REAL, NOT NULL): 明细金额(quantity * price)。

1.2 数据库初始化脚本

database/db.py 中更新数据库初始化逻辑:

def create_database():
    conn = sqlite3.connect('warehouse.db')
    cursor = conn.cursor()
    
    # 创建入库主表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS StockIn (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            supplier_id INTEGER NOT NULL,
            date TEXT NOT NULL,
            total_quantity INTEGER NOT NULL,
            total_amount REAL NOT NULL,
            FOREIGN KEY (supplier_id) REFERENCES Suppliers(id)
        )
    ''')
    
    # 创建入库明细表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS StockInDetails (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            stock_in_id INTEGER NOT NULL,
            product_id INTEGER NOT NULL,
            quantity INTEGER NOT NULL,
            price REAL NOT NULL,
            amount REAL NOT NULL,
            FOREIGN KEY (stock_in_id) REFERENCES StockIn(id),
            FOREIGN KEY (product_id) REFERENCES Products(id)
        )
    ''')
    
    conn.commit()
    conn.close()

2. 表单设计

2.1 添加入库记录表单

ui/stock_ui.py 中设计一个表单,支持添加多个明细商品:

from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QTableWidget, QTableWidgetItem, QLineEdit, QDateEdit, QComboBox
from PySide6.QtCore import QDate
from database.queries import get_all_suppliers, get_all_products

class StockInUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()
        self.details = []  # 存储明细商品

    def init_ui(self):
        self.layout = QVBoxLayout()
        
        # 供应商选择
        self.supplier_combo = QComboBox()
        self.supplier_combo.addItems([s['name'] for s in get_all_suppliers()])
        self.layout.addWidget(self.supplier_combo)
        
        # 入库日期
        self.date_edit = QDateEdit(QDate.currentDate())
        self.layout.addWidget(self.date_edit)
        
        # 明细商品表格
        self.details_table = QTableWidget()
        self.details_table.setColumnCount(4)
        self.details_table.setHorizontalHeaderLabels(["商品", "数量", "单价", "金额"])
        self.layout.addWidget(self.details_table)
        
        # 添加明细按钮
        self.add_detail_button = QPushButton("添加明细")
        self.add_detail_button.clicked.connect(self.add_detail)
        self.layout.addWidget(self.add_detail_button)
        
        # 提交按钮
        self.submit_button = QPushButton("提交入库")
        self.submit_button.clicked.connect(self.submit_stock_in)
        self.layout.addWidget(self.submit_button)
        
        self.setLayout(self.layout)

    def add_detail(self):
        """添加明细商品"""
        # 弹出对话框选择商品和输入数量、单价
        dialog = QDialog(self)
        dialog.setWindowTitle("添加明细")
        layout = QVBoxLayout()
        
        # 商品选择
        product_combo = QComboBox()
        product_combo.addItems([p['name'] for p in get_all_products()])
        layout.addWidget(product_combo)
        
        # 数量输入
        quantity_edit = QLineEdit()
        quantity_edit.setPlaceholderText("数量")
        layout.addWidget(quantity_edit)
        
        # 单价输入
        price_edit = QLineEdit()
        price_edit.setPlaceholderText("单价")
        layout.addWidget(price_edit)
        
        # 确认按钮
        confirm_button = QPushButton("确认")
        confirm_button.clicked.connect(lambda: self.confirm_detail(
            dialog, product_combo.currentText(), quantity_edit.text(), price_edit.text()
        ))
        layout.addWidget(confirm_button)
        
        dialog.setLayout(layout)
        dialog.exec()

    def confirm_detail(self, dialog, product_name, quantity, price):
        """确认添加明细"""
        try:
            quantity = int(quantity)
            price = float(price)
            amount = quantity * price
            
            # 添加到明细列表
            self.details.append({
                "product_name": product_name,
                "quantity": quantity,
                "price": price,
                "amount": amount
            })
            
            # 更新表格
            row = self.details_table.rowCount()
            self.details_table.insertRow(row)
            self.details_table.setItem(row, 0, QTableWidgetItem(product_name))
            self.details_table.setItem(row, 1, QTableWidgetItem(str(quantity)))
            self.details_table.setItem(row, 2, QTableWidgetItem(str(price)))
            self.details_table.setItem(row, 3, QTableWidgetItem(str(amount)))
            
            dialog.close()
        except ValueError:
            print("请输入有效的数量和单价")

    def submit_stock_in(self):
        """提交入库记录"""
        if not self.details:
            print("请添加至少一个明细商品")
            return
        
        # 计算总数量和总金额
        total_quantity = sum(d['quantity'] for d in self.details)
        total_amount = sum(d['amount'] for d in self.details)
        
        # 获取供应商 ID
        supplier_name = self.supplier_combo.currentText()
        supplier_id = next(s['id'] for s in get_all_suppliers() if s['name'] == supplier_name)
        
        # 插入入库主表
        from database.queries import insert_stock_in
        stock_in_id = insert_stock_in(supplier_id, self.date_edit.date().toString("yyyy-MM-dd"), total_quantity, total_amount)
        
        # 插入入库明细表
        from database.queries import insert_stock_in_detail
        for detail in self.details:
            product_id = next(p['id'] for p in get_all_products() if p['name'] == detail['product_name'])
            insert_stock_in_detail(stock_in_id, product_id, detail['quantity'], detail['price'], detail['amount'])
        
        print("入库记录提交成功")
        self.details.clear()
        self.details_table.setRowCount(0)

3. 数据库操作

database/queries.py 中编写数据库操作函数:

def insert_stock_in(supplier_id, date, total_quantity, total_amount):
    """插入入库主表记录"""
    conn = sqlite3.connect('warehouse.db')
    cursor = conn.cursor()
    cursor.execute('''
        INSERT INTO StockIn (supplier_id, date, total_quantity, total_amount)
        VALUES (?, ?, ?, ?)
    ''', (supplier_id, date, total_quantity, total_amount))
    conn.commit()
    stock_in_id = cursor.lastrowid
    conn.close()
    return stock_in_id

def insert_stock_in_detail(stock_in_id, product_id, quantity, price, amount):
    """插入入库明细表记录"""
    conn = sqlite3.connect('warehouse.db')
    cursor = conn.cursor()
    cursor.execute('''
        INSERT INTO StockInDetails (stock_in_id, product_id, quantity, price, amount)
        VALUES (?, ?, ?, ?, ?)
    ''', (stock_in_id, product_id, quantity, price, amount))
    conn.commit()
    conn.close()

4. 总结

通过以上设计,系统可以支持:

  1. 多个明细商品:每次入库可以添加多个商品。
  2. 数据一致性:入库主表和明细表通过外键关联,确保数据完整性。
  3. 灵活扩展:可以轻松扩展功能,如支持修改明细、删除明细等。

这种方法非常适合需要记录复杂入库场景的仓库管理系统。

为了支持 Excel 导出和导入 功能,我们可以使用 Python 的 openpyxl 库来处理 Excel 文件。以下是实现方案,涵盖 商品管理供应商管理客户管理入库记录 等模块的 Excel 导出和导入功能。


1. 安装依赖

首先,安装 openpyxl 库:

pip install openpyxl

2. 导出功能实现

2.1 导出商品数据到 Excel

utils/excel_utils.py 中编写导出工具函数:

from openpyxl import Workbook

def export_to_excel(data, headers, file_path):
    """
    将数据导出到 Excel 文件
    :param data: 数据列表(每行是一个字典)
    :param headers: 表头列表(例如 ["ID", "名称", "描述", "价格", "库存"])
    :param file_path: 导出的文件路径(例如 "products.xlsx")
    """
    wb = Workbook()
    ws = wb.active
    
    # 写入表头
    ws.append(headers)
    
    # 写入数据
    for row in data:
        ws.append([row.get(header.lower(), "") for header in headers])
    
    # 保存文件
    wb.save(file_path)
    print(f"数据已导出到 {file_path}")

logic/product_logic.py 中调用导出函数:

from utils.excel_utils import export_to_excel
from database.queries import get_all_products

def export_products_to_excel(file_path):
    """导出商品数据到 Excel"""
    products = get_all_products()
    headers = ["ID", "名称", "描述", "价格", "库存"]
    export_to_excel(products, headers, file_path)

2.2 在界面中添加导出按钮

ui/product_ui.py 中添加导出按钮:

from PySide6.QtWidgets import QFileDialog
from logic.product_logic import export_products_to_excel

class ProductUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()
        
        # 导出按钮
        self.export_button = QPushButton("导出到 Excel")
        self.export_button.clicked.connect(self.export_products)
        self.layout.addWidget(self.export_button)
        
        self.setLayout(self.layout)

    def export_products(self):
        """导出商品数据"""
        file_path, _ = QFileDialog.getSaveFileName(self, "保存文件", "", "Excel 文件 (*.xlsx)")
        if file_path:
            export_products_to_excel(file_path)

3. 导入功能实现

3.1 从 Excel 导入商品数据

utils/excel_utils.py 中编写导入工具函数:

from openpyxl import load_workbook

def import_from_excel(file_path):
    """
    从 Excel 文件导入数据
    :param file_path: Excel 文件路径
    :return: 数据列表(每行是一个字典)
    """
    wb = load_workbook(file_path)
    ws = wb.active
    
    # 读取表头
    headers = [cell.value for cell in ws[1]]
    
    # 读取数据
    data = []
    for row in ws.iter_rows(min_row=2, values_only=True):
        row_data = {headers[i].lower(): row[i] for i in range(len(headers))}
        data.append(row_data)
    
    return data

logic/product_logic.py 中调用导入函数:

from utils.excel_utils import import_from_excel
from database.queries import insert_product

def import_products_from_excel(file_path):
    """从 Excel 导入商品数据"""
    data = import_from_excel(file_path)
    for item in data:
        insert_product(
            name=item.get("名称", ""),
            description=item.get("描述", ""),
            price=item.get("价格", 0),
            quantity=item.get("库存", 0)
        )
    print(f"成功导入 {len(data)} 条商品数据")

3.2 在界面中添加导入按钮

ui/product_ui.py 中添加导入按钮:

from logic.product_logic import import_products_from_excel

class ProductUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()
        
        # 导入按钮
        self.import_button = QPushButton("从 Excel 导入")
        self.import_button.clicked.connect(self.import_products)
        self.layout.addWidget(self.import_button)
        
        self.setLayout(self_layout)

    def import_products(self):
        """导入商品数据"""
        file_path, _ = QFileDialog.getOpenFileName(self, "选择文件", "", "Excel 文件 (*.xlsx)")
        if file_path:
            import_products_from_excel(file_path)

4. 支持其他模块

4.1 供应商管理

导出供应商数据
from database.queries import get_all_suppliers

def export_suppliers_to_excel(file_path):
    """导出供应商数据到 Excel"""
    suppliers = get_all_suppliers()
    headers = ["ID", "名称", "联系人", "电话", "地址"]
    export_to_excel(suppliers, headers, file_path)
导入供应商数据
from database.queries import insert_supplier

def import_suppliers_from_excel(file_path):
    """从 Excel 导入供应商数据"""
    data = import_from_excel(file_path)
    for item in data:
        insert_supplier(
            name=item.get("名称", ""),
            contact=item.get("联系人", ""),
            phone=item.get("电话", ""),
            address=item.get("地址", "")
        )
    print(f"成功导入 {len(data)} 条供应商数据")

4.2 客户管理

导出客户数据
from database.queries import get_all_customers

def export_customers_to_excel(file_path):
    """导出客户数据到 Excel"""
    customers = get_all_customers()
    headers = ["ID", "名称", "联系人", "电话", "地址"]
    export_to_excel(customers, headers, file_path)
导入客户数据
from database.queries import insert_customer

def import_customers_from_excel(file_path):
    """从 Excel 导入客户数据"""
    data = import_from_excel(file_path)
    for item in data:
        insert_customer(
            name=item.get("名称", ""),
            contact=item.get("联系人", ""),
            phone=item.get("电话", ""),
            address=item.get("地址", "")
        )
    print(f"成功导入 {len(data)} 条客户数据")

4.3 入库记录

导出入库记录
from database.queries import get_all_stock_in

def export_stock_in_to_excel(file_path):
    """导出入库记录到 Excel"""
    stock_in_records = get_all_stock_in()
    headers = ["ID", "供应商", "日期", "总数量", "总金额"]
    export_to_excel(stock_in_records, headers, file_path)
导入入库记录
from database.queries import insert_stock_in

def import_stock_in_from_excel(file_path):
    """从 Excel 导入入库记录"""
    data = import_from_excel(file_path)
    for item in data:
        insert_stock_in(
            supplier_id=item.get("供应商ID", 0),
            date=item.get("日期", ""),
            total_quantity=item.get("总数量", 0),
            total_amount=item.get("总金额", 0)
        )
    print(f"成功导入 {len(data)} 条入库记录")

5. 总结

通过以上实现,系统可以支持:

  1. Excel 导出:将商品、供应商、客户、入库记录等数据导出为 Excel 文件。
  2. Excel 导入:从 Excel 文件导入数据到系统中。
  3. 灵活扩展:可以轻松扩展其他模块的导入导出功能。

这种方法非常适合需要与 Excel 交互的仓库管理系统,同时也能提高数据管理的效率。

要实现 模糊录入 功能,系统需要能够从用户粘贴的文本中自动识别 产品名称单价数量。这可以通过以下步骤实现:


1. 功能需求分析

  1. 输入:用户粘贴一段文本(例如从文档或聊天记录中复制的内容)。
  2. 处理
    • 识别文本中的产品名称。
    • 提取单价和数量。
  1. 输出:将识别出的产品名称、单价和数量填充到表单中。

2. 实现方案

2.1 文本预处理

  • 去除多余的空格、换行符等。
  • 将文本按行或按特定分隔符(如逗号、分号)拆分为多个条目。

2.2 识别产品名称

  • 使用正则表达式匹配已知的产品名称。
  • 如果没有匹配到,可以提示用户手动选择。

2.3 提取单价和数量

  • 使用正则表达式提取数字和单位(如“元”、“个”等)。
  • 根据上下文判断数字是单价还是数量。

2.4 填充表单

  • 将识别出的数据填充到表单中,供用户确认或修改。

3. 代码实现

3.1 文本预处理

import re

def preprocess_text(text):
    """
    预处理文本
    :param text: 用户输入的文本
    :return: 处理后的文本列表(每行一个条目)
    """
    # 去除多余的空格和换行符
    text = re.sub(r'\s+', ' ', text).strip()
    # 按行或分号拆分
    lines = re.split(r'[\n;]', text)
    return [line.strip() for line in lines if line.strip()]

3.2 识别产品名称

假设系统中已有商品列表,可以从数据库中获取:

from database.queries import get_all_products

def extract_product_name(text, products):
    """
    从文本中提取产品名称
    :param text: 单行文本
    :param products: 商品列表(从数据库获取)
    :return: 匹配到的产品名称,如果没有匹配到则返回 None
    """
    for product in products:
        if product['name'] in text:
            return product['name']
    return None

3.3 提取单价和数量

def extract_price_and_quantity(text):
    """
    从文本中提取单价和数量
    :param text: 单行文本
    :return: 单价和数量(如果未提取到则返回 None)
    """
    # 匹配数字(支持小数)
    numbers = re.findall(r'\d+\.?\d*', text)
    if len(numbers) >= 2:
        return float(numbers[0]), int(numbers[1])  # 第一个数字是单价,第二个是数量
    return None, None

3.4 综合处理

def parse_input_text(text):
    """
    解析用户输入的文本
    :param text: 用户输入的文本
    :return: 解析后的数据列表(每个条目是一个字典)
    """
    products = get_all_products()
    lines = preprocess_text(text)
    result = []
    
    for line in lines:
        product_name = extract_product_name(line, products)
        price, quantity = extract_price_and_quantity(line)
        
        if product_name and price and quantity:
            result.append({
                "product_name": product_name,
                "price": price,
                "quantity": quantity
            })
    
    return result

3.5 在界面中实现模糊录入

ui/stock_ui.py 中添加模糊录入功能:

from PySide6.QtWidgets import QTextEdit, QMessageBox

class StockInUI(QWidget):
    def __init__(self):
        super().__init__()
        self.init_ui()

    def init_ui(self):
        self.layout = QVBoxLayout()
        
        # 模糊录入文本框
        self.fuzzy_input = QTextEdit()
        self.fuzzy_input.setPlaceholderText("粘贴文本内容(例如:苹果 5.5元 3个)")
        self.layout.addWidget(self.fuzzy_input)
        
        # 解析按钮
        self.parse_button = QPushButton("解析文本")
        self.parse_button.clicked.connect(self.parse_input)
        self.layout.addWidget(self.parse_button)
        
        self.setLayout(self.layout)

    def parse_input(self):
        """解析用户输入的文本"""
        text = self.fuzzy_input.toPlainText()
        if not text:
            QMessageBox.warning(self, "错误", "请输入文本内容")
            return
        
        parsed_data = parse_input_text(text)
        if not parsed_data:
            QMessageBox.warning(self, "错误", "未识别到有效数据")
            return
        
        # 将解析结果填充到表单中
        for item in parsed_data:
            self.add_detail(item['product_name'], item['quantity'], item['price'])
        
        QMessageBox.information(self, "成功", f"成功解析 {len(parsed_data)} 条数据")

    def add_detail(self, product_name, quantity, price):
        """将解析结果添加到明细表格"""
        row = self.details_table.rowCount()
        self.details_table.insertRow(row)
        self.details_table.setItem(row, 0, QTableWidgetItem(product_name))
        self.details_table.setItem(row, 1, QTableWidgetItem(str(quantity)))
        self.details_table.setItem(row, 2, QTableWidgetItem(str(price)))
        self.details_table.setItem(row, 3, QTableWidgetItem(str(quantity * price)))

4. 示例

输入文本

苹果 5.5元 3个
香蕉 3.2元 5个
橙子 4.0元 2个

解析结果

[
    {"product_name": "苹果", "price": 5.5, "quantity": 3},
    {"product_name": "香蕉", "price": 3.2, "quantity": 5},
    {"product_name": "橙子", "price": 4.0, "quantity": 2}
]

5. 总结

通过以上实现,系统可以:

  1. 模糊录入:从用户粘贴的文本中自动识别产品名称、单价和数量。
  2. 智能填充:将解析结果自动填充到表单中,减少用户手动输入的工作量。
  3. 灵活扩展:可以根据需求调整正则表达式或匹配逻辑,支持更多格式的文本。

这种方法非常适合需要快速录入数据的场景,能够显著提高工作效率。

为了实现 每周五自动发送邮件 给采购人员,通知库存低的商品需要补货,我们可以结合以下技术:

  1. 定时任务:使用 Python 的 schedule 库或操作系统的定时任务(如 cron)来定期执行脚本。
  2. 邮件发送:使用 Python 的 smtplib 库发送邮件。
  3. 库存检查:从数据库中查询库存低的商品。

以下是详细实现方案:


1. 安装依赖

安装所需的 Python 库:

pip install schedule

2. 数据库查询

database/queries.py 中编写查询库存低商品的函数:

def get_low_stock_products(threshold=10):
    """
    获取库存低于阈值的商品
    :param threshold: 库存阈值,默认 10
    :return: 库存低的商品列表
    """
    conn = sqlite3.connect('warehouse.db')
    cursor = conn.cursor()
    cursor.execute('''
        SELECT name, quantity FROM Products WHERE quantity < ?
    ''', (threshold,))
    products = cursor.fetchall()
    conn.close()
    return products

3. 邮件发送

utils/email_utils.py 中编写邮件发送工具:

import smtplib
from email.mime.text import MIMEText
from email.header import Header

def send_email(subject, body, to_emails, smtp_server, smtp_port, sender_email, sender_password):
    """
    发送邮件
    :param subject: 邮件主题
    :param body: 邮件正文
    :param to_emails: 收件人邮箱列表
    :param smtp_server: SMTP 服务器地址
    :param smtp_port: SMTP 服务器端口
    :param sender_email: 发件人邮箱
    :param sender_password: 发件人邮箱密码或授权码
    """
    try:
        # 创建邮件内容
        msg = MIMEText(body, 'plain', 'utf-8')
        msg['Subject'] = Header(subject, 'utf-8')
        msg['From'] = sender_email
        msg['To'] = ', '.join(to_emails)
        
        # 连接 SMTP 服务器并发送邮件
        with smtplib.SMTP(smtp_server, smtp_port) as server:
            server.starttls()  # 启用 TLS 加密
            server.login(sender_email, sender_password)
            server.sendmail(sender_email, to_emails, msg.as_string())
        print("邮件发送成功")
    except Exception as e:
        print(f"邮件发送失败: {e}")

4. 定时任务

scripts/low_stock_notification.py 中编写定时任务脚本:

import schedule
import time
from database.queries import get_low_stock_products
from utils.email_utils import send_email

def check_low_stock_and_notify():
    """
    检查库存低的商品并发送邮件通知
    """
    # 获取库存低的商品
    low_stock_products = get_low_stock_products(threshold=10)
    
    if not low_stock_products:
        print("没有库存低的商品")
        return
    
    # 生成邮件正文
    body = "以下商品库存较低,请及时补货:\n\n"
    for product in low_stock_products:
        body += f"商品名称: {product[0]}, 当前库存: {product[1]}\n"
    
    # 邮件配置
    subject = "库存补货通知"
    to_emails = ["purchaser1@example.com", "purchaser2@example.com"]  # 采购人员邮箱
    smtp_server = "smtp.example.com"  # SMTP 服务器地址
    smtp_port = 587  # SMTP 服务器端口
    sender_email = "noreply@example.com"  # 发件人邮箱
    sender_password = "your_password"  # 发件人邮箱密码或授权码
    
    # 发送邮件
    send_email(subject, body, to_emails, smtp_server, smtp_port, sender_email, sender_password)

# 每周五上午 10:00 执行任务
schedule.every().friday.at("10:00").do(check_low_stock_and_notify)

# 保持脚本运行
while True:
    schedule.run_pending()
    time.sleep(1)

5. 部署定时任务

5.1 使用 Python 脚本运行

直接运行 low_stock_notification.py 脚本:

python scripts/low_stock_notification.py

5.2 使用操作系统的定时任务

如果希望脚本在后台运行,可以使用操作系统的定时任务工具。

在 Linux 上使用 cron
  1. 打开 crontab 编辑器:
crontab -e
  1. 添加以下行(每周五上午 10:00 执行):
0 10 * * 5 python /path/to/your/scripts/low_stock_notification.py
在 Windows 上使用任务计划程序
  1. 打开任务计划程序。
  2. 创建一个新任务,设置触发器为每周五上午 10:00。
  3. 设置操作为运行 python 并指定脚本路径。

6. 示例邮件内容

邮件主题

库存补货通知

邮件正文

以下商品库存较低,请及时补货:

商品名称: 苹果, 当前库存: 5
商品名称: 香蕉, 当前库存: 8
商品名称: 橙子, 当前库存: 3

7. 总结

通过以上实现,系统可以:

  1. 自动检查库存:每周五自动检查库存低的商品。
  2. 发送邮件通知:将库存低的商品列表通过邮件发送给采购人员。
  3. 灵活配置:可以调整库存阈值、邮件接收人、发送时间等。

这种方法非常适合需要定期补货的场景,能够显著提高仓库管理的效率。


http://www.kler.cn/a/505281.html

相关文章:

  • 初始Java4
  • rsarsa-给定pqe求私钥对密文解密
  • JAVA安全—JWT攻防Swagger自动化Druid泄露
  • STM32-keil安装时遇到的一些问题以及解决方案
  • 汽车免拆诊断案例 | 2007 款法拉利 599 GTB 车发动机故障灯异常点亮
  • MySQL 排除指定时间内重复记录的解决方案
  • 工业界主流大语言模型后训练技术综述:偏好对齐与能力提升
  • 【Block总结】ELGCA模块,池化-转置(PT)注意力和深度卷积有效聚合局部和全局上下文信息
  • 2025-01-08 - 通用人工智能技术 - RAG - 双系统 GPU直通 - 流雨声
  • LeetCode 3066.超过阈值的最少操作数 II:模拟 - 原地建堆O(1)空间 / 优先队列O(n)空间
  • WEB 攻防-通用漏-XSS 跨站脚本攻击-反射型/存储型/DOMBEEF-XSS
  • 书生大模型基础岛第四关
  • 批量识别图片型PDF指定区域内容识别保存表格+PDF批量改名:技术难题与项目实战总结
  • 【Sql递归查询】Mysql、Oracle、SQL Server、PostgreSQL 实现递归查询的区别与案例(详解)
  • Mac操作系统zip压缩加密
  • 【Vim Masterclass 笔记10】S06L23:Vim 核心操作训练之 —— 文本的搜索、查找与替换操作(第二部分)
  • 【21天学习AI底层概念】day13 (kaggle新手入门教程)Exercise: Underfitting and Overfitting
  • 【搭建JavaEE】(2)Tomcat安装配置和第一个JavaEE程序
  • 详解如何自定义 Android Dex VMP 保护壳
  • 深度学习核函数
  • HTML学习笔记(3)
  • YOLOv10-1.1部分代码阅读笔记-dataset.py
  • Web网页实现上拉加载分页
  • 蓝桥杯刷题第二天——背包问题
  • [信息安全] 1. 企业网络安全基础知识
  • Springboot和Es整合