Python 写的 智慧记 进销存 辅助 程序 导入导出 excel 可打印

 图样:

 

就可以导入了

上代码

import tkinter as tk
from tkinter import ttk
import sqlite3
from datetime import datetime
from tkinter import messagebox, filedialog
import pandas as pd
import re

class OrderSystem:
    def __init__(self, root):
        self.root = root
        self.root.title("订单记录系统")
        
        # 创建数据库连接
        self.conn = sqlite3.connect('orders.db')
        self.create_table()
        
        # 创建界面
        self.create_ui()
        
        # 添加搜索框架
        self.create_search_frame()
        
        # 添加更多功能按钮
        self.add_function_buttons()
        
        # 加载所有订单数据
        self.load_all_orders()
        
        # 设置默认值
        self.set_default_values()
        
    def create_table(self):
        cursor = self.conn.cursor()
        cursor.execute('''
        CREATE TABLE IF NOT EXISTS orders (
            order_date TEXT,
            order_number TEXT,
            customer TEXT,
            product TEXT,
            unit TEXT,
            quantity REAL,
            price REAL,
            discount REAL,
            final_price REAL,
            total REAL,
            remarks TEXT,
            discount_amount REAL,
            discount_total REAL,
            delivery TEXT,
            payment_received REAL,
            end_customer TEXT,
            notes TEXT,
            business TEXT
        )
        ''')
        self.conn.commit()
        
    def create_ui(self):
        # 创建主框架来容纳左右两部分
        main_frame = ttk.Frame(self.root)
        main_frame.pack(fill="both", expand=True)
        
        # 创建左侧框架
        left_frame = ttk.Frame(main_frame)
        left_frame.pack(side="left", fill="both", expand=True)
        
        # 创建右侧框架
        right_frame = ttk.Frame(main_frame)
        right_frame.pack(side="right", fill="y", padx=5)
        
        # 创建输入框架(放在左侧)
        input_frame = ttk.LabelFrame(left_frame, text="订单信息")
        input_frame.pack(padx=5, pady=5, fill="x")
        
        # 修改订单分类框架
        order_group_frame = ttk.LabelFrame(right_frame, text="订单查询")
        order_group_frame.pack(padx=5, pady=5, fill="both", expand=True)
        
        # 添加筛选框
        filter_frame = ttk.Frame(order_group_frame)
        filter_frame.pack(fill="x", padx=5, pady=5)
        
        # 单据���号筛选
        ttk.Label(filter_frame, text="单据编号:").grid(row=0, column=0, padx=5)
        self.order_number_filter = ttk.Combobox(filter_frame, width=15)
        self.order_number_filter.grid(row=0, column=1, padx=5)
        
        # 客户名称筛选
        ttk.Label(filter_frame, text="客户名称:").grid(row=0, column=2, padx=5)
        self.customer_filter = ttk.Combobox(filter_frame, width=15)
        self.customer_filter.grid(row=0, column=3, padx=5)
        
        # 筛选按钮
        ttk.Button(filter_frame, text="筛选", command=self.filter_orders).grid(row=0, column=4, padx=5)
        ttk.Button(filter_frame, text="重置", command=self.reset_filter).grid(row=0, column=5, padx=5)
        ttk.Button(filter_frame, text="打印", command=self.print_filtered_data).grid(row=0, column=6, padx=5)
        
        # 绑定下拉框事件
        self.order_number_filter.bind('<KeyRelease>', self.update_order_number_list)
        self.customer_filter.bind('<KeyRelease>', self.update_customer_list)
        
        # 修改订单分类的树形视图列
        self.group_tree = ttk.Treeview(order_group_frame, columns=[
            "order_number", "customer", "product", "unit", 
            "quantity", "price", "total", "remarks"
        ], show="headings", height=15)
        
        # 设置列标题和宽度
        columns = [
            ("order_number", "单据编号", 100),
            ("customer", "客户名称", 100),
            ("product", "品名规格", 120),
            ("unit", "单位", 50),
            ("quantity", "数量", 60),
            ("price", "原价", 80),
            ("total", "金额", 80),
            ("remarks", "备注", 100)
        ]
        
        for col, heading, width in columns:
            self.group_tree.heading(col, text=heading)
            self.group_tree.column(col, width=width)
        
        self.group_tree.pack(padx=5, pady=5, fill="both", expand=True)
        
        # 添加滚动条
        group_scrollbar = ttk.Scrollbar(order_group_frame, orient="vertical", command=self.group_tree.yview)
        group_scrollbar.pack(side="right", fill="y")
        self.group_tree.configure(yscrollcommand=group_scrollbar.set)
        
        # 绑定点击事件
        self.group_tree.bind('<<TreeviewSelect>>', self.on_group_select)
        
        # 修改输入字段列表,确保与数据库字段完全匹配
        self.entries = {}
        fields = [
            ("order_date", "单据日期"), 
            ("order_number", "单据编号"),
            ("customer", "客户名称"), 
            ("product", "品名规格"),
            ("unit", "单位"),
            ("quantity", "数量"),
            ("price", "原价"), 
            ("discount", "单行折扣率(%)"),
            ("final_price", "折后价"), 
            ("total", "金额"),
            ("remarks", "备注"), 
            ("discount_amount", "整单折扣率(%)"),
            ("discount_total", "折后金额"), 
            ("delivery", "运费"),
            ("payment_received", "本单已收"), 
            ("end_customer", "结算账户"),
            ("notes", "说明"), 
            ("business", "营业员")
        ]
        
        for row, (field, label) in enumerate(fields):
            ttk.Label(input_frame, text=label).grid(row=row//2, column=(row%2)*2, padx=5, pady=2)
            self.entries[field] = ttk.Entry(input_frame)
            self.entries[field].grid(row=row//2, column=(row%2)*2+1, padx=5, pady=2, sticky="ew")
            
        # 添加按钮
        self.btn_frame = ttk.Frame(self.root)
        self.btn_frame.pack(pady=5)
        
        ttk.Button(self.btn_frame, text="保存", command=self.save_order).pack(side="left", padx=5)
        ttk.Button(self.btn_frame, text="清空", command=self.clear_fields).pack(side="left", padx=5)
        ttk.Button(self.btn_frame, text="导入Excel", command=self.import_from_excel).pack(side="left", padx=5)
        ttk.Button(self.btn_frame, text="导出模板", command=self.export_template).pack(side="left", padx=5)
        
        # 修改表格显示,显示所有列
        self.tree = ttk.Treeview(self.root, columns=[
            "order_date", "order_number", "customer", "product", "unit",
            "quantity", "price", "discount", "final_price", "total",
            "remarks", "discount_amount", "discount_total", "delivery",
            "payment_received", "end_customer", "notes", "business"
        ], show="headings")
        
        # 修改列标题定义,显示所有列
        columns = [
            ("order_date", "单据日期"), 
            ("order_number", "单据编号"),
            ("customer", "客户名称"), 
            ("product", "品名规格"),
            ("unit", "单位"),
            ("quantity", "数量"),
            ("price", "原价"), 
            ("discount", "单行折扣率(%)"),
            ("final_price", "折后价"), 
            ("total", "金额"),
            ("remarks", "备注"),
            ("discount_amount", "整单折扣率(%)"),
            ("discount_total", "折后金额"),
            ("delivery", "运费"),
            ("payment_received", "本单已收"),
            ("end_customer", "结算账户"),
            ("notes", "说明"),
            ("business", "营业员")
        ]
        
        for col, heading in columns:
            self.tree.heading(col, text=heading)
            self.tree.column(col, width=100)
            
        self.tree.pack(padx=5, pady=5, fill="both", expand=True)
        
        # 添加滚动条
        scrollbar = ttk.Scrollbar(self.root, orient="vertical", command=self.tree.yview)
        scrollbar.pack(side="right", fill="y")
        self.tree.configure(yscrollcommand=scrollbar.set)
        
        # 添加自动计算绑定
        self.entries['quantity'].bind('<KeyRelease>', self.calculate_total)
        self.entries['price'].bind('<KeyRelease>', self.calculate_total)
        self.entries['discount'].bind('<KeyRelease>', self.calculate_total)
        
        # 在订单分类框架底部添加合计标签
        self.total_label = ttk.Label(order_group_frame, text="合计金额: ¥0.00")
        self.total_label.pack(pady=5)

    def calculate_total(self, event=None):
        """计算折后价和金额"""
        try:
            quantity = float(self.entries['quantity'].get() or 0)
            price = float(self.entries['price'].get() or 0)
            discount = float(self.entries['discount'].get() or 100)
            
            # 计算折后价
            final_price = price * discount / 100
            self.entries['final_price'].delete(0, tk.END)
            self.entries['final_price'].insert(0, f"{final_price:.2f}")
            
            # 计算金额
            total = quantity * final_price
            self.entries['total'].delete(0, tk.END)
            self.entries['total'].insert(0, f"{total:.2f}")
        except ValueError:
            pass

    def create_search_frame(self):
        search_frame = ttk.LabelFrame(self.root, text="搜索")
        search_frame.pack(padx=5, pady=5, fill="x")
        
        ttk.Label(search_frame, text="搜索条件:").pack(side="left", padx=5)
        self.search_entry = ttk.Entry(search_frame)
        self.search_entry.pack(side="left", padx=5, fill="x", expand=True)
        
        ttk.Button(search_frame, text="搜索", command=self.search_orders).pack(side="left", padx=5)
        
    def add_function_buttons(self):
        # 在原有btn_frame中添加更多按钮
        ttk.Button(self.btn_frame, text="编辑", command=self.edit_selected).pack(side="left", padx=5)
        ttk.Button(self.btn_frame, text="删除", command=self.delete_selected).pack(side="left", padx=5)
        ttk.Button(self.btn_frame, text="导出Excel", command=self.export_to_excel).pack(side="left", padx=5)
        ttk.Button(self.btn_frame, text="统计报表", command=self.show_statistics).pack(side="left", padx=5)

    def validate_data(self):
        """数据验证"""
        errors = []
        
        # 验证日期格式
        date = self.entries['order_date'].get().strip()
        if not date:
            errors.append("单据日期不能为空")
        elif not re.match(r'^\d{4}-\d{2}-\d{2}$', date):
            errors.append("单据日期格式错误,应为 YYYY-MM-DD")
        
        # 验证必填字段
        required_fields = {
            'order_number': '单据编号',
            'customer': '客户名称',
            'product': '品名规格',
            'unit': '单位',
            'quantity': '数量',
            'price': '原价'
        }
        
        for field, name in required_fields.items():
            value = self.entries[field].get().strip()
            if not value:
                errors.append(f"{name}不能为空")
        
        # 验证数字字段
        number_fields = {
            'quantity': '数量',
            'price': '原价',
            'discount': '单行折扣率(%)',
            'final_price': '折后价',
            'total': '金额',
            'discount_amount': '整单折扣率(%)',
            'discount_total': '折后金额',
            'payment_received': '本单已收'
        }
        
        for field, name in number_fields.items():
            value = self.entries[field].get().strip()
            if value:  # 如果有值才验证
                try:
                    num = float(value)
                    if field in ['quantity', 'price'] and num <= 0:
                        errors.append(f"{name}必须大于0")
                    elif num < 0:
                        errors.append(f"{name}不能为负数")
                except ValueError:
                    errors.append(f"{name}必须是数字")
        
        if errors:
            messagebox.showerror("验证错误", "\n".join(errors))
            return False
        return True

    def save_order(self):
        """保存订单数据"""
        if not self.validate_data():
            return
        
        try:
            # 获取所有输入值
            values = []
            fields_order = [
                'order_date', 'order_number', 'customer', 'product', 'unit',
                'quantity', 'price', 'discount', 'final_price', 'total',
                'remarks', 'discount_amount', 'discount_total', 'delivery',
                'payment_received', 'end_customer', 'notes', 'business'
            ]
            
            for field in fields_order:
                value = self.entries[field].get().strip()
                
                # 对数字字段进行转换
                if field in ['quantity', 'price', 'discount', 'final_price', 'total', 
                            'discount_amount', 'discount_total', 'payment_received']:
                    try:
                        value = float(value) if value else 0.0
                    except ValueError:
                        value = 0.0
                elif not value:  # 对非数字字段,如果为空则设为空字符串
                    value = ''
                
                values.append(value)
            
            # 检查单据编号是否重复
            cursor = self.conn.cursor()
            cursor.execute('SELECT COUNT(*) FROM orders WHERE order_number = ?', (values[1],))
            if cursor.fetchone()[0] > 0:
                if not messagebox.askyesno("警告", "单据编号已存在是否继续保存?"):
                    return
            
            # 插入数据
            try:
                cursor.execute('''
                INSERT INTO orders VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
                ''', values)
                self.conn.commit()
                
                # 更新表格显示
                self.tree.insert("", "end", values=values)
                
                # 清空输入框并设置默认值
                self.set_default_values()
                
                # 显示成功消息
                messagebox.showinfo("成功", "订单保存成功!")
                
            except sqlite3.Error as e:
                self.conn.rollback()
                messagebox.showerror("数据库错误", f"保存失败:{str(e)}")
                return
                
        except Exception as e:
            messagebox.showerror("错误", f"保存过程中出错:{str(e)}")
            return
        
        self.update_order_groups()

    def clear_fields(self):
        """清空所有输入框"""
        for field in self.entries:
            self.entries[field].delete(0, tk.END)

    def __del__(self):
        self.conn.close()

    def search_orders(self):
        search_text = self.search_entry.get().strip()
        if not search_text:
            self.load_all_orders()
            return
            
        cursor = self.conn.cursor()
        cursor.execute('''
        SELECT * FROM orders 
        WHERE order_date LIKE ? OR order_number LIKE ? OR customer LIKE ? OR product LIKE ?
        ''', [f'%{search_text}%'] * 4)
        
        self.tree.delete(*self.tree.get_children())
        for row in cursor.fetchall():
            self.tree.insert("", "end", values=row)

    def edit_selected(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一条记录")
            return
            
        item = self.tree.item(selected[0])
        values = item['values']
        
        # 填充表单
        for field, value in zip(self.entries.keys(), values):
            self.entries[field].delete(0, tk.END)
            self.entries[field].insert(0, str(value))

    def delete_selected(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选择一条记录")
            return
            
        if messagebox.askyesno("确认", "确定要删除中的记录吗?"):
            item = self.tree.item(selected[0])
            order_number = item['values'][1]
            
            cursor = self.conn.cursor()
            cursor.execute('DELETE FROM orders WHERE order_number = ?', (order_number,))
            self.conn.commit()
            
            self.tree.delete(selected[0])
        
        self.update_order_groups()

    def export_to_excel(self):
        """导出数据到Excel"""
        try:
            # 先获取保存路径
            filename = filedialog.asksaveasfilename(
                defaultextension=".xlsx",
                filetypes=[("Excel files", "*.xlsx")]
            )
            if not filename:
                return
            
            # 获取数据
            cursor = self.conn.cursor()
            cursor.execute('SELECT * FROM orders')
            data = cursor.fetchall()
            
            # 准备列名
            columns = [
                '单据日期', '单据编号', '客户名称', '品名规格',
                '单位', '数量', '原价', '单行折扣率(%)', '折后价', 
                '金额', '备注', '整单折扣率(%)', '折后金额', '运费',
                '本单已收', '结算账户', '说明', '营业员'
            ]
            
            # 创建DataFrame
            df = pd.DataFrame(data, columns=columns)
            
            # 直接导出
            df.to_excel(filename, index=False)
            messagebox.showinfo("成功", "数据已导出到Excel文件")
            
        except PermissionError:
            messagebox.showerror("错误", "无法保存文件,请确保:\n1. 文件未被其他程序打开\n2. 您有写入权限")
        except Exception as e:
            messagebox.showerror("错误", f"导出过程中出错:{str(e)}")

    def show_statistics(self):
        stats_window = tk.Toplevel(self.root)
        stats_window.title("统计报表")
        
        cursor = self.conn.cursor()
        
        # 客户统计
        cursor.execute('''
        SELECT customer, 
               COUNT(*) as order_count,
               SUM(total) as total_amount,
               SUM(payment_received) as t
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值