| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516 |
- """
- 数据库操作模块
- 使用SQLite存储地磅单、公司名称、货物名称等数据
- 同时支持MySQL数据库存储(双数据库写入)
- """
- import sqlite3
- import os
- import sys
- from datetime import datetime
- from typing import List, Dict, Optional, Tuple
- import logging
- # 尝试导入MySQL相关模块
- try:
- import pymysql
- PYMySQL_AVAILABLE = True
- except ImportError:
- PYMySQL_AVAILABLE = False
- # 尝试导入配置模块
- try:
- import config
- MYSQL_ENABLED = getattr(config, 'ENABLE_MYSQL', False) and PYMySQL_AVAILABLE
- MYSQL_CONFIG = getattr(config, 'MYSQL_CONFIG', {})
- CONTINUE_ON_MYSQL_ERROR = getattr(config, 'CONTINUE_ON_MYSQL_ERROR', True)
- except ImportError:
- MYSQL_ENABLED = False
- MYSQL_CONFIG = {}
- CONTINUE_ON_MYSQL_ERROR = True
- # 配置日志 - 设置为INFO级别以便看到MySQL操作信息
- logging.basicConfig(
- level=logging.INFO,
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
- )
- logger = logging.getLogger(__name__)
- def get_base_path():
- """
- 获取程序运行的基础路径
- 在开发环境中返回脚本所在目录,在打包后返回exe所在目录
- """
- if getattr(sys, 'frozen', False):
- # 打包后的exe环境
- return os.path.dirname(sys.executable)
- else:
- # 开发环境
- return os.path.dirname(os.path.abspath(__file__))
- class Database:
- """数据库操作类,支持SQLite和MySQL双数据库存储"""
-
- def __init__(self, db_path: str = None):
- """
- 初始化数据库连接
- :param db_path: 数据库文件路径,如果为None则使用默认路径(exe同目录下的dibang.db)
- """
- if db_path is None:
- # 使用exe同目录下的dibang.db
- base_path = get_base_path()
- db_path = os.path.join(base_path, "dibang.db")
- self.db_path = db_path
- self.mysql_enabled = MYSQL_ENABLED
- self.mysql_connection = None
- self.init_database()
-
- def get_connection(self) -> sqlite3.Connection:
- """获取SQLite数据库连接"""
- conn = sqlite3.connect(self.db_path)
- conn.row_factory = sqlite3.Row # 使查询结果可以通过列名访问
- return conn
-
- def get_mysql_connection(self, force_reconnect: bool = False):
- """
- 获取MySQL数据库连接
- :param force_reconnect: 是否强制重新连接(用于确保读取最新数据)
- :return: MySQL连接对象
- """
- if not self.mysql_enabled:
- return None
- try:
- # 如果强制重新连接,先关闭旧连接
- if force_reconnect and self.mysql_connection is not None:
- try:
- self.mysql_connection.close()
- logger.info("强制重新建立MySQL连接以获取最新数据")
- except:
- pass
- self.mysql_connection = None
-
- # 检查连接是否存在且有效
- if self.mysql_connection is None:
- self.mysql_connection = pymysql.connect(
- host=MYSQL_CONFIG.get('host', 'localhost'),
- port=MYSQL_CONFIG.get('port', 3306),
- user=MYSQL_CONFIG.get('user', 'root'),
- password=MYSQL_CONFIG.get('password', ''),
- database=MYSQL_CONFIG.get('database', 'dibang'),
- charset=MYSQL_CONFIG.get('charset', 'utf8mb4'),
- cursorclass=pymysql.cursors.DictCursor,
- autocommit=False
- )
- else:
- # 检查连接是否有效
- try:
- self.mysql_connection.ping(reconnect=True)
- except Exception as ping_error:
- # 连接失效,重新连接
- logger.info(f"MySQL连接失效,重新连接: {str(ping_error)}")
- try:
- self.mysql_connection.close()
- except:
- pass
- self.mysql_connection = pymysql.connect(
- host=MYSQL_CONFIG.get('host', 'localhost'),
- port=MYSQL_CONFIG.get('port', 3306),
- user=MYSQL_CONFIG.get('user', 'root'),
- password=MYSQL_CONFIG.get('password', ''),
- database=MYSQL_CONFIG.get('database', 'dibang'),
- charset=MYSQL_CONFIG.get('charset', 'utf8mb4'),
- cursorclass=pymysql.cursors.DictCursor,
- autocommit=False
- )
- return self.mysql_connection
- except Exception as e:
- logger.warning(f"MySQL连接失败: {str(e)}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
- return None
-
- def _execute_mysql(self, sql: str, params: tuple = None):
- """执行MySQL语句(内部方法)"""
- if not self.mysql_enabled:
- return
- conn = self.get_mysql_connection()
- if conn is None:
- return
- try:
- with conn.cursor() as cursor:
- cursor.execute(sql, params)
- conn.commit()
- except Exception as e:
- logger.warning(f"MySQL执行失败: {str(e)}, SQL: {sql}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
- try:
- conn.rollback()
- except:
- pass
-
- def init_database(self):
- """初始化数据库表结构"""
- conn = self.get_connection()
- cursor = conn.cursor()
-
- # 创建地磅单表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS weighing_slips (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- vehicle_no TEXT NOT NULL,
- plan_no TEXT,
- cargo_name TEXT NOT NULL,
- business_type TEXT NOT NULL,
- batch_no TEXT,
- supplier TEXT NOT NULL,
- consignee TEXT NOT NULL,
- gross_weight REAL NOT NULL,
- gross_weight_time TEXT NOT NULL,
- tare_weight REAL NOT NULL,
- tare_weight_time TEXT NOT NULL,
- deduction REAL DEFAULT 0,
- net_weight REAL NOT NULL,
- planned_quantity REAL,
- executed_quantity REAL,
- weighing_point TEXT DEFAULT '山峡地磅',
- remarks TEXT,
- is_voided INTEGER DEFAULT 0,
- created_at TEXT NOT NULL
- )
- """)
-
- # 创建公司名称表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS companies (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- name TEXT NOT NULL UNIQUE,
- created_at TEXT NOT NULL
- )
- """)
-
- # 创建货物名称表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS cargos (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- name TEXT NOT NULL UNIQUE,
- created_at TEXT NOT NULL
- )
- """)
-
- # 创建采购计划表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS purchase_plans (
- id INTEGER PRIMARY KEY AUTOINCREMENT,
- plan_date TEXT NOT NULL,
- business_type TEXT NOT NULL,
- product TEXT NOT NULL,
- specification TEXT,
- planned_quantity REAL NOT NULL,
- vehicle_no TEXT NOT NULL,
- customer_name TEXT,
- remarks TEXT,
- created_at TEXT NOT NULL
- )
- """)
-
- # 如果表已存在但没有customer_name字段,则添加该字段
- try:
- cursor.execute("ALTER TABLE purchase_plans ADD COLUMN customer_name TEXT")
- except sqlite3.OperationalError:
- # 字段已存在,忽略错误
- pass
-
- # 如果表已存在但没有remarks字段,则添加该字段
- try:
- cursor.execute("ALTER TABLE purchase_plans ADD COLUMN remarks TEXT")
- except sqlite3.OperationalError:
- # 字段已存在,忽略错误
- pass
-
- conn.commit()
- conn.close()
-
- # 初始化MySQL数据库表结构
- if self.mysql_enabled:
- self._init_mysql_database()
-
- def _init_mysql_database(self):
- """初始化MySQL数据库表结构"""
- conn = self.get_mysql_connection()
- if conn is None:
- return
-
- try:
- with conn.cursor() as cursor:
- # 创建地磅单表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS weighing_slips (
- id INT PRIMARY KEY AUTO_INCREMENT,
- vehicle_no VARCHAR(255) NOT NULL,
- plan_no VARCHAR(255),
- cargo_name VARCHAR(255) NOT NULL,
- business_type VARCHAR(255) NOT NULL,
- batch_no VARCHAR(255),
- supplier VARCHAR(255) NOT NULL,
- consignee VARCHAR(255) NOT NULL,
- gross_weight DOUBLE NOT NULL,
- gross_weight_time VARCHAR(255) NOT NULL,
- tare_weight DOUBLE NOT NULL,
- tare_weight_time VARCHAR(255) NOT NULL,
- deduction DOUBLE DEFAULT 0,
- net_weight DOUBLE NOT NULL,
- planned_quantity DOUBLE,
- executed_quantity DOUBLE,
- weighing_point VARCHAR(255) DEFAULT '山峡地磅',
- remarks TEXT,
- is_voided INT DEFAULT 0,
- created_at VARCHAR(255) NOT NULL
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- """)
-
- # 创建公司名称表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS companies (
- id INT PRIMARY KEY AUTO_INCREMENT,
- name VARCHAR(255) NOT NULL UNIQUE,
- created_at VARCHAR(255) NOT NULL
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- """)
-
- # 创建货物名称表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS cargos (
- id INT PRIMARY KEY AUTO_INCREMENT,
- name VARCHAR(255) NOT NULL UNIQUE,
- created_at VARCHAR(255) NOT NULL
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- """)
-
- # 创建采购计划表
- cursor.execute("""
- CREATE TABLE IF NOT EXISTS purchase_plans (
- id INT PRIMARY KEY AUTO_INCREMENT,
- plan_date VARCHAR(255) NOT NULL,
- business_type VARCHAR(255) NOT NULL,
- product VARCHAR(255) NOT NULL,
- specification VARCHAR(255),
- planned_quantity DOUBLE NOT NULL,
- vehicle_no VARCHAR(255) NOT NULL,
- customer_name VARCHAR(255),
- remarks TEXT,
- created_at VARCHAR(255) NOT NULL
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
- """)
-
- # 检查并添加customer_name字段(如果不存在)
- try:
- cursor.execute("ALTER TABLE purchase_plans ADD COLUMN customer_name VARCHAR(255)")
- except:
- pass # 字段已存在,忽略错误
-
- # 检查并添加remarks字段(如果不存在)
- try:
- cursor.execute("ALTER TABLE purchase_plans ADD COLUMN remarks TEXT")
- except:
- pass # 字段已存在,忽略错误
-
- conn.commit()
- except Exception as e:
- logger.warning(f"MySQL表初始化失败: {str(e)}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
- try:
- conn.rollback()
- except:
- pass
-
- # ========== 地磅单相关操作 ==========
-
- def insert_weighing_slip(self, data: Dict) -> int:
- """
- 插入地磅单记录
- :param data: 地磅单数据字典
- :return: 插入记录的ID
- """
- # 计算净重
- net_weight = data['gross_weight'] - data['tare_weight'] - data.get('deduction', 0)
- created_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
-
- record_id = None
-
- # 先操作MySQL,获取MySQL生成的ID
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- INSERT INTO weighing_slips (
- vehicle_no, plan_no, cargo_name, business_type, batch_no,
- supplier, consignee, gross_weight, gross_weight_time,
- tare_weight, tare_weight_time, deduction, net_weight,
- planned_quantity, executed_quantity, weighing_point, remarks,
- is_voided, created_at
- ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
- """, (
- data['vehicle_no'],
- data.get('plan_no', ''),
- data['cargo_name'],
- data['business_type'],
- data.get('batch_no', ''),
- data['supplier'],
- data['consignee'],
- data['gross_weight'],
- data['gross_weight_time'],
- data['tare_weight'],
- data['tare_weight_time'],
- data.get('deduction', 0),
- net_weight,
- data.get('planned_quantity'),
- data.get('executed_quantity'),
- data.get('weighing_point', '山峡地磅'),
- data.get('remarks', ''),
- 0, # is_voided
- created_at
- ))
- record_id = mysql_cursor.lastrowid
- mysql_conn.commit()
- except Exception as e:
- logger.warning(f"MySQL插入地磅单失败: {str(e)}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 如果MySQL失败或未启用,使用SQLite生成ID
- if record_id is None:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO weighing_slips (
- vehicle_no, plan_no, cargo_name, business_type, batch_no,
- supplier, consignee, gross_weight, gross_weight_time,
- tare_weight, tare_weight_time, deduction, net_weight,
- planned_quantity, executed_quantity, weighing_point, remarks,
- is_voided, created_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- """, (
- data['vehicle_no'],
- data.get('plan_no', ''),
- data['cargo_name'],
- data['business_type'],
- data.get('batch_no', ''),
- data['supplier'],
- data['consignee'],
- data['gross_weight'],
- data['gross_weight_time'],
- data['tare_weight'],
- data['tare_weight_time'],
- data.get('deduction', 0),
- net_weight,
- data.get('planned_quantity'),
- data.get('executed_quantity'),
- data.get('weighing_point', '山峡地磅'),
- data.get('remarks', ''),
- 0, # is_voided
- created_at
- ))
- record_id = cursor.lastrowid
- conn.commit()
- conn.close()
- else:
- # 使用MySQL的ID同步到SQLite
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO weighing_slips (
- id, vehicle_no, plan_no, cargo_name, business_type, batch_no,
- supplier, consignee, gross_weight, gross_weight_time,
- tare_weight, tare_weight_time, deduction, net_weight,
- planned_quantity, executed_quantity, weighing_point, remarks,
- is_voided, created_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- """, (
- record_id, # 使用MySQL返回的ID
- data['vehicle_no'],
- data.get('plan_no', ''),
- data['cargo_name'],
- data['business_type'],
- data.get('batch_no', ''),
- data['supplier'],
- data['consignee'],
- data['gross_weight'],
- data['gross_weight_time'],
- data['tare_weight'],
- data['tare_weight_time'],
- data.get('deduction', 0),
- net_weight,
- data.get('planned_quantity'),
- data.get('executed_quantity'),
- data.get('weighing_point', '山峡地磅'),
- data.get('remarks', ''),
- 0, # is_voided
- created_at
- ))
- conn.commit()
- conn.close()
-
- return record_id
-
- def get_all_weighing_slips(self, include_voided: bool = False) -> List[Dict]:
- """
- 获取所有地磅单记录
- :param include_voided: 是否包含作废的记录
- :return: 地磅单记录列表
- """
- # 先尝试从MySQL查询(强制重新连接以确保获取最新数据)
- if self.mysql_enabled:
- try:
- # 强制重新连接以确保读取最新数据
- mysql_conn = self.get_mysql_connection(force_reconnect=True)
- if mysql_conn:
- try:
- # 确保事务已提交
- mysql_conn.commit()
- # 设置隔离级别为READ COMMITTED
- with mysql_conn.cursor() as cursor:
- cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
-
- with mysql_conn.cursor() as mysql_cursor:
- if include_voided:
- mysql_cursor.execute("""
- SELECT * FROM weighing_slips
- ORDER BY id DESC
- """)
- else:
- mysql_cursor.execute("""
- SELECT * FROM weighing_slips
- WHERE is_voided = 0
- ORDER BY id DESC
- """)
- rows = mysql_cursor.fetchall()
- result = [dict(row) for row in rows]
- logger.info(f"✅ 从MySQL获取地磅单列表,共{len(result)}条记录")
- return result
- except Exception as query_error:
- logger.error(f"MySQL查询地磅单执行失败: {str(query_error)}", exc_info=True)
- raise
- else:
- logger.warning("⚠️ MySQL连接不可用,将从SQLite查询地磅单列表")
- except Exception as e:
- logger.warning(f"⚠️ MySQL查询地磅单失败,将从SQLite查询: {str(e)}", exc_info=True)
-
- # MySQL失败或未启用,从SQLite查询
- logger.info("从SQLite获取地磅单列表")
- conn = self.get_connection()
- cursor = conn.cursor()
-
- if include_voided:
- cursor.execute("""
- SELECT * FROM weighing_slips
- ORDER BY id DESC
- """)
- else:
- cursor.execute("""
- SELECT * FROM weighing_slips
- WHERE is_voided = 0
- ORDER BY id DESC
- """)
-
- rows = cursor.fetchall()
- conn.close()
-
- result = [dict(row) for row in rows]
- logger.info(f"从SQLite获取地磅单列表,共{len(result)}条记录")
- return result
-
- def get_weighing_slip_by_id(self, slip_id: int) -> Optional[Dict]:
- """
- 根据ID获取地磅单记录
- :param slip_id: 地磅单ID
- :return: 地磅单记录字典,如果不存在返回None
- """
- # 先尝试从MySQL查询
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("SELECT * FROM weighing_slips WHERE id = %s", (slip_id,))
- row = mysql_cursor.fetchone()
- if row:
- return dict(row)
- except Exception as e:
- logger.warning(f"MySQL查询地磅单失败,将从SQLite查询: {str(e)}")
-
- # MySQL失败或未启用,从SQLite查询
- conn = self.get_connection()
- cursor = conn.cursor()
-
- cursor.execute("SELECT * FROM weighing_slips WHERE id = ?", (slip_id,))
- row = cursor.fetchone()
- conn.close()
-
- return dict(row) if row else None
-
- def void_weighing_slip(self, slip_id: int) -> bool:
- """
- 作废地磅单
- :param slip_id: 地磅单ID
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- UPDATE weighing_slips
- SET is_voided = 1
- WHERE id = %s
- """, (slip_id,))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL作废地磅单成功: ID {slip_id}")
- else:
- logger.warning(f"MySQL作废地磅单: ID {slip_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法作废地磅单 ID {slip_id}")
- except Exception as e:
- logger.error(f"MySQL作废地磅单失败: ID {slip_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- UPDATE weighing_slips
- SET is_voided = 1
- WHERE id = ?
- """, (slip_id,))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite作废地磅单: ID {slip_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite作废地磅单失败: ID {slip_id}, 错误: {str(e)}")
-
- return success
-
- # ========== 公司名称相关操作 ==========
-
- def insert_company(self, name: str) -> int:
- """
- 插入公司名称
- :param name: 公司名称
- :return: 插入记录的ID
- """
- created_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- record_id = None
-
- # 先操作MySQL,获取MySQL生成的ID
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- INSERT INTO companies (name, created_at)
- VALUES (%s, %s)
- """, (name, created_at))
- record_id = mysql_cursor.lastrowid
- mysql_conn.commit()
- except Exception as e:
- logger.warning(f"MySQL插入公司失败: {str(e)}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 如果MySQL失败或未启用,使用SQLite生成ID
- if record_id is None:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO companies (name, created_at)
- VALUES (?, ?)
- """, (name, created_at))
- record_id = cursor.lastrowid
- conn.commit()
- conn.close()
- else:
- # 使用MySQL的ID同步到SQLite
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO companies (id, name, created_at)
- VALUES (?, ?, ?)
- """, (record_id, name, created_at))
- conn.commit()
- conn.close()
-
- return record_id
-
- def get_all_companies(self) -> List[Dict]:
- """
- 获取所有公司名称
- :return: 公司名称列表
- """
- # 先尝试从MySQL查询(强制重新连接以确保获取最新数据)
- if self.mysql_enabled:
- try:
- # 强制重新连接以确保读取最新数据
- mysql_conn = self.get_mysql_connection(force_reconnect=True)
- if mysql_conn:
- try:
- # 确保事务已提交
- mysql_conn.commit()
- # 设置隔离级别为READ COMMITTED
- with mysql_conn.cursor() as cursor:
- cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
-
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("SELECT * FROM companies ORDER BY name")
- rows = mysql_cursor.fetchall()
- result = [dict(row) for row in rows]
- logger.info(f"✅ 从MySQL获取公司列表,共{len(result)}条记录")
- return result
- except Exception as query_error:
- logger.error(f"MySQL查询公司执行失败: {str(query_error)}", exc_info=True)
- raise
- else:
- logger.warning("⚠️ MySQL连接不可用,将从SQLite查询公司列表")
- except Exception as e:
- logger.warning(f"⚠️ MySQL查询公司失败,将从SQLite查询: {str(e)}", exc_info=True)
-
- # MySQL失败或未启用,从SQLite查询
- logger.info("从SQLite获取公司列表")
- conn = self.get_connection()
- cursor = conn.cursor()
-
- cursor.execute("SELECT * FROM companies ORDER BY name")
- rows = cursor.fetchall()
- conn.close()
-
- result = [dict(row) for row in rows]
- logger.info(f"从SQLite获取公司列表,共{len(result)}条记录")
- return result
-
- def update_company(self, company_id: int, name: str) -> bool:
- """
- 更新公司名称
- :param company_id: 公司ID
- :param name: 新名称
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- UPDATE companies
- SET name = %s
- WHERE id = %s
- """, (name, company_id))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL更新公司成功: ID {company_id}, 新名称: {name}")
- else:
- logger.warning(f"MySQL更新公司: ID {company_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法更新公司 ID {company_id}")
- except Exception as e:
- logger.error(f"MySQL更新公司失败: ID {company_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- UPDATE companies
- SET name = ?
- WHERE id = ?
- """, (name, company_id))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite更新公司: ID {company_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite更新公司失败: ID {company_id}, 错误: {str(e)}")
-
- return success
-
- def delete_company(self, company_id: int) -> bool:
- """
- 删除公司名称
- :param company_id: 公司ID
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("DELETE FROM companies WHERE id = %s", (company_id,))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL删除公司成功: ID {company_id}")
- else:
- logger.warning(f"MySQL删除公司: ID {company_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法删除公司 ID {company_id}")
- except Exception as e:
- logger.error(f"MySQL删除公司失败: ID {company_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM companies WHERE id = ?", (company_id,))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite删除公司: ID {company_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite删除公司失败: ID {company_id}, 错误: {str(e)}")
-
- return success
-
- def is_company_used(self, company_id: int) -> bool:
- """
- 检查公司是否被地磅单引用
- :param company_id: 公司ID
- :return: 是否被引用
- """
- # 先尝试从MySQL查询
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- # 获取公司名称
- mysql_cursor.execute("SELECT name FROM companies WHERE id = %s", (company_id,))
- row = mysql_cursor.fetchone()
- if not row:
- return False
-
- company_name = row['name']
-
- # 检查是否在供货单位或收货单位中被使用
- mysql_cursor.execute("""
- SELECT COUNT(*) as count FROM weighing_slips
- WHERE supplier = %s OR consignee = %s
- """, (company_name, company_name))
-
- result = mysql_cursor.fetchone()
- return result['count'] > 0 if result else False
- except Exception as e:
- logger.warning(f"MySQL检查公司使用情况失败,将从SQLite查询: {str(e)}")
-
- # MySQL失败或未启用,从SQLite查询
- conn = self.get_connection()
- cursor = conn.cursor()
-
- # 获取公司名称
- cursor.execute("SELECT name FROM companies WHERE id = ?", (company_id,))
- row = cursor.fetchone()
- if not row:
- conn.close()
- return False
-
- company_name = row['name']
-
- # 检查是否在供货单位或收货单位中被使用
- cursor.execute("""
- SELECT COUNT(*) as count FROM weighing_slips
- WHERE supplier = ? OR consignee = ?
- """, (company_name, company_name))
-
- result = cursor.fetchone()
- conn.close()
- return result['count'] > 0
-
- def company_exists(self, name: str, exclude_id: Optional[int] = None) -> bool:
- """
- 检查公司名称是否存在
- :param name: 公司名称
- :param exclude_id: 排除的ID(用于修改时检查)
- :return: 是否存在
- """
- # 先尝试从MySQL查询
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- if exclude_id:
- mysql_cursor.execute("""
- SELECT COUNT(*) as count FROM companies
- WHERE name = %s AND id != %s
- """, (name, exclude_id))
- else:
- mysql_cursor.execute("""
- SELECT COUNT(*) as count FROM companies
- WHERE name = %s
- """, (name,))
-
- result = mysql_cursor.fetchone()
- return result['count'] > 0 if result else False
- except Exception as e:
- logger.warning(f"MySQL检查公司是否存在失败,将从SQLite查询: {str(e)}")
-
- # MySQL失败或未启用,从SQLite查询
- conn = self.get_connection()
- cursor = conn.cursor()
-
- if exclude_id:
- cursor.execute("""
- SELECT COUNT(*) as count FROM companies
- WHERE name = ? AND id != ?
- """, (name, exclude_id))
- else:
- cursor.execute("""
- SELECT COUNT(*) as count FROM companies
- WHERE name = ?
- """, (name,))
-
- result = cursor.fetchone()
- conn.close()
- return result['count'] > 0
-
- # ========== 货物名称相关操作 ==========
-
- def insert_cargo(self, name: str) -> int:
- """
- 插入货物名称
- :param name: 货物名称
- :return: 插入记录的ID
- """
- created_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- record_id = None
-
- # 先操作MySQL,获取MySQL生成的ID
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- INSERT INTO cargos (name, created_at)
- VALUES (%s, %s)
- """, (name, created_at))
- record_id = mysql_cursor.lastrowid
- mysql_conn.commit()
- except Exception as e:
- logger.warning(f"MySQL插入货物失败: {str(e)}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 如果MySQL失败或未启用,使用SQLite生成ID
- if record_id is None:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO cargos (name, created_at)
- VALUES (?, ?)
- """, (name, created_at))
- record_id = cursor.lastrowid
- conn.commit()
- conn.close()
- else:
- # 使用MySQL的ID同步到SQLite
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO cargos (id, name, created_at)
- VALUES (?, ?, ?)
- """, (record_id, name, created_at))
- conn.commit()
- conn.close()
-
- return record_id
-
- def get_all_cargos(self) -> List[Dict]:
- """
- 获取所有货物名称
- :return: 货物名称列表
- """
- # 先尝试从MySQL查询(强制重新连接以确保获取最新数据)
- if self.mysql_enabled:
- try:
- # 强制重新连接以确保读取最新数据
- mysql_conn = self.get_mysql_connection(force_reconnect=True)
- if mysql_conn:
- try:
- # 确保事务已提交,并设置隔离级别为READ COMMITTED以读取最新数据
- mysql_conn.commit() # 提交任何未提交的事务
- # 设置隔离级别为READ COMMITTED,确保读取已提交的最新数据
- with mysql_conn.cursor() as cursor:
- cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
-
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("SELECT * FROM cargos ORDER BY name")
- rows = mysql_cursor.fetchall()
- result = [dict(row) for row in rows]
- logger.info(f"✅ 从MySQL获取货物列表,共{len(result)}条记录")
- # 打印前几条记录用于调试
- if result:
- logger.info(f"示例:id={result[0].get('id')}, name={result[0].get('name')}")
- return result
- except Exception as query_error:
- logger.error(f"MySQL查询货物执行失败: {str(query_error)}", exc_info=True)
- raise
- else:
- logger.warning("⚠️ MySQL连接不可用(返回None),将从SQLite查询货物列表")
- except Exception as e:
- logger.warning(f"⚠️ MySQL查询货物失败,将从SQLite查询: {str(e)}", exc_info=True)
-
- # MySQL失败或未启用,从SQLite查询
- logger.info("ℹ️ 从SQLite获取货物列表")
- conn = self.get_connection()
- cursor = conn.cursor()
-
- cursor.execute("SELECT * FROM cargos ORDER BY name")
- rows = cursor.fetchall()
- conn.close()
-
- result = [dict(row) for row in rows]
- logger.info(f"从SQLite获取货物列表,共{len(result)}条记录")
- if result:
- logger.info(f"示例:id={result[0].get('id')}, name={result[0].get('name')}")
- return result
-
- def update_cargo(self, cargo_id: int, name: str) -> bool:
- """
- 更新货物名称
- :param cargo_id: 货物ID
- :param name: 新名称
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- UPDATE cargos
- SET name = %s
- WHERE id = %s
- """, (name, cargo_id))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL更新货物成功: ID {cargo_id}, 新名称: {name}")
- else:
- logger.warning(f"MySQL更新货物: ID {cargo_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法更新货物 ID {cargo_id}")
- except Exception as e:
- logger.error(f"MySQL更新货物失败: ID {cargo_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- UPDATE cargos
- SET name = ?
- WHERE id = ?
- """, (name, cargo_id))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite更新货物: ID {cargo_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite更新货物失败: ID {cargo_id}, 错误: {str(e)}")
-
- return success
-
- def delete_cargo(self, cargo_id: int) -> bool:
- """
- 删除货物名称
- :param cargo_id: 货物ID
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("DELETE FROM cargos WHERE id = %s", (cargo_id,))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL删除货物成功: ID {cargo_id}")
- else:
- logger.warning(f"MySQL删除货物: ID {cargo_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法删除货物 ID {cargo_id}")
- except Exception as e:
- logger.error(f"MySQL删除货物失败: ID {cargo_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM cargos WHERE id = ?", (cargo_id,))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite删除货物: ID {cargo_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite删除货物失败: ID {cargo_id}, 错误: {str(e)}")
-
- return success
-
- def is_cargo_used(self, cargo_id: int) -> bool:
- """
- 检查货物是否被地磅单引用
- :param cargo_id: 货物ID
- :return: 是否被引用
- """
- # 先尝试从MySQL查询
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- # 获取货物名称
- mysql_cursor.execute("SELECT name FROM cargos WHERE id = %s", (cargo_id,))
- row = mysql_cursor.fetchone()
- if not row:
- return False
-
- cargo_name = row['name']
-
- # 检查是否在地磅单中被使用
- mysql_cursor.execute("""
- SELECT COUNT(*) as count FROM weighing_slips
- WHERE cargo_name = %s
- """, (cargo_name,))
-
- result = mysql_cursor.fetchone()
- return result['count'] > 0 if result else False
- except Exception as e:
- logger.warning(f"MySQL检查货物使用情况失败,将从SQLite查询: {str(e)}")
-
- # MySQL失败或未启用,从SQLite查询
- conn = self.get_connection()
- cursor = conn.cursor()
-
- # 获取货物名称
- cursor.execute("SELECT name FROM cargos WHERE id = ?", (cargo_id,))
- row = cursor.fetchone()
- if not row:
- conn.close()
- return False
-
- cargo_name = row['name']
-
- # 检查是否在地磅单中被使用
- cursor.execute("""
- SELECT COUNT(*) as count FROM weighing_slips
- WHERE cargo_name = ?
- """, (cargo_name,))
-
- result = cursor.fetchone()
- conn.close()
- return result['count'] > 0
-
- def cargo_exists(self, name: str, exclude_id: Optional[int] = None) -> bool:
- """
- 检查货物名称是否存在
- :param name: 货物名称
- :param exclude_id: 排除的ID(用于修改时检查)
- :return: 是否存在
- """
- # 先尝试从MySQL查询
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- if exclude_id:
- mysql_cursor.execute("""
- SELECT COUNT(*) as count FROM cargos
- WHERE name = %s AND id != %s
- """, (name, exclude_id))
- else:
- mysql_cursor.execute("""
- SELECT COUNT(*) as count FROM cargos
- WHERE name = %s
- """, (name,))
-
- result = mysql_cursor.fetchone()
- return result['count'] > 0 if result else False
- except Exception as e:
- logger.warning(f"MySQL检查货物是否存在失败,将从SQLite查询: {str(e)}")
-
- # MySQL失败或未启用,从SQLite查询
- conn = self.get_connection()
- cursor = conn.cursor()
-
- if exclude_id:
- cursor.execute("""
- SELECT COUNT(*) as count FROM cargos
- WHERE name = ? AND id != ?
- """, (name, exclude_id))
- else:
- cursor.execute("""
- SELECT COUNT(*) as count FROM cargos
- WHERE name = ?
- """, (name,))
-
- result = cursor.fetchone()
- conn.close()
- return result['count'] > 0
-
- # ========== 采购计划相关操作 ==========
-
- def insert_purchase_plan(self, data: Dict) -> int:
- """
- 插入采购计划记录
- :param data: 采购计划数据字典
- :return: 插入记录的ID
- """
- created_at = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- record_id = None
-
- # 先操作MySQL,获取MySQL生成的ID
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- INSERT INTO purchase_plans (
- plan_date, business_type, product, specification,
- planned_quantity, vehicle_no, customer_name, remarks, created_at
- ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
- """, (
- data['plan_date'],
- data['business_type'],
- data['product'],
- data.get('specification', ''),
- data['planned_quantity'],
- data['vehicle_no'],
- data.get('customer_name', ''),
- data.get('remarks', ''),
- created_at
- ))
- record_id = mysql_cursor.lastrowid
- mysql_conn.commit()
- except Exception as e:
- logger.warning(f"MySQL插入采购计划失败: {str(e)}")
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 如果MySQL失败或未启用,使用SQLite生成ID
- if record_id is None:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO purchase_plans (
- plan_date, business_type, product, specification,
- planned_quantity, vehicle_no, customer_name, remarks, created_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
- """, (
- data['plan_date'],
- data['business_type'],
- data['product'],
- data.get('specification', ''),
- data['planned_quantity'],
- data['vehicle_no'],
- data.get('customer_name', ''),
- data.get('remarks', ''),
- created_at
- ))
- record_id = cursor.lastrowid
- conn.commit()
- conn.close()
- else:
- # 使用MySQL的ID同步到SQLite
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- INSERT INTO purchase_plans (
- id, plan_date, business_type, product, specification,
- planned_quantity, vehicle_no, customer_name, remarks, created_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- """, (
- record_id, # 使用MySQL返回的ID
- data['plan_date'],
- data['business_type'],
- data['product'],
- data.get('specification', ''),
- data['planned_quantity'],
- data['vehicle_no'],
- data.get('customer_name', ''),
- data.get('remarks', ''),
- created_at
- ))
- conn.commit()
- conn.close()
-
- return record_id
-
- def get_all_purchase_plans(self) -> List[Dict]:
- """
- 获取所有采购计划记录
- :return: 采购计划记录列表
- """
- # 先尝试从MySQL查询(强制重新连接以确保获取最新数据)
- if self.mysql_enabled:
- try:
- # 强制重新连接以确保读取最新数据
- mysql_conn = self.get_mysql_connection(force_reconnect=True)
- if mysql_conn:
- try:
- # 确保事务已提交
- mysql_conn.commit()
- # 设置隔离级别为READ COMMITTED
- with mysql_conn.cursor() as cursor:
- cursor.execute("SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")
-
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- SELECT * FROM purchase_plans
- ORDER BY plan_date DESC, created_at DESC
- """)
- rows = mysql_cursor.fetchall()
- result = [dict(row) for row in rows]
- logger.info(f"✅ 从MySQL获取采购计划列表,共{len(result)}条记录")
- return result
- except Exception as query_error:
- logger.error(f"MySQL查询采购计划执行失败: {str(query_error)}", exc_info=True)
- raise
- else:
- logger.warning("⚠️ MySQL连接不可用,将从SQLite查询采购计划列表")
- except Exception as e:
- logger.warning(f"⚠️ MySQL查询采购计划失败,将从SQLite查询: {str(e)}", exc_info=True)
-
- # MySQL失败或未启用,从SQLite查询
- logger.info("从SQLite获取采购计划列表")
- conn = self.get_connection()
- cursor = conn.cursor()
-
- cursor.execute("""
- SELECT * FROM purchase_plans
- ORDER BY plan_date DESC, created_at DESC
- """)
-
- rows = cursor.fetchall()
- conn.close()
-
- result = [dict(row) for row in rows]
- logger.info(f"从SQLite获取采购计划列表,共{len(result)}条记录")
- return result
-
- def get_purchase_plan_by_id(self, plan_id: int) -> Optional[Dict]:
- """
- 根据ID获取采购计划记录
- :param plan_id: 采购计划ID
- :return: 采购计划记录字典,如果不存在返回None
- """
- # 先尝试从MySQL查询
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("SELECT * FROM purchase_plans WHERE id = %s", (plan_id,))
- row = mysql_cursor.fetchone()
- if row:
- return dict(row)
- except Exception as e:
- logger.warning(f"MySQL查询采购计划失败,将从SQLite查询: {str(e)}")
-
- # MySQL失败或未启用,从SQLite查询
- conn = self.get_connection()
- cursor = conn.cursor()
-
- cursor.execute("SELECT * FROM purchase_plans WHERE id = ?", (plan_id,))
- row = cursor.fetchone()
- conn.close()
-
- return dict(row) if row else None
-
- def update_purchase_plan(self, plan_id: int, data: Dict) -> bool:
- """
- 更新采购计划记录
- :param plan_id: 采购计划ID
- :param data: 采购计划数据字典
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("""
- UPDATE purchase_plans
- SET plan_date = %s, business_type = %s, product = %s,
- specification = %s, planned_quantity = %s,
- vehicle_no = %s, customer_name = %s, remarks = %s
- WHERE id = %s
- """, (
- data['plan_date'],
- data['business_type'],
- data['product'],
- data.get('specification', ''),
- data['planned_quantity'],
- data['vehicle_no'],
- data.get('customer_name', ''),
- data.get('remarks', ''),
- plan_id
- ))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL更新采购计划成功: ID {plan_id}")
- else:
- logger.warning(f"MySQL更新采购计划: ID {plan_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法更新采购计划 ID {plan_id}")
- except Exception as e:
- logger.error(f"MySQL更新采购计划失败: ID {plan_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("""
- UPDATE purchase_plans
- SET plan_date = ?, business_type = ?, product = ?,
- specification = ?, planned_quantity = ?,
- vehicle_no = ?, customer_name = ?, remarks = ?
- WHERE id = ?
- """, (
- data['plan_date'],
- data['business_type'],
- data['product'],
- data.get('specification', ''),
- data['planned_quantity'],
- data['vehicle_no'],
- data.get('customer_name', ''),
- data.get('remarks', ''),
- plan_id
- ))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite更新采购计划: ID {plan_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite更新采购计划失败: ID {plan_id}, 错误: {str(e)}")
-
- return success
-
- def delete_purchase_plan(self, plan_id: int) -> bool:
- """
- 删除采购计划记录
- :param plan_id: 采购计划ID
- :return: 是否成功
- """
- success = False
-
- # 先操作MySQL
- if self.mysql_enabled:
- try:
- mysql_conn = self.get_mysql_connection()
- if mysql_conn:
- with mysql_conn.cursor() as mysql_cursor:
- mysql_cursor.execute("DELETE FROM purchase_plans WHERE id = %s", (plan_id,))
- affected_rows = mysql_cursor.rowcount
- mysql_conn.commit()
- if affected_rows > 0:
- success = True
- logger.info(f"MySQL删除采购计划成功: ID {plan_id}")
- else:
- logger.warning(f"MySQL删除采购计划: ID {plan_id} 未找到记录")
- else:
- logger.warning(f"MySQL连接失败,无法删除采购计划 ID {plan_id}")
- except Exception as e:
- logger.error(f"MySQL删除采购计划失败: ID {plan_id}, 错误: {str(e)}", exc_info=True)
- if not CONTINUE_ON_MYSQL_ERROR:
- raise
-
- # 同步到SQLite
- if success or not self.mysql_enabled:
- try:
- conn = self.get_connection()
- cursor = conn.cursor()
- cursor.execute("DELETE FROM purchase_plans WHERE id = ?", (plan_id,))
- sqlite_success = cursor.rowcount > 0
- conn.commit()
- conn.close()
- if self.mysql_enabled and not sqlite_success:
- logger.warning(f"SQLite删除采购计划: ID {plan_id} 未找到记录,可能ID不匹配")
- elif not self.mysql_enabled:
- success = sqlite_success
- except Exception as e:
- logger.error(f"SQLite删除采购计划失败: ID {plan_id}, 错误: {str(e)}")
-
- return success
|