feat: 实现月底/月初数据调整功能
1. 新增月底/月初智能数据调整功能 - 月底最后一天自动弹出剔除数据对话框 - 月初1号自动弹出添加数据对话框 - 普通日期不弹出对话框 2. 实现月底剔除数据自动转移到次月1号 - 月底剔除的数据自动添加到次月1号统计 - 支持跨月、跨年数据转移 - 数据备注自动记录转移信息 3. 修复自动获取数据后不弹出调整对话框的问题 - 修改auto_fetch_data()方法,成功获取数据后调用调整处理 - 确保第一次打开GUI也能弹出相应对话框 4. 修复月度统计不包含调整数据的问题 - 修改get_monthly_stats()方法包含手动调整数据 - 确保调整数据正确影响月度统计 5. 恢复日报原始模板格式 - 移除调整数据的详细说明 - 保持原始日报模板,只显示最终结果 6. 数据库增强 - 新增manual_adjustments表存储手动调整数据 - 实现调整数据的增删改查方法 - 实现包含调整数据的每日数据获取方法 测试通过:所有功能正常工作,数据计算准确。
This commit is contained in:
@@ -100,6 +100,25 @@ class DailyLogsDatabase(DatabaseBase):
|
||||
)
|
||||
''')
|
||||
|
||||
# 创建手动调整数据表
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS manual_adjustments (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL, -- 调整适用的日期
|
||||
ship_name TEXT NOT NULL, -- 船名
|
||||
teu INTEGER NOT NULL, -- TEU数量
|
||||
twenty_feet INTEGER DEFAULT 0, -- 20尺箱量
|
||||
forty_feet INTEGER DEFAULT 0, -- 40尺箱量
|
||||
adjustment_type TEXT NOT NULL, -- 'add' 或 'exclude'
|
||||
note TEXT, -- 备注
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
''')
|
||||
|
||||
# 创建索引
|
||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_manual_date ON manual_adjustments(date)')
|
||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_manual_type ON manual_adjustments(adjustment_type)')
|
||||
|
||||
conn.commit()
|
||||
logger.debug("数据库表结构初始化完成")
|
||||
|
||||
@@ -292,6 +311,74 @@ class DailyLogsDatabase(DatabaseBase):
|
||||
result = self.execute_query(query, (year_month,))
|
||||
return result[0]['teu'] if result else 0
|
||||
|
||||
def reduce_unaccounted(self, year_month: str, teu_to_reduce: int) -> bool:
|
||||
"""
|
||||
减少指定月份的未统计数据
|
||||
|
||||
参数:
|
||||
year_month: 年月字符串,格式 "2025-12"
|
||||
teu_to_reduce: 要减少的TEU数量
|
||||
|
||||
返回:
|
||||
是否成功
|
||||
"""
|
||||
try:
|
||||
# 先获取当前值
|
||||
current_teu = self.get_unaccounted(year_month)
|
||||
|
||||
# 计算新值(允许负数)
|
||||
new_teu = current_teu - teu_to_reduce
|
||||
|
||||
if new_teu == 0:
|
||||
# 如果减少后等于0,则删除记录
|
||||
query = 'DELETE FROM monthly_unaccounted WHERE year_month = ?'
|
||||
self.execute_update(query, (year_month,))
|
||||
logger.info(f"减少未统计数据后删除记录: {year_month},原值: {current_teu}TEU,减少: {teu_to_reduce}TEU,新值: 0TEU")
|
||||
else:
|
||||
# 更新记录(允许负数)
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO monthly_unaccounted
|
||||
(year_month, teu, note, created_at)
|
||||
VALUES (?, ?, ?, CURRENT_TIMESTAMP)
|
||||
'''
|
||||
# 保留原有备注
|
||||
note_query = 'SELECT note FROM monthly_unaccounted WHERE year_month = ?'
|
||||
note_result = self.execute_query(note_query, (year_month,))
|
||||
note = note_result[0]['note'] if note_result else ''
|
||||
|
||||
self.execute_update(query, (year_month, new_teu, note))
|
||||
logger.info(f"减少未统计数据: {year_month},原值: {current_teu}TEU,减少: {teu_to_reduce}TEU,新值: {new_teu}TEU")
|
||||
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"减少未统计数据失败: {e}")
|
||||
return False
|
||||
|
||||
def delete_unaccounted(self, year_month: str) -> bool:
|
||||
"""
|
||||
删除指定月份的未统计数据
|
||||
|
||||
参数:
|
||||
year_month: 年月字符串,格式 "2025-12"
|
||||
|
||||
返回:
|
||||
是否成功删除(如果记录不存在也返回True)
|
||||
"""
|
||||
try:
|
||||
query = 'DELETE FROM monthly_unaccounted WHERE year_month = ?'
|
||||
result = self.execute_update(query, (year_month,))
|
||||
if result > 0:
|
||||
logger.info(f"删除未统计数据: {year_month}")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"未找到 {year_month} 月的未统计数据")
|
||||
return True # 记录不存在也算成功
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"删除未统计数据失败: {e}")
|
||||
return False
|
||||
|
||||
def delete_by_date(self, date: str) -> int:
|
||||
"""
|
||||
删除指定日期的记录
|
||||
@@ -304,6 +391,196 @@ class DailyLogsDatabase(DatabaseBase):
|
||||
"""
|
||||
query = 'DELETE FROM daily_handover_logs WHERE date = ?'
|
||||
return self.execute_update(query, (date,))
|
||||
|
||||
def insert_manual_adjustment(self, date: str, ship_name: str, teu: int,
|
||||
twenty_feet: int = 0, forty_feet: int = 0,
|
||||
adjustment_type: str = 'add', note: str = '') -> bool:
|
||||
"""
|
||||
插入手动调整数据
|
||||
|
||||
参数:
|
||||
date: 日期字符串
|
||||
ship_name: 船名
|
||||
teu: TEU数量
|
||||
twenty_feet: 20尺箱量
|
||||
forty_feet: 40尺箱量
|
||||
adjustment_type: 调整类型 'add' 或 'exclude'
|
||||
note: 备注
|
||||
|
||||
返回:
|
||||
是否成功
|
||||
"""
|
||||
try:
|
||||
query = '''
|
||||
INSERT INTO manual_adjustments
|
||||
(date, ship_name, teu, twenty_feet, forty_feet, adjustment_type, note, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||
'''
|
||||
params = (date, ship_name, teu, twenty_feet, forty_feet, adjustment_type, note)
|
||||
self.execute_update(query, params)
|
||||
logger.info(f"插入手动调整数据: {date} {ship_name} {teu}TEU ({adjustment_type})")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"插入手动调整数据失败: {e}")
|
||||
return False
|
||||
|
||||
def get_manual_adjustments(self, date: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取指定日期的所有手动调整数据
|
||||
|
||||
参数:
|
||||
date: 日期字符串
|
||||
|
||||
返回:
|
||||
手动调整数据列表
|
||||
"""
|
||||
query = '''
|
||||
SELECT * FROM manual_adjustments
|
||||
WHERE date = ? ORDER BY created_at DESC
|
||||
'''
|
||||
return self.execute_query(query, (date,))
|
||||
|
||||
def get_manual_adjustments_by_type(self, date: str, adjustment_type: str) -> List[Dict[str, Any]]:
|
||||
"""
|
||||
获取指定日期和类型的调整数据
|
||||
|
||||
参数:
|
||||
date: 日期字符串
|
||||
adjustment_type: 调整类型 'add' 或 'exclude'
|
||||
|
||||
返回:
|
||||
手动调整数据列表
|
||||
"""
|
||||
query = '''
|
||||
SELECT * FROM manual_adjustments
|
||||
WHERE date = ? AND adjustment_type = ? ORDER BY created_at DESC
|
||||
'''
|
||||
return self.execute_query(query, (date, adjustment_type))
|
||||
|
||||
def delete_manual_adjustment(self, adjustment_id: int) -> bool:
|
||||
"""
|
||||
删除指定ID的手动调整数据
|
||||
|
||||
参数:
|
||||
adjustment_id: 调整记录ID
|
||||
|
||||
返回:
|
||||
是否成功删除
|
||||
"""
|
||||
try:
|
||||
query = 'DELETE FROM manual_adjustments WHERE id = ?'
|
||||
result = self.execute_update(query, (adjustment_id,))
|
||||
if result > 0:
|
||||
logger.info(f"删除手动调整数据: ID={adjustment_id}")
|
||||
return True
|
||||
else:
|
||||
logger.warning(f"未找到手动调整数据: ID={adjustment_id}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"删除手动调整数据失败: {e}")
|
||||
return False
|
||||
|
||||
def clear_manual_adjustments(self, date: str) -> int:
|
||||
"""
|
||||
清除指定日期的所有手动调整数据
|
||||
|
||||
参数:
|
||||
date: 日期字符串
|
||||
|
||||
返回:
|
||||
删除的记录数
|
||||
"""
|
||||
query = 'DELETE FROM manual_adjustments WHERE date = ?'
|
||||
result = self.execute_update(query, (date,))
|
||||
logger.info(f"清除 {date} 的手动调整数据: {result} 条记录")
|
||||
return result
|
||||
|
||||
def get_daily_data_with_adjustments(self, date: str) -> Dict[str, Any]:
|
||||
"""
|
||||
获取指定日期的数据(包含手动调整)
|
||||
|
||||
参数:
|
||||
date: 日期字符串
|
||||
|
||||
返回:
|
||||
包含调整的每日数据字典
|
||||
"""
|
||||
try:
|
||||
# 获取原始数据
|
||||
logs = self.query_by_date(date)
|
||||
|
||||
# 获取手动调整数据
|
||||
adjustments = self.get_manual_adjustments(date)
|
||||
|
||||
# 按船名汇总原始数据
|
||||
ships: Dict[str, Dict[str, Any]] = {}
|
||||
for log in logs:
|
||||
ship = log['ship_name']
|
||||
if ship not in ships:
|
||||
ships[ship] = {
|
||||
'teu': 0,
|
||||
'twenty_feet': 0,
|
||||
'forty_feet': 0,
|
||||
'adjustments': []
|
||||
}
|
||||
if log.get('teu'):
|
||||
ships[ship]['teu'] += log['teu']
|
||||
if log.get('twenty_feet'):
|
||||
ships[ship]['twenty_feet'] += log['twenty_feet']
|
||||
if log.get('forty_feet'):
|
||||
ships[ship]['forty_feet'] += log['forty_feet']
|
||||
|
||||
# 应用调整数据
|
||||
total_adjustment_teu = 0
|
||||
for adj in adjustments:
|
||||
ship = adj['ship_name']
|
||||
if ship not in ships:
|
||||
ships[ship] = {
|
||||
'teu': 0,
|
||||
'twenty_feet': 0,
|
||||
'forty_feet': 0,
|
||||
'adjustments': []
|
||||
}
|
||||
|
||||
# 记录调整
|
||||
ships[ship]['adjustments'].append(adj)
|
||||
|
||||
# 根据调整类型计算
|
||||
if adj['adjustment_type'] == 'add':
|
||||
ships[ship]['teu'] += adj['teu']
|
||||
ships[ship]['twenty_feet'] += adj['twenty_feet']
|
||||
ships[ship]['forty_feet'] += adj['forty_feet']
|
||||
total_adjustment_teu += adj['teu']
|
||||
elif adj['adjustment_type'] == 'exclude':
|
||||
ships[ship]['teu'] -= adj['teu']
|
||||
ships[ship]['twenty_feet'] -= adj['twenty_feet']
|
||||
ships[ship]['forty_feet'] -= adj['forty_feet']
|
||||
total_adjustment_teu -= adj['teu']
|
||||
|
||||
# 计算总TEU
|
||||
total_teu = sum(ship_data['teu'] for ship_data in ships.values())
|
||||
|
||||
return {
|
||||
'date': date,
|
||||
'ships': ships,
|
||||
'total_teu': total_teu,
|
||||
'ship_count': len(ships),
|
||||
'adjustments': adjustments,
|
||||
'total_adjustment_teu': total_adjustment_teu
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"获取包含调整的每日数据失败: {date}, 错误: {e}")
|
||||
return {
|
||||
'date': date,
|
||||
'ships': {},
|
||||
'total_teu': 0,
|
||||
'ship_count': 0,
|
||||
'adjustments': [],
|
||||
'total_adjustment_teu': 0
|
||||
}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
Reference in New Issue
Block a user