|
|
|
|
|
|
|
|
import_btn.pack(side="left", padx=3) |
|
|
import_btn.pack(side="left", padx=3) |
|
|
|
|
|
|
|
|
# 添加文件数量显示 |
|
|
# 添加文件数量显示 |
|
|
self.file_count_label = ttk.Label(button_frame, text="已选择: 0 个文件") |
|
|
|
|
|
|
|
|
self.file_count_label = ttk.Label(button_frame, text="已选择: 0 个员工") |
|
|
self.file_count_label.pack(side="left", padx=10) |
|
|
self.file_count_label.pack(side="left", padx=10) |
|
|
|
|
|
|
|
|
# 文件列表区域 |
|
|
# 文件列表区域 |
|
|
list_frame = ttk.Frame(import_frame) |
|
|
list_frame = ttk.Frame(import_frame) |
|
|
list_frame.pack(fill="both", expand=True) |
|
|
list_frame.pack(fill="both", expand=True) |
|
|
|
|
|
|
|
|
columns = ("filename", "employee", "company", "bank", "other") |
|
|
|
|
|
|
|
|
columns = ("employee", "company", "bank", "date", "match_status") |
|
|
self.file_tree = ttk.Treeview(list_frame, columns=columns, show="headings", selectmode="browse") |
|
|
self.file_tree = ttk.Treeview(list_frame, columns=columns, show="headings", selectmode="browse") |
|
|
|
|
|
|
|
|
# 设置列标题 |
|
|
# 设置列标题 |
|
|
self.file_tree.heading("filename", text="文件名") |
|
|
|
|
|
self.file_tree.heading("employee", text="员工姓名 (C3)") |
|
|
self.file_tree.heading("employee", text="员工姓名 (C3)") |
|
|
self.file_tree.heading("company", text="所属公司信息 (C2)") |
|
|
self.file_tree.heading("company", text="所属公司信息 (C2)") |
|
|
self.file_tree.heading("bank", text="转账银行信息 (B30)") |
|
|
self.file_tree.heading("bank", text="转账银行信息 (B30)") |
|
|
self.file_tree.heading("other", text="日本日期 (F2)") |
|
|
|
|
|
|
|
|
self.file_tree.heading("date", text="日本日期 (F2)") |
|
|
|
|
|
self.file_tree.heading("match_status", text="工作表匹配状态") |
|
|
|
|
|
|
|
|
# 设置列宽 |
|
|
# 设置列宽 |
|
|
self.file_tree.column("filename", width=280) |
|
|
|
|
|
self.file_tree.column("employee", width=110) |
|
|
|
|
|
|
|
|
self.file_tree.column("employee", width=120) |
|
|
self.file_tree.column("company", width=170) |
|
|
self.file_tree.column("company", width=170) |
|
|
self.file_tree.column("bank", width=170) |
|
|
self.file_tree.column("bank", width=170) |
|
|
self.file_tree.column("other", width=120) |
|
|
|
|
|
|
|
|
self.file_tree.column("date", width=120) |
|
|
|
|
|
self.file_tree.column("match_status", width=120) |
|
|
|
|
|
|
|
|
# 添加滚动条 |
|
|
# 添加滚动条 |
|
|
scrollbar_y = ttk.Scrollbar(list_frame, orient="vertical", command=self.file_tree.yview) |
|
|
scrollbar_y = ttk.Scrollbar(list_frame, orient="vertical", command=self.file_tree.yview) |
|
|
|
|
|
|
|
|
self.status_label.pack(side="left", padx=5) |
|
|
self.status_label.pack(side="left", padx=5) |
|
|
|
|
|
|
|
|
def select_files(self): |
|
|
def select_files(self): |
|
|
files = filedialog.askopenfilenames( |
|
|
|
|
|
|
|
|
file = filedialog.askopenfilename( |
|
|
title="选择Excel文件", |
|
|
title="选择Excel文件", |
|
|
filetypes=[("Excel Files", "*.xlsx")] |
|
|
filetypes=[("Excel Files", "*.xlsx")] |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
if files: |
|
|
|
|
|
self.import_files = list(files) |
|
|
|
|
|
|
|
|
if file: |
|
|
|
|
|
self.import_files = [file] |
|
|
self.update_file_tree() |
|
|
self.update_file_tree() |
|
|
|
|
|
|
|
|
def update_file_tree(self): |
|
|
def update_file_tree(self): |
|
|
|
|
|
|
|
|
for item in self.file_tree.get_children(): |
|
|
for item in self.file_tree.get_children(): |
|
|
self.file_tree.delete(item) |
|
|
self.file_tree.delete(item) |
|
|
|
|
|
|
|
|
# 更新文件计数 |
|
|
|
|
|
self.file_count_label.config(text=f"已选择: {len(self.import_files)} 个文件") |
|
|
|
|
|
|
|
|
|
|
|
# 用于存储未匹配的员工姓名 |
|
|
# 用于存储未匹配的员工姓名 |
|
|
unmatch_employees = [] |
|
|
unmatch_employees = [] |
|
|
|
|
|
|
|
|
# Add files to tree with employee name and Japanese date |
|
|
|
|
|
for file in self.import_files: |
|
|
|
|
|
try: |
|
|
|
|
|
# Get employee name from C3 cell |
|
|
|
|
|
filename = os.path.basename(file) |
|
|
|
|
|
employee_name = "" |
|
|
|
|
|
original_date = "" |
|
|
|
|
|
|
|
|
|
|
|
# Get data from Excel file |
|
|
|
|
|
wb = openpyxl.load_workbook(file) |
|
|
|
|
|
name_sheet = wb.worksheets[0] |
|
|
|
|
|
employee_name = name_sheet.cell(row=3, column=3).value or "" |
|
|
|
|
|
|
|
|
|
|
|
# 获取日期单元格的原始值,不进行格式转换 |
|
|
|
|
|
date_sheet = wb.worksheets[1] |
|
|
|
|
|
original_date = date_sheet.cell(row=4, column=2).value or "" |
|
|
|
|
|
|
|
|
|
|
|
# 仅为提取年月信息做最小处理(用于文件名和工作表名称),不影响显示 |
|
|
|
|
|
extracted_year = None |
|
|
|
|
|
extracted_month = None |
|
|
|
|
|
|
|
|
# 当前只处理单个文件 |
|
|
|
|
|
if not self.import_files: |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
file = self.import_files[0] |
|
|
|
|
|
try: |
|
|
|
|
|
# 打开工作簿 |
|
|
|
|
|
wb = openpyxl.load_workbook(file) |
|
|
|
|
|
name_sheet = wb.worksheets[0] |
|
|
|
|
|
|
|
|
|
|
|
# 验证是否存在第二个工作表 |
|
|
|
|
|
if len(wb.worksheets) < 2: |
|
|
|
|
|
messagebox.showerror("错误", "导入的Excel必须包含至少两个工作表") |
|
|
|
|
|
self.import_files = [] |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
if isinstance(original_date, (int, float)): |
|
|
|
|
|
# Excel日期数字格式 |
|
|
|
|
|
base_date = datetime(1899, 12, 30) |
|
|
|
|
|
date_obj = base_date + timedelta(days=original_date) |
|
|
|
|
|
extracted_year = date_obj.year |
|
|
|
|
|
extracted_month = date_obj.month |
|
|
|
|
|
elif isinstance(original_date, datetime): |
|
|
|
|
|
# 日期对象 |
|
|
|
|
|
extracted_year = original_date.year |
|
|
|
|
|
extracted_month = original_date.month |
|
|
|
|
|
else: |
|
|
|
|
|
# 字符串格式 - 尝试提取年月 |
|
|
|
|
|
date_str = str(original_date) |
|
|
|
|
|
year_month_match = re.search(r'(\d{4})年(\d{1,2})月', date_str) |
|
|
|
|
|
if year_month_match: |
|
|
|
|
|
extracted_year, extracted_month = map(int, year_month_match.groups()) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error processing date: {e}") |
|
|
|
|
|
|
|
|
date_sheet = wb.worksheets[1] |
|
|
|
|
|
|
|
|
|
|
|
# 获取日期信息 |
|
|
|
|
|
original_date = date_sheet.cell(row=4, column=2).value or "" |
|
|
|
|
|
|
|
|
|
|
|
# 提取年月信息 |
|
|
|
|
|
extracted_year = None |
|
|
|
|
|
extracted_month = None |
|
|
|
|
|
try: |
|
|
|
|
|
if isinstance(original_date, (int, float)): |
|
|
|
|
|
base_date = datetime(1899, 12, 30) |
|
|
|
|
|
date_obj = base_date + timedelta(days=original_date) |
|
|
|
|
|
extracted_year = date_obj.year |
|
|
|
|
|
extracted_month = date_obj.month |
|
|
|
|
|
elif isinstance(original_date, datetime): |
|
|
|
|
|
extracted_year = original_date.year |
|
|
|
|
|
extracted_month = original_date.month |
|
|
|
|
|
else: |
|
|
|
|
|
date_str = str(original_date) |
|
|
|
|
|
year_month_match = re.search(r'(\d{4})年(\d{1,2})月', date_str) |
|
|
|
|
|
if year_month_match: |
|
|
|
|
|
extracted_year, extracted_month = map(int, year_month_match.groups()) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error processing date: {e}") |
|
|
|
|
|
|
|
|
|
|
|
# 生成令和年号日期格式 |
|
|
|
|
|
reiwa_date = "" |
|
|
|
|
|
if extracted_year and extracted_month: |
|
|
|
|
|
reiwa_year = extracted_year - 2019 + 1 |
|
|
|
|
|
if reiwa_year > 0: |
|
|
|
|
|
reiwa_date = f"令和{reiwa_year}年{extracted_month}月分" |
|
|
|
|
|
|
|
|
|
|
|
# 检查工作表中是否存在员工姓名对应的工作表 |
|
|
|
|
|
sheet_names = wb.sheetnames |
|
|
|
|
|
employee_sheets = sheet_names[1:] # 从第二个工作表开始 |
|
|
|
|
|
|
|
|
|
|
|
# 获取所有员工数据(从C3开始的行) |
|
|
|
|
|
current_row = 3 # 从C3开始 |
|
|
|
|
|
while True: |
|
|
|
|
|
name_cell = name_sheet.cell(row=current_row, column=3) # C列 |
|
|
|
|
|
if not name_cell.value: # 如果C列单元格为空,说明没有更多数据 |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
# 生成令和年号日期格式 |
|
|
|
|
|
reiwa_date = "" |
|
|
|
|
|
if extracted_year and extracted_month: |
|
|
|
|
|
# 计算令和年号 (2019年为令和元年/1年) |
|
|
|
|
|
reiwa_year = extracted_year - 2019 + 1 |
|
|
|
|
|
if reiwa_year > 0: # 只有2019年之后才使用令和年号 |
|
|
|
|
|
reiwa_date = f"令和{reiwa_year}年{extracted_month}月分" |
|
|
|
|
|
|
|
|
employee_name = name_cell.value |
|
|
|
|
|
if employee_name: |
|
|
|
|
|
# 清除员工姓名中的所有空格 |
|
|
|
|
|
employee_name = employee_name.replace(" ", "").strip() |
|
|
|
|
|
name_sheet.cell(row=current_row, column=3).value = employee_name |
|
|
|
|
|
|
|
|
# 默认值 |
|
|
# 默认值 |
|
|
company = "选择公司" |
|
|
company = "选择公司" |
|
|
|
|
|
|
|
|
employee_matched = False |
|
|
employee_matched = False |
|
|
if employee_name: |
|
|
if employee_name: |
|
|
for emp_info in EMPLOYEE_INFO: |
|
|
for emp_info in EMPLOYEE_INFO: |
|
|
if emp_info.get("employee_name") == employee_name: |
|
|
|
|
|
|
|
|
# 清除员工配置中姓名的空格后再比较 |
|
|
|
|
|
config_name = emp_info.get("employee_name", "").replace(" ", "").strip() |
|
|
|
|
|
if config_name == employee_name: |
|
|
employee_matched = True |
|
|
employee_matched = True |
|
|
# 匹配到员工信息,更新公司和银行信息 |
|
|
# 匹配到员工信息,更新公司和银行信息 |
|
|
company = emp_info.get("company_name", "") |
|
|
company = emp_info.get("company_name", "") |
|
|
|
|
|
|
|
|
bank_info = f"振込先金融機関:{bank_name}\n口座番号:{branch_account}" |
|
|
bank_info = f"振込先金融機関:{bank_name}\n口座番号:{branch_account}" |
|
|
break |
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
# 检查员工名称是否在工作表名称中 |
|
|
|
|
|
sheet_match = False |
|
|
|
|
|
for sheet_name in employee_sheets: |
|
|
|
|
|
# 清除工作表名称中的空格后再比较 |
|
|
|
|
|
clean_sheet_name = sheet_name.replace(" ", "").strip() |
|
|
|
|
|
if employee_name == clean_sheet_name: |
|
|
|
|
|
sheet_match = True |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
# 如果未匹配,添加到未匹配列表 |
|
|
# 如果未匹配,添加到未匹配列表 |
|
|
if not employee_matched and employee_name not in unmatch_employees: |
|
|
if not employee_matched and employee_name not in unmatch_employees: |
|
|
unmatch_employees.append(employee_name) |
|
|
unmatch_employees.append(employee_name) |
|
|
|
|
|
|
|
|
# 自动添加到文件树 - 在日本日期(F2)字段显示令和年月 |
|
|
|
|
|
self.file_tree.insert("", "end", values=(filename, employee_name, company, bank_info, reiwa_date or original_date)) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error reading file {file}: {e}") |
|
|
|
|
|
self.file_tree.insert("", "end", values=(filename, "", "选择公司", "选择银行", "")) |
|
|
|
|
|
|
|
|
# 添加到文件树 - 在日本日期(F2)字段显示令和年月及工作表匹配状态 |
|
|
|
|
|
matching_info = "✓ 已匹配工作表" if sheet_match else "✗ 未匹配工作表" |
|
|
|
|
|
|
|
|
|
|
|
self.file_tree.insert("", "end", values=( |
|
|
|
|
|
employee_name, # 员工姓名 |
|
|
|
|
|
company, # 公司信息 |
|
|
|
|
|
bank_info, # 银行信息 |
|
|
|
|
|
reiwa_date, # 日期信息 |
|
|
|
|
|
matching_info # 工作表匹配状态 |
|
|
|
|
|
)) |
|
|
|
|
|
|
|
|
|
|
|
current_row += 1 |
|
|
|
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error reading file {file}: {e}") |
|
|
|
|
|
|
|
|
|
|
|
# 更新文件计数 |
|
|
|
|
|
total_employees = len(self.file_tree.get_children()) |
|
|
|
|
|
self.file_count_label.config(text=f"已选择: {total_employees} 个员工") |
|
|
|
|
|
|
|
|
# 如果有未匹配的员工,显示警告消息 |
|
|
# 如果有未匹配的员工,显示警告消息 |
|
|
if unmatch_employees: |
|
|
if unmatch_employees: |
|
|
|
|
|
|
|
|
# 标记未匹配的行 |
|
|
# 标记未匹配的行 |
|
|
for item in self.file_tree.get_children(): |
|
|
for item in self.file_tree.get_children(): |
|
|
values = self.file_tree.item(item, "values") |
|
|
values = self.file_tree.item(item, "values") |
|
|
if values[1] in unmatch_employees: |
|
|
|
|
|
|
|
|
if values[0] in unmatch_employees: |
|
|
self.file_tree.item(item, tags=("unmatch",)) |
|
|
self.file_tree.item(item, tags=("unmatch",)) |
|
|
|
|
|
|
|
|
# 设置未匹配样式(黄色背景) |
|
|
# 设置未匹配样式(黄色背景) |
|
|
self.file_tree.tag_configure("unmatch", background="#FFF9C4") # 浅黄色 |
|
|
self.file_tree.tag_configure("unmatch", background="#FFF9C4") # 浅黄色 |
|
|
|
|
|
|
|
|
# 设置状态提示 |
|
|
# 设置状态提示 |
|
|
if self.import_files: |
|
|
|
|
|
self.status_label.config(text="文件已加载,请配置转换选项", foreground=self.text_color) |
|
|
|
|
|
|
|
|
if total_employees > 0: |
|
|
|
|
|
self.status_label.config(text="员工信息已加载,请配置转换选项", foreground=self.text_color) |
|
|
else: |
|
|
else: |
|
|
self.status_label.config(text="准备就绪", foreground="gray") |
|
|
self.status_label.config(text="准备就绪", foreground="gray") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unmatch_employees = [] |
|
|
unmatch_employees = [] |
|
|
for item in self.file_tree.get_children(): |
|
|
for item in self.file_tree.get_children(): |
|
|
values = self.file_tree.item(item, "values") |
|
|
values = self.file_tree.item(item, "values") |
|
|
employee_name = values[1] |
|
|
|
|
|
|
|
|
employee_name = values[0] |
|
|
|
|
|
|
|
|
# 检查是否有匹配 |
|
|
# 检查是否有匹配 |
|
|
if employee_name and not any(emp_info.get("employee_name") == employee_name for emp_info in EMPLOYEE_INFO): |
|
|
if employee_name and not any(emp_info.get("employee_name") == employee_name for emp_info in EMPLOYEE_INFO): |
|
|
|
|
|
|
|
|
values = self.file_tree.item(item, "values") |
|
|
values = self.file_tree.item(item, "values") |
|
|
|
|
|
|
|
|
# 安全地获取值 |
|
|
# 安全地获取值 |
|
|
filename = values[0] if len(values) > 0 else "" |
|
|
|
|
|
employee_name = values[1] if len(values) > 1 else "" |
|
|
|
|
|
company = values[2] if len(values) > 2 else "" |
|
|
|
|
|
bank = values[3] if len(values) > 3 else "" |
|
|
|
|
|
other_info = values[4] if len(values) > 4 else "" |
|
|
|
|
|
|
|
|
employee_name = values[0] |
|
|
|
|
|
|
|
|
# Process file |
|
|
# Process file |
|
|
success = self.process_file(file_path, company, bank, other_info, employee_name) |
|
|
|
|
|
|
|
|
success = self.process_file(file_path, "", "", "", employee_name) |
|
|
if success: |
|
|
if success: |
|
|
success_count += 1 |
|
|
success_count += 1 |
|
|
# 设置行的背景色为成功 |
|
|
# 设置行的背景色为成功 |
|
|
|
|
|
|
|
|
# Extract name and date |
|
|
# Extract name and date |
|
|
input_wb = openpyxl.load_workbook(input_file) |
|
|
input_wb = openpyxl.load_workbook(input_file) |
|
|
name_sheet = input_wb.worksheets[0] |
|
|
name_sheet = input_wb.worksheets[0] |
|
|
name = employee_name or name_sheet.cell(row=3, column=3).value # Use provided name or C3 cell value |
|
|
|
|
|
date_sheet = input_wb.worksheets[1] |
|
|
date_sheet = input_wb.worksheets[1] |
|
|
date_value = date_sheet.cell(row=4, column=2).value # B4 cell for date - 只获取不修改 |
|
|
|
|
|
|
|
|
|
|
|
logging.debug(f"Extracted name: {name}") |
|
|
|
|
|
logging.debug(f"Original date value: {date_value}") |
|
|
|
|
|
|
|
|
date_value = date_sheet.cell(row=4, column=2).value # B4 cell for date |
|
|
|
|
|
|
|
|
# 只为了文件名和标题提取年月信息,不修改原始数据 |
|
|
|
|
|
# 提取年月用于文件名和第二个工作表标题 |
|
|
|
|
|
|
|
|
# 获取年月信息 |
|
|
try: |
|
|
try: |
|
|
# 使用不同方法尝试获取年月信息,但不修改原始单元格内容 |
|
|
|
|
|
extracted_year = None |
|
|
extracted_year = None |
|
|
extracted_month = None |
|
|
extracted_month = None |
|
|
|
|
|
|
|
|
if isinstance(date_value, (int, float)): |
|
|
if isinstance(date_value, (int, float)): |
|
|
# Excel日期数字格式 |
|
|
|
|
|
base_date = datetime(1899, 12, 30) |
|
|
base_date = datetime(1899, 12, 30) |
|
|
date_obj = base_date + timedelta(days=date_value) |
|
|
date_obj = base_date + timedelta(days=date_value) |
|
|
extracted_year = date_obj.year |
|
|
extracted_year = date_obj.year |
|
|
extracted_month = date_obj.month |
|
|
extracted_month = date_obj.month |
|
|
elif isinstance(date_value, datetime): |
|
|
elif isinstance(date_value, datetime): |
|
|
# 日期对象 |
|
|
|
|
|
extracted_year = date_value.year |
|
|
extracted_year = date_value.year |
|
|
extracted_month = date_value.month |
|
|
extracted_month = date_value.month |
|
|
else: |
|
|
else: |
|
|
# 字符串格式 - 尝试提取年月 |
|
|
|
|
|
date_str = str(date_value) |
|
|
date_str = str(date_value) |
|
|
|
|
|
|
|
|
# 尝试匹配 YYYY年M月 或 YYYY年M月D日 |
|
|
|
|
|
year_month_match = re.search(r'(\d{4})年(\d{1,2})月', date_str) |
|
|
year_month_match = re.search(r'(\d{4})年(\d{1,2})月', date_str) |
|
|
if year_month_match: |
|
|
if year_month_match: |
|
|
extracted_year, extracted_month = map(int, year_month_match.groups()) |
|
|
extracted_year, extracted_month = map(int, year_month_match.groups()) |
|
|
|
|
|
|
|
|
# 如果无法提取年月,使用当前日期 |
|
|
|
|
|
|
|
|
|
|
|
if extracted_year is None or extracted_month is None: |
|
|
if extracted_year is None or extracted_month is None: |
|
|
current_date = datetime.now() |
|
|
current_date = datetime.now() |
|
|
extracted_year = current_date.year |
|
|
extracted_year = current_date.year |
|
|
extracted_month = current_date.month |
|
|
extracted_month = current_date.month |
|
|
logging.warning(f"Could not extract year/month from date value: {date_value}, using current date") |
|
|
logging.warning(f"Could not extract year/month from date value: {date_value}, using current date") |
|
|
|
|
|
|
|
|
# 用于文件名和工作表标题的年月 |
|
|
|
|
|
|
|
|
|
|
|
year = extracted_year |
|
|
year = extracted_year |
|
|
month = extracted_month |
|
|
month = extracted_month |
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
# 如果提取失败,使用当前日期 |
|
|
|
|
|
current_date = datetime.now() |
|
|
|
|
|
year = current_date.year |
|
|
|
|
|
month = current_date.month |
|
|
|
|
|
logging.error(f"Error extracting date: {e}, using current date") |
|
|
|
|
|
|
|
|
|
|
|
logging.debug(f"Using year={year}, month={month} for filename and sheet title") |
|
|
|
|
|
|
|
|
|
|
|
# Create output filename - 确保使用employee_name |
|
|
|
|
|
output_filename = OUTPUT_FILENAME_FORMAT.format(year=year, month=f'{month:02}', name=name) |
|
|
|
|
|
output_path = os.path.join(self.export_dir, output_filename) |
|
|
|
|
|
|
|
|
|
|
|
logging.debug(f"Output path: {output_path}") |
|
|
|
|
|
|
|
|
|
|
|
# Copy template file to output |
|
|
|
|
|
shutil.copy(self.template_path, output_path) |
|
|
|
|
|
|
|
|
logging.error(f"Error extracting year/month: {e}") |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
# Open output file |
|
|
|
|
|
output_wb = openpyxl.load_workbook(output_path) |
|
|
|
|
|
|
|
|
# 获取所有工作表名称,用于后续匹配 |
|
|
|
|
|
sheet_names = input_wb.sheetnames |
|
|
|
|
|
|
|
|
|
|
|
# 获取所有员工数据(从C3开始的行) |
|
|
|
|
|
employee_rows = [] |
|
|
|
|
|
current_row = 3 # 从C3开始 |
|
|
|
|
|
while True: |
|
|
|
|
|
name_cell = name_sheet.cell(row=current_row, column=3) # C列 |
|
|
|
|
|
if not name_cell.value: # 如果C列单元格为空,说明没有更多数据 |
|
|
|
|
|
break |
|
|
|
|
|
employee_rows.append(current_row) |
|
|
|
|
|
current_row += 1 |
|
|
|
|
|
|
|
|
|
|
|
if not employee_rows: |
|
|
|
|
|
logging.error("No employee data found in the first sheet") |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
# Apply cell mappings from config |
|
|
|
|
|
for src, dst in CELL_MAPPINGS.items(): |
|
|
|
|
|
src_sheet_idx, src_row, src_col = src |
|
|
|
|
|
dst_sheet_idx, dst_row, dst_col = dst |
|
|
|
|
|
try: |
|
|
|
|
|
src_sheet = input_wb.worksheets[src_sheet_idx] |
|
|
|
|
|
|
|
|
|
|
|
# 处理合并单元格问题 |
|
|
|
|
|
cell = src_sheet.cell(row=src_row, column=src_col) |
|
|
|
|
|
# 如果是合并单元格,获取主单元格的值 |
|
|
|
|
|
if isinstance(cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
# 找到包含此单元格的合并区域 |
|
|
|
|
|
for merged_range in src_sheet.merged_cells.ranges: |
|
|
|
|
|
if cell.coordinate in merged_range: |
|
|
|
|
|
# 获取合并区域左上角单元格的值 |
|
|
|
|
|
top_left = merged_range.min_row, merged_range.min_col |
|
|
|
|
|
src_value = src_sheet.cell(row=top_left[0], column=top_left[1]).value |
|
|
|
|
|
break |
|
|
|
|
|
else: |
|
|
|
|
|
# 如果没有找到合并区域,设为空值 |
|
|
|
|
|
src_value = None |
|
|
|
|
|
else: |
|
|
|
|
|
# 正常单元格直接获取值 |
|
|
|
|
|
src_value = cell.value |
|
|
|
|
|
|
|
|
|
|
|
dst_sheet = output_wb.worksheets[dst_sheet_idx] |
|
|
|
|
|
dst_sheet.cell(row=dst_row, column=dst_col).value = src_value |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
# 只记录错误,继续处理下一个单元格 |
|
|
|
|
|
logging.error(f"Error copying cell from {src} to {dst}: {e}") |
|
|
|
|
|
|
|
|
# 为每个员工创建输出文件 |
|
|
|
|
|
success = True |
|
|
|
|
|
for row_index in employee_rows: |
|
|
|
|
|
employee_name = name_sheet.cell(row=row_index, column=3).value |
|
|
|
|
|
if not employee_name: |
|
|
continue |
|
|
continue |
|
|
|
|
|
|
|
|
# Set custom fields - 使用try/except包裹每个操作 |
|
|
|
|
|
try: |
|
|
|
|
|
# 尝试查找匹配的员工信息 |
|
|
|
|
|
matched_info = None |
|
|
|
|
|
for emp_info in EMPLOYEE_INFO: |
|
|
|
|
|
if emp_info.get("employee_name") == name: |
|
|
|
|
|
matched_info = emp_info |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
# 如果有匹配的员工信息,则使用员工信息中的公司 |
|
|
|
|
|
if matched_info and matched_info.get("company_name"): |
|
|
|
|
|
company = matched_info.get("company_name") |
|
|
|
|
|
|
|
|
|
|
|
sheet_idx, row, col = CUSTOM_CELLS["company"] |
|
|
|
|
|
output_wb.worksheets[sheet_idx].cell(row=row, column=col).value = company |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting company field: {e}") |
|
|
|
|
|
|
|
|
|
|
|
# 计算转账日期(月份+1) |
|
|
|
|
|
try: |
|
|
|
|
|
transfer_month = month + 1 |
|
|
|
|
|
transfer_year = year |
|
|
|
|
|
if transfer_month > 12: |
|
|
|
|
|
transfer_month = 1 |
|
|
|
|
|
transfer_year += 1 |
|
|
|
|
|
|
|
|
|
|
|
# 计算令和年号 |
|
|
|
|
|
reiwa_year = transfer_year - 2019 + 1 |
|
|
|
|
|
transfer_date = f"令和{reiwa_year}年{transfer_month}月25日" |
|
|
|
|
|
|
|
|
|
|
|
# 尝试寻找匹配的银行信息 |
|
|
|
|
|
bank_info = bank |
|
|
|
|
|
|
|
|
# 清除员工姓名中的所有空格 |
|
|
|
|
|
employee_name = employee_name.replace(" ", "").strip() |
|
|
|
|
|
|
|
|
# 根据员工姓名查找匹配的员工信息 - 使用EMPLOYEE_INFO |
|
|
|
|
|
matched_info = None |
|
|
|
|
|
for emp_info in EMPLOYEE_INFO: |
|
|
|
|
|
if emp_info.get("employee_name") == name: |
|
|
|
|
|
matched_info = emp_info |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
if matched_info: |
|
|
|
|
|
# 使用匹配到的员工信息 |
|
|
|
|
|
bank_name = matched_info.get("bank_name", "") |
|
|
|
|
|
branch_account = matched_info.get("branch_account", "") |
|
|
|
|
|
# 使用新的格式 |
|
|
|
|
|
bank_info = f"振込先金融機関:{bank_name}\n口座番号:{branch_account}" |
|
|
|
|
|
|
|
|
|
|
|
# 组合银行转账信息 - 使用新的格式,名義人始终使用employee_name |
|
|
|
|
|
if name and transfer_date: |
|
|
|
|
|
bank_info = f"{bank_info}\n名義人:{name}\n振込日:{transfer_date}\n※休日の場合は、翌営業日にお振込みします。" |
|
|
|
|
|
|
|
|
|
|
|
sheet_idx, row, col = CUSTOM_CELLS["bank"] |
|
|
|
|
|
output_wb.worksheets[sheet_idx].cell(row=row, column=col).value = bank_info |
|
|
|
|
|
|
|
|
|
|
|
# 设置单元格自动换行 |
|
|
|
|
|
cell = output_wb.worksheets[sheet_idx].cell(row=row, column=col) |
|
|
|
|
|
cell.alignment = Alignment(wrap_text=True, vertical='top') |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting bank info: {e}") |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
sheet_idx, row, col = CUSTOM_CELLS["other"] |
|
|
|
|
|
|
|
|
# 创建输出文件名 |
|
|
|
|
|
output_filename = OUTPUT_FILENAME_FORMAT.format( |
|
|
|
|
|
year=year, |
|
|
|
|
|
month=month, |
|
|
|
|
|
name=employee_name |
|
|
|
|
|
) |
|
|
|
|
|
output_path = os.path.join(self.export_dir, output_filename) |
|
|
|
|
|
|
|
|
# 生成令和年号日期格式 |
|
|
|
|
|
reiwa_date = "" |
|
|
|
|
|
if year and month: |
|
|
|
|
|
# 计算令和年号 (2019年为令和元年/1年) |
|
|
|
|
|
reiwa_year = year - 2019 + 1 |
|
|
|
|
|
reiwa_date = f"令和{reiwa_year}年{month}月分" |
|
|
|
|
|
|
|
|
# 加载模板 |
|
|
|
|
|
template_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), TEMPLATE_PATH) |
|
|
|
|
|
output_wb = openpyxl.load_workbook(template_path) |
|
|
|
|
|
|
|
|
# 设置F2单元格的值为令和日期格式 |
|
|
|
|
|
output_wb.worksheets[sheet_idx].cell(row=row, column=col).value = reiwa_date or other_info |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting other info: {e}") |
|
|
|
|
|
|
|
|
|
|
|
# Copy second sheet |
|
|
|
|
|
try: |
|
|
|
|
|
if len(output_wb.worksheets) == 1: |
|
|
|
|
|
output_wb.create_sheet() |
|
|
|
|
|
output_sheet2 = output_wb.worksheets[1] |
|
|
|
|
|
output_sheet2.title = SHEET2_NAME_FORMAT.format(month=month) |
|
|
|
|
|
|
|
|
# 应用单元格映射 |
|
|
|
|
|
for src, dst in CELL_MAPPINGS.items(): |
|
|
|
|
|
src_sheet_idx, src_row_offset, src_col = src |
|
|
|
|
|
dst_sheet_idx, dst_row, dst_col = dst |
|
|
|
|
|
try: |
|
|
|
|
|
src_sheet = input_wb.worksheets[src_sheet_idx] |
|
|
|
|
|
src_row = row_index # 使用当前员工的行 |
|
|
|
|
|
|
|
|
|
|
|
# 处理合并单元格 |
|
|
|
|
|
cell = src_sheet.cell(row=src_row, column=src_col) |
|
|
|
|
|
if isinstance(cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
for merged_range in src_sheet.merged_cells.ranges: |
|
|
|
|
|
if cell.coordinate in merged_range: |
|
|
|
|
|
top_left = merged_range.min_row, merged_range.min_col |
|
|
|
|
|
src_value = src_sheet.cell(row=top_left[0], column=top_left[1]).value |
|
|
|
|
|
break |
|
|
|
|
|
else: |
|
|
|
|
|
src_value = None |
|
|
|
|
|
else: |
|
|
|
|
|
src_value = cell.value |
|
|
|
|
|
|
|
|
|
|
|
dst_sheet = output_wb.worksheets[dst_sheet_idx] |
|
|
|
|
|
dst_sheet.cell(row=dst_row, column=dst_col).value = src_value |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error copying cell from {src} to {dst}: {e}") |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
# 先保存文件,以便后续使用xlwings处理 |
|
|
|
|
|
output_wb.save(output_path) |
|
|
|
|
|
|
|
|
# 设置自定义字段 |
|
|
|
|
|
try: |
|
|
|
|
|
matched_info = None |
|
|
|
|
|
for emp_info in EMPLOYEE_INFO: |
|
|
|
|
|
# 清除员工配置中姓名的空格后再比较 |
|
|
|
|
|
config_name = emp_info.get("employee_name", "").replace(" ", "").strip() |
|
|
|
|
|
if config_name == employee_name: |
|
|
|
|
|
matched_info = emp_info |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
if matched_info and matched_info.get("company_name"): |
|
|
|
|
|
company = matched_info.get("company_name") |
|
|
|
|
|
|
|
|
|
|
|
sheet_idx, row, col = CUSTOM_CELLS["company"] |
|
|
|
|
|
output_wb.worksheets[sheet_idx].cell(row=row, column=col).value = company |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting company field: {e}") |
|
|
|
|
|
|
|
|
# 尝试使用xlwings做直接复制(对日期格式更可靠) |
|
|
|
|
|
try: |
|
|
try: |
|
|
# 使用更安全的xlwings调用方式 |
|
|
|
|
|
logging.debug("尝试使用xlwings复制第二个工作表...") |
|
|
|
|
|
|
|
|
sheet_idx, row, col = CUSTOM_CELLS["bank"] |
|
|
|
|
|
|
|
|
|
|
|
# 计算转账日期(月份+1) |
|
|
|
|
|
transfer_month = month + 1 |
|
|
|
|
|
transfer_year = year |
|
|
|
|
|
if transfer_month > 12: |
|
|
|
|
|
transfer_month = 1 |
|
|
|
|
|
transfer_year += 1 |
|
|
|
|
|
|
|
|
# 使用visible=True可能会解决某些权限问题 |
|
|
|
|
|
with xw.App(visible=False, add_book=False) as app: |
|
|
|
|
|
# 禁用警告和事件可以提高稳定性 |
|
|
|
|
|
app.display_alerts = False |
|
|
|
|
|
app.screen_updating = False |
|
|
|
|
|
|
|
|
# 计算令和年号 |
|
|
|
|
|
reiwa_year = transfer_year - 2019 + 1 |
|
|
|
|
|
transfer_date = f"令和{reiwa_year}年{transfer_month}月25日" |
|
|
|
|
|
|
|
|
|
|
|
# 获取银行信息 |
|
|
|
|
|
bank_info = bank |
|
|
|
|
|
if employee_name: |
|
|
|
|
|
# 查找匹配的员工信息 |
|
|
|
|
|
matched_info = None |
|
|
|
|
|
for emp_info in EMPLOYEE_INFO: |
|
|
|
|
|
# 清除员工配置中姓名的空格后再比较 |
|
|
|
|
|
config_name = emp_info.get("employee_name", "").replace(" ", "").strip() |
|
|
|
|
|
if config_name == employee_name: |
|
|
|
|
|
matched_info = emp_info |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
# 打开工作簿 |
|
|
|
|
|
input_wb_xw = app.books.open(input_file) |
|
|
|
|
|
output_wb_xw = app.books.open(output_path) |
|
|
|
|
|
|
|
|
|
|
|
# 尝试完整复制第二个工作表内容 |
|
|
|
|
|
src_sheet = input_wb_xw.sheets[1] |
|
|
|
|
|
dst_sheet = output_wb_xw.sheets[1] |
|
|
|
|
|
|
|
|
if matched_info: |
|
|
|
|
|
bank_name = matched_info.get("bank_name", "") |
|
|
|
|
|
branch_account = matched_info.get("branch_account", "") |
|
|
|
|
|
account_holder = matched_info.get("account_holder", employee_name) |
|
|
|
|
|
|
|
|
# 复制包含单元格值和格式的范围 |
|
|
|
|
|
src_used = src_sheet.used_range |
|
|
|
|
|
if src_used: |
|
|
|
|
|
src_used.copy() |
|
|
|
|
|
dst_sheet.range('A1').paste() |
|
|
|
|
|
|
|
|
|
|
|
# 保存和关闭工作簿 |
|
|
|
|
|
output_wb_xw.save() |
|
|
|
|
|
input_wb_xw.close() |
|
|
|
|
|
output_wb_xw.close() |
|
|
|
|
|
|
|
|
|
|
|
logging.debug("使用xlwings成功复制了第二个工作表") |
|
|
|
|
|
return True # 如果xlwings成功,直接返回成功 |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"xlwings复制过程中发生错误: {e}") |
|
|
|
|
|
# 关闭所有打开的工作簿 |
|
|
|
|
|
for book in app.books: |
|
|
|
|
|
try: |
|
|
|
|
|
book.close() |
|
|
|
|
|
except: |
|
|
|
|
|
pass |
|
|
|
|
|
raise # 重新引发异常,将进入备选方案 |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"使用xlwings复制B4单元格失败: {e},将使用openpyxl备选方案") |
|
|
|
|
|
|
|
|
|
|
|
# 如果xlwings失败,使用openpyxl作为备选方案继续处理 |
|
|
|
|
|
# 重新加载文件,因为我们之前已保存 |
|
|
|
|
|
output_wb = openpyxl.load_workbook(output_path) |
|
|
|
|
|
output_sheet2 = output_wb.worksheets[1] |
|
|
|
|
|
|
|
|
# 组合完整的银行转账信息 |
|
|
|
|
|
bank_info = f"振込先金融機関:{bank_name}\n口座番号:{branch_account}\n名義人:{account_holder}\n振込日:{transfer_date}\n※休日の場合は、翌営業日にお振込みします。" |
|
|
|
|
|
|
|
|
# 获取源工作表尺寸 |
|
|
|
|
|
max_row = date_sheet.max_row |
|
|
|
|
|
max_col = date_sheet.max_column |
|
|
|
|
|
|
|
|
output_wb.worksheets[sheet_idx].cell(row=row, column=col).value = bank_info |
|
|
|
|
|
|
|
|
# 优先复制所有合并单元格 |
|
|
|
|
|
for merged_range in date_sheet.merged_cells.ranges: |
|
|
|
|
|
output_sheet2.merge_cells(str(merged_range)) |
|
|
|
|
|
|
|
|
# 设置单元格自动换行 |
|
|
|
|
|
cell = output_wb.worksheets[sheet_idx].cell(row=row, column=col) |
|
|
|
|
|
cell.alignment = Alignment(wrap_text=True, vertical='top') |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting bank info: {e}") |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
sheet_idx, row, col = CUSTOM_CELLS["other"] |
|
|
|
|
|
reiwa_date = "" |
|
|
|
|
|
if year and month: |
|
|
|
|
|
reiwa_year = year - 2019 + 1 |
|
|
|
|
|
reiwa_date = f"令和{reiwa_year}年{month}月分" |
|
|
|
|
|
output_wb.worksheets[sheet_idx].cell(row=row, column=col).value = reiwa_date or other_info |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting other info: {e}") |
|
|
|
|
|
|
|
|
|
|
|
# 复制第二个工作表 - 根据员工姓名匹配工作表 |
|
|
|
|
|
try: |
|
|
|
|
|
if len(output_wb.worksheets) == 1: |
|
|
|
|
|
output_wb.create_sheet() |
|
|
|
|
|
output_sheet2 = output_wb.worksheets[1] |
|
|
|
|
|
output_sheet2.title = SHEET2_NAME_FORMAT.format(month=month) |
|
|
|
|
|
|
|
|
# 改进的合并单元格处理方式 |
|
|
|
|
|
# 首先识别所有合并单元格的主单元格(左上角单元格) |
|
|
|
|
|
merged_cell_masters = {} |
|
|
|
|
|
for merged_range in date_sheet.merged_cells.ranges: |
|
|
|
|
|
min_row, min_col = merged_range.min_row, merged_range.min_col |
|
|
|
|
|
merged_cell_masters[(min_row, min_col)] = date_sheet.cell(row=min_row, column=min_col).value |
|
|
|
|
|
|
|
|
# 查找员工姓名匹配的工作表 |
|
|
|
|
|
matched_sheet = None |
|
|
|
|
|
for sheet_name in input_wb.sheetnames: |
|
|
|
|
|
# 清除工作表名称中的空格后再比较 |
|
|
|
|
|
clean_sheet_name = sheet_name.replace(" ", "").strip() |
|
|
|
|
|
if employee_name == clean_sheet_name: |
|
|
|
|
|
matched_sheet = sheet_name |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
# 逐个单元格复制 |
|
|
|
|
|
for row in range(1, max_row + 1): |
|
|
|
|
|
for col in range(1, max_col + 1): |
|
|
|
|
|
try: |
|
|
|
|
|
# 获取源单元格 |
|
|
|
|
|
src_cell = date_sheet.cell(row=row, column=col) |
|
|
|
|
|
dst_cell = output_sheet2.cell(row=row, column=col) |
|
|
|
|
|
|
|
|
if matched_sheet: |
|
|
|
|
|
logging.debug(f"Found matching sheet: {matched_sheet} for employee: {employee_name}") |
|
|
|
|
|
try: |
|
|
|
|
|
# 保存当前工作簿以便使用xlwings处理 |
|
|
|
|
|
temp_output_path = os.path.join(self.export_dir, f"temp_{employee_name}.xlsx") |
|
|
|
|
|
output_wb.save(temp_output_path) |
|
|
|
|
|
|
|
|
|
|
|
# 使用xlwings处理文件 - 这样可以避免合并单元格的问题 |
|
|
|
|
|
with xw.App(visible=False, add_book=False) as app: |
|
|
|
|
|
app.display_alerts = False |
|
|
|
|
|
app.screen_updating = False |
|
|
|
|
|
|
|
|
# 特殊处理B4单元格 |
|
|
|
|
|
if row == 4 and col == 2: |
|
|
|
|
|
if isinstance(src_cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
# 如果B4是合并单元格,找到主单元格 |
|
|
|
|
|
for merged_range in date_sheet.merged_cells.ranges: |
|
|
|
|
|
if src_cell.coordinate in merged_range: |
|
|
|
|
|
min_row, min_col = merged_range.min_row, merged_range.min_col |
|
|
|
|
|
main_cell = date_sheet.cell(row=min_row, column=min_col) |
|
|
|
|
|
dst_cell.value = main_cell.value |
|
|
|
|
|
|
|
|
|
|
|
# 复制主单元格格式 |
|
|
|
|
|
if hasattr(main_cell, 'number_format'): |
|
|
|
|
|
dst_cell.number_format = main_cell.number_format |
|
|
|
|
|
|
|
|
|
|
|
if hasattr(main_cell, 'font'): |
|
|
|
|
|
dst_cell.font = copy(main_cell.font) |
|
|
|
|
|
if hasattr(main_cell, 'border'): |
|
|
|
|
|
dst_cell.border = copy(main_cell.border) |
|
|
|
|
|
if hasattr(main_cell, 'fill'): |
|
|
|
|
|
dst_cell.fill = copy(main_cell.fill) |
|
|
|
|
|
if hasattr(main_cell, 'alignment'): |
|
|
|
|
|
dst_cell.alignment = copy(main_cell.alignment) |
|
|
|
|
|
|
|
|
|
|
|
logging.debug(f"B4是合并单元格,已复制主单元格值={main_cell.value}") |
|
|
|
|
|
break |
|
|
|
|
|
else: |
|
|
|
|
|
# 普通单元格处理 |
|
|
|
|
|
dst_cell.value = src_cell.value |
|
|
|
|
|
|
|
|
|
|
|
# 对于日期类型,特别处理 |
|
|
|
|
|
from datetime import date |
|
|
|
|
|
if isinstance(src_cell.value, (datetime, date)): |
|
|
|
|
|
if hasattr(src_cell, 'number_format'): |
|
|
|
|
|
dst_cell.number_format = src_cell.number_format |
|
|
|
|
|
else: |
|
|
|
|
|
# 设置通用日期格式 |
|
|
|
|
|
dst_cell.number_format = "yyyy/mm/dd" |
|
|
|
|
|
|
|
|
|
|
|
# 复制格式属性 |
|
|
|
|
|
if hasattr(src_cell, 'font'): |
|
|
|
|
|
dst_cell.font = copy(src_cell.font) |
|
|
|
|
|
if hasattr(src_cell, 'border'): |
|
|
|
|
|
dst_cell.border = copy(src_cell.border) |
|
|
|
|
|
if hasattr(src_cell, 'fill'): |
|
|
|
|
|
dst_cell.fill = copy(src_cell.fill) |
|
|
|
|
|
if hasattr(src_cell, 'alignment'): |
|
|
|
|
|
dst_cell.alignment = copy(src_cell.alignment) |
|
|
|
|
|
if hasattr(src_cell, 'number_format'): |
|
|
|
|
|
dst_cell.number_format = src_cell.number_format |
|
|
|
|
|
|
|
|
try: |
|
|
|
|
|
# 打开输入和输出文件 |
|
|
|
|
|
input_wb_xw = app.books.open(input_file) |
|
|
|
|
|
output_wb_xw = app.books.open(temp_output_path) |
|
|
|
|
|
|
|
|
|
|
|
# 获取匹配的工作表 |
|
|
|
|
|
src_sheet = None |
|
|
|
|
|
for sheet in input_wb_xw.sheets: |
|
|
|
|
|
if sheet.name == matched_sheet: |
|
|
|
|
|
src_sheet = sheet |
|
|
|
|
|
break |
|
|
|
|
|
|
|
|
|
|
|
if src_sheet: |
|
|
|
|
|
# 获取输出工作表 |
|
|
|
|
|
dst_sheet = output_wb_xw.sheets[1] |
|
|
|
|
|
|
|
|
|
|
|
# 复制所有单元格的值 - 只复制数据 |
|
|
|
|
|
used_range = src_sheet.used_range |
|
|
|
|
|
data_values = used_range.value # 获取所有值而不带格式 |
|
|
|
|
|
|
|
|
logging.debug(f"B4是普通单元格,已复制值={src_cell.value}, 类型={type(src_cell.value)}") |
|
|
|
|
|
else: |
|
|
|
|
|
# 一般单元格处理 - 区分合并单元格与普通单元格 |
|
|
|
|
|
if isinstance(src_cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
# 对于合并单元格中的从属单元格,值保持为None |
|
|
|
|
|
dst_cell.value = None |
|
|
|
|
|
else: |
|
|
|
|
|
# 普通单元格的值直接复制 |
|
|
|
|
|
dst_cell.value = src_cell.value |
|
|
|
|
|
|
|
|
# 确保data_values不为None |
|
|
|
|
|
if data_values: |
|
|
|
|
|
# 确保是二维数组 |
|
|
|
|
|
if not isinstance(data_values, list): |
|
|
|
|
|
data_values = [[data_values]] |
|
|
|
|
|
elif not isinstance(data_values[0], list): |
|
|
|
|
|
data_values = [data_values] |
|
|
|
|
|
|
|
|
# 复制格式 |
|
|
|
|
|
if hasattr(src_cell, 'font'): |
|
|
|
|
|
dst_cell.font = copy(src_cell.font) |
|
|
|
|
|
if hasattr(src_cell, 'border'): |
|
|
|
|
|
dst_cell.border = copy(src_cell.border) |
|
|
|
|
|
if hasattr(src_cell, 'fill'): |
|
|
|
|
|
dst_cell.fill = copy(src_cell.fill) |
|
|
|
|
|
if hasattr(src_cell, 'alignment'): |
|
|
|
|
|
dst_cell.alignment = copy(src_cell.alignment) |
|
|
|
|
|
if hasattr(src_cell, 'number_format'): |
|
|
|
|
|
dst_cell.number_format = src_cell.number_format |
|
|
|
|
|
|
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
# 处理合并单元格 |
|
|
|
|
|
if isinstance(src_cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
# 对于合并单元格,找到合并区域的左上角主单元格的值 |
|
|
|
|
|
cell_value = None |
|
|
|
|
|
for merged_range in date_sheet.merged_cells.ranges: |
|
|
|
|
|
if src_cell.coordinate in merged_range: |
|
|
|
|
|
top_left = merged_range.min_row, merged_range.min_col |
|
|
|
|
|
cell_value = date_sheet.cell(row=top_left[0], column=top_left[1]).value |
|
|
|
|
|
break |
|
|
|
|
|
else: |
|
|
|
|
|
# 普通单元格直接读取值 |
|
|
|
|
|
cell_value = src_cell.value |
|
|
|
|
|
|
|
|
|
|
|
# 设置目标单元格值 |
|
|
|
|
|
output_sheet2.cell(row=row, column=col).value = cell_value |
|
|
|
|
|
|
|
|
|
|
|
# 复制单元格格式(如果源单元格不是合并单元格) |
|
|
|
|
|
if not isinstance(src_cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
if hasattr(src_cell, 'has_style') and src_cell.has_style: |
|
|
|
|
|
output_cell = output_sheet2.cell(row=row, column=col) |
|
|
|
|
|
|
|
|
# 写入所有值 |
|
|
|
|
|
dst_sheet.range('A1').value = data_values |
|
|
|
|
|
|
|
|
|
|
|
# 保存并关闭 |
|
|
|
|
|
output_wb_xw.save() |
|
|
|
|
|
input_wb_xw.close() |
|
|
|
|
|
output_wb_xw.close() |
|
|
|
|
|
|
|
|
|
|
|
# 重新加载保存的文件 |
|
|
|
|
|
output_wb = openpyxl.load_workbook(temp_output_path) |
|
|
|
|
|
|
|
|
|
|
|
# 删除临时文件 |
|
|
|
|
|
if os.path.exists(temp_output_path): |
|
|
try: |
|
|
try: |
|
|
output_cell.font = copy(src_cell.font) |
|
|
|
|
|
output_cell.border = copy(src_cell.border) |
|
|
|
|
|
output_cell.fill = copy(src_cell.fill) |
|
|
|
|
|
output_cell.number_format = src_cell.number_format |
|
|
|
|
|
output_cell.protection = copy(src_cell.protection) |
|
|
|
|
|
output_cell.alignment = copy(src_cell.alignment) |
|
|
|
|
|
|
|
|
os.remove(temp_output_path) |
|
|
except: |
|
|
except: |
|
|
# 忽略样式复制错误 |
|
|
|
|
|
pass |
|
|
pass |
|
|
|
|
|
|
|
|
|
|
|
logging.debug(f"Successfully copied data from sheet {matched_sheet} using xlwings") |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error in xlwings processing: {e}") |
|
|
|
|
|
# 如果xlwings失败,我们将尝试直接处理数据 |
|
|
|
|
|
try: |
|
|
|
|
|
# 重新打开工作簿 |
|
|
|
|
|
output_wb = openpyxl.load_workbook(template_path) |
|
|
|
|
|
if len(output_wb.worksheets) == 1: |
|
|
|
|
|
output_wb.create_sheet() |
|
|
|
|
|
output_sheet2 = output_wb.worksheets[1] |
|
|
|
|
|
output_sheet2.title = SHEET2_NAME_FORMAT.format(month=month) |
|
|
|
|
|
|
|
|
|
|
|
# 直接使用openpyxl |
|
|
|
|
|
src_sheet = input_wb[matched_sheet] |
|
|
|
|
|
|
|
|
|
|
|
# 获取所有单元格的值并只复制值 |
|
|
|
|
|
max_row = src_sheet.max_row |
|
|
|
|
|
max_col = src_sheet.max_column |
|
|
|
|
|
|
|
|
|
|
|
for r in range(1, max_row + 1): |
|
|
|
|
|
for c in range(1, max_col + 1): |
|
|
|
|
|
src_cell = src_sheet.cell(row=r, column=c) |
|
|
|
|
|
# 判断是否为合并单元格 |
|
|
|
|
|
if isinstance(src_cell, openpyxl.cell.cell.MergedCell): |
|
|
|
|
|
# 对于合并单元格,跳过写入 |
|
|
|
|
|
continue |
|
|
|
|
|
else: |
|
|
|
|
|
# 对于普通单元格,只复制值 |
|
|
|
|
|
output_sheet2.cell(row=r, column=c).value = src_cell.value |
|
|
|
|
|
|
|
|
|
|
|
logging.debug(f"Successfully copied data from sheet {matched_sheet} using openpyxl fallback") |
|
|
|
|
|
except Exception as fallback_error: |
|
|
|
|
|
logging.error(f"Fallback error: {fallback_error}") |
|
|
|
|
|
raise |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error copying sheet {matched_sheet} data: {e}") |
|
|
|
|
|
success = False |
|
|
|
|
|
else: |
|
|
|
|
|
logging.warning(f"No matching sheet found for employee: {employee_name}") |
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
# 更加详细的错误记录 |
|
|
|
|
|
logging.warning(f"复制单元格 row={row}, col={col} 时出错: {e}", exc_info=True) |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error setting up second sheet: {e}") |
|
|
|
|
|
success = False |
|
|
|
|
|
|
|
|
|
|
|
# 保存输出工作簿 |
|
|
|
|
|
try: |
|
|
|
|
|
output_wb.save(output_path) |
|
|
|
|
|
logging.debug(f"File processed successfully for employee: {employee_name}") |
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logging.error(f"复制第二个工作表时出错: {e}", exc_info=True) |
|
|
|
|
|
return False |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error copying second sheet: {e}") |
|
|
|
|
|
|
|
|
logging.error(f"Error saving output file: {e}") |
|
|
|
|
|
success = False |
|
|
|
|
|
|
|
|
# Save output workbook |
|
|
|
|
|
try: |
|
|
|
|
|
output_wb.save(output_path) |
|
|
|
|
|
logging.debug("File processed successfully") |
|
|
|
|
|
return True |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
logging.error(f"Error saving output file: {e}") |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
return success |
|
|
|
|
|
|
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
logging.error(f"Error processing file: {e}") |
|
|
logging.error(f"Error processing file: {e}") |
|
|
# 不显示消息框,只记录错误 |
|
|
|
|
|
return False |
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|