ERP/import_reconciliation_excel.py

145 lines
5.2 KiB
Python
Raw Normal View History

2025-11-25 02:35:02 +00:00
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""从Excel导入对账单数据"""
import pandas as pd
import sqlite3
import os
from datetime import datetime, timezone, timedelta
# 数据库路径
DB_PATH = os.path.join(os.path.dirname(__file__), 'server', 'data.db')
EXCEL_FILE = '25年11月份对账单-易泰勒.xlsx'
def get_beijing_time():
"""获取北京时间UTC+8的ISO格式字符串"""
beijing_tz = timezone(timedelta(hours=8))
return datetime.now(beijing_tz).isoformat()
def import_from_excel():
"""从Excel导入对账单数据"""
# 读取Excel文件
df = pd.read_excel(EXCEL_FILE)
# 打印前20行查看结构
print("Excel文件结构:")
print("=" * 80)
for i in range(min(20, len(df))):
print(f"{i}行: {df.iloc[i].tolist()}")
print("=" * 80)
# 查找表头行(包含"序号"的行)
header_row = None
for i in range(len(df)):
row_values = df.iloc[i].tolist()
if any(str(val).strip() == '序号' for val in row_values if pd.notna(val)):
header_row = i
print(f"\n找到表头行: 第{i}")
print(f"表头内容: {row_values}")
break
if header_row is None:
print("❌ 未找到表头行(包含'序号'的行)")
return
# 重新读取,跳过前面的行,使用找到的行作为表头
df = pd.read_excel(EXCEL_FILE, skiprows=header_row)
# 设置第一行为列名
df.columns = df.iloc[0]
df = df[1:] # 删除第一行(已经作为列名)
df = df.reset_index(drop=True)
print(f"\n数据形状: {df.shape}")
print(f"列名: {df.columns.tolist()}")
print(f"\n前5行数据:")
print(df.head())
# 连接数据库
conn = sqlite3.connect(DB_PATH)
c = conn.cursor()
now = get_beijing_time()
imported_count = 0
# 遍历数据行
for idx, row in df.iterrows():
# 跳过空行或无效行
if pd.isna(row.get('序号')):
continue
try:
# 提取数据
# 处理日期格式
def format_date(date_val):
if pd.isna(date_val):
return ''
if isinstance(date_val, datetime):
return date_val.strftime('%Y/%m/%d')
date_str = str(date_val).strip()
# 如果已经是 YYYY/MM/DD 格式,保持不变
if '/' in date_str:
return date_str
# 如果是 YYYY-MM-DD 格式,转换为 YYYY/MM/DD
if '-' in date_str:
return date_str.split()[0].replace('-', '/')
return date_str
order_date = format_date(row.get('下单时间'))
contract_no = str(row.get('合同编号', '')).strip() if pd.notna(row.get('合同编号')) else ''
material_name = str(row.get('物料名称', '')).strip() if pd.notna(row.get('物料名称')) else ''
spec_model = str(row.get('规格型号', '')).strip() if pd.notna(row.get('规格型号')) else ''
transport_no = str(row.get('运输单号', '')).strip() if pd.notna(row.get('运输单号')) else ''
quantity = int(row.get('数量', 0)) if pd.notna(row.get('数量')) else 0
unit = str(row.get('单位', 'pcs')).strip() if pd.notna(row.get('单位')) else 'pcs'
unit_price = float(row.get('含税单价', 0)) if pd.notna(row.get('含税单价')) else 0.0
total_amount = float(row.get('含税金额', 0)) if pd.notna(row.get('含税金额')) else 0.0
delivery_date = format_date(row.get('交货日期'))
shipment_date = format_date(row.get('出货日期'))
# 验证必填字段
if not all([order_date, contract_no, material_name, spec_model, quantity, unit, unit_price]):
print(f"⚠️ 跳过第{idx+1}行: 缺少必填字段")
continue
# 插入数据库
c.execute('''
INSERT INTO reconciliations(
order_date, contract_no, material_name, spec_model, transport_no,
quantity, unit, unit_price, total_amount, delivery_date, shipment_date,
created_by, created_at, updated_at
) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?)
''', (
order_date,
contract_no,
material_name,
spec_model,
transport_no,
quantity,
unit,
unit_price,
total_amount,
delivery_date,
shipment_date,
'admin',
now,
now
))
imported_count += 1
print(f"✅ 导入第{idx+1}行: {contract_no} - {material_name}")
except Exception as e:
print(f"❌ 导入第{idx+1}行失败: {e}")
continue
conn.commit()
conn.close()
print(f"\n{'='*80}")
print(f"✅ 成功导入 {imported_count} 条对账单数据")
print(f"{'='*80}")
if __name__ == '__main__':
import_from_excel()