修复归档路径错误,添加公式单元格缓存值支持
- fill 命令生成 Excel 后正确移动到归档目录而非保留在报销输出 - 新增 build_formula_cached_values 支持填充公式单元格的缓存值 - 完成后清理报销输出目录避免残留临时文件 - .gitignore 移除 *.json 使 analyzed_result.json 可被追踪
This commit is contained in:
parent
240d8534fd
commit
04e1592fe3
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,7 +3,6 @@
|
||||||
*.jpeg
|
*.jpeg
|
||||||
*.png
|
*.png
|
||||||
*.txt
|
*.txt
|
||||||
*.json
|
|
||||||
*.xlsx
|
*.xlsx
|
||||||
报销输出/
|
报销输出/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
|
|
||||||
49
差旅报销.py
49
差旅报销.py
|
|
@ -221,10 +221,11 @@ def command_fill(args):
|
||||||
output_dir = json_path.parent
|
output_dir = json_path.parent
|
||||||
archive_dir = output_dir.parent if output_dir.name == OUTPUT_DIR_NAME else Path(".")
|
archive_dir = output_dir.parent if output_dir.name == OUTPUT_DIR_NAME else Path(".")
|
||||||
|
|
||||||
output_file = fill_template(result, output_dir)
|
output_file = fill_template(result, archive_dir)
|
||||||
verify_output(output_file, result)
|
verify_output(output_file, result)
|
||||||
final_archive_dir = finalize_archive_dir(archive_dir, result)
|
final_archive_dir = finalize_archive_dir(archive_dir, result)
|
||||||
final_output_file = final_archive_dir / OUTPUT_DIR_NAME / output_file.name
|
final_output_file = final_archive_dir / output_file.name
|
||||||
|
cleanup_output_dir(final_archive_dir / OUTPUT_DIR_NAME)
|
||||||
cleanup_pycache()
|
cleanup_pycache()
|
||||||
|
|
||||||
print(f"完成:{final_output_file}")
|
print(f"完成:{final_output_file}")
|
||||||
|
|
@ -314,7 +315,7 @@ def fill_template(result, output_dir):
|
||||||
output_file = output_dir / build_output_filename(meta)
|
output_file = output_dir / build_output_filename(meta)
|
||||||
|
|
||||||
shutil.copy(TEMPLATE_FILE, output_file)
|
shutil.copy(TEMPLATE_FILE, output_file)
|
||||||
update_xlsx_cells(output_file, build_cell_values(result))
|
update_xlsx_cells(output_file, build_cell_values(result), build_formula_cached_values(result))
|
||||||
return output_file
|
return output_file
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -327,6 +328,7 @@ def build_cell_values(result):
|
||||||
"B6": f'{meta["出发地"]}-{meta["目的地"]}',
|
"B6": f'{meta["出发地"]}-{meta["目的地"]}',
|
||||||
"C6": f'{meta["出差天数"]}天',
|
"C6": f'{meta["出差天数"]}天',
|
||||||
"D6": meta["出行方式"],
|
"D6": meta["出行方式"],
|
||||||
|
"F6": meta["出差天数"],
|
||||||
"H6": expenses["住宿"]["单据张数"],
|
"H6": expenses["住宿"]["单据张数"],
|
||||||
"I6": expenses["住宿"]["金额"],
|
"I6": expenses["住宿"]["金额"],
|
||||||
"H7": expenses["饮食"]["单据张数"],
|
"H7": expenses["饮食"]["单据张数"],
|
||||||
|
|
@ -338,7 +340,20 @@ def build_cell_values(result):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def update_xlsx_cells(xlsx_path, cell_values):
|
def build_formula_cached_values(result):
|
||||||
|
summary = result["summary"]
|
||||||
|
advance = summary["预借差旅费"]
|
||||||
|
total = summary["报销总额"]
|
||||||
|
return {
|
||||||
|
"H2": summary["附件总张数"],
|
||||||
|
"F9": result["meta"]["出差天数"],
|
||||||
|
"C10": total,
|
||||||
|
"H10": max(total - advance, 0),
|
||||||
|
"H11": max(advance - total, 0),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def update_xlsx_cells(xlsx_path, cell_values, formula_cached_values):
|
||||||
temp_file = NamedTemporaryFile(delete=False, suffix=".xlsx", dir=xlsx_path.parent)
|
temp_file = NamedTemporaryFile(delete=False, suffix=".xlsx", dir=xlsx_path.parent)
|
||||||
temp_path = Path(temp_file.name)
|
temp_path = Path(temp_file.name)
|
||||||
temp_file.close()
|
temp_file.close()
|
||||||
|
|
@ -349,7 +364,7 @@ def update_xlsx_cells(xlsx_path, cell_values):
|
||||||
for item in source.infolist():
|
for item in source.infolist():
|
||||||
data = source.read(item.filename)
|
data = source.read(item.filename)
|
||||||
if item.filename == "xl/worksheets/sheet1.xml":
|
if item.filename == "xl/worksheets/sheet1.xml":
|
||||||
data = update_sheet_xml(data, cell_values)
|
data = update_sheet_xml(data, cell_values, formula_cached_values)
|
||||||
target.writestr(item, data)
|
target.writestr(item, data)
|
||||||
temp_path.replace(xlsx_path)
|
temp_path.replace(xlsx_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -357,7 +372,7 @@ def update_xlsx_cells(xlsx_path, cell_values):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def update_sheet_xml(sheet_xml, cell_values):
|
def update_sheet_xml(sheet_xml, cell_values, formula_cached_values):
|
||||||
namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
namespace = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
||||||
ET.register_namespace("", namespace)
|
ET.register_namespace("", namespace)
|
||||||
root = ET.fromstring(sheet_xml)
|
root = ET.fromstring(sheet_xml)
|
||||||
|
|
@ -366,6 +381,11 @@ def update_sheet_xml(sheet_xml, cell_values):
|
||||||
if cell is None:
|
if cell is None:
|
||||||
raise SystemExit(f"模板缺少单元格:{cell_ref}")
|
raise SystemExit(f"模板缺少单元格:{cell_ref}")
|
||||||
set_cell_xml_value(cell, value, namespace)
|
set_cell_xml_value(cell, value, namespace)
|
||||||
|
for cell_ref, value in formula_cached_values.items():
|
||||||
|
cell = root.find(f".//{{{namespace}}}c[@r='{cell_ref}']")
|
||||||
|
if cell is None:
|
||||||
|
raise SystemExit(f"模板缺少单元格:{cell_ref}")
|
||||||
|
set_formula_cached_value(cell, value, namespace)
|
||||||
return ET.tostring(root, encoding="utf-8", xml_declaration=True)
|
return ET.tostring(root, encoding="utf-8", xml_declaration=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -385,6 +405,18 @@ def set_cell_xml_value(cell, value, namespace):
|
||||||
text_node.text = str(value)
|
text_node.text = str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def set_formula_cached_value(cell, value, namespace):
|
||||||
|
cell.attrib.pop("t", None)
|
||||||
|
value_node = None
|
||||||
|
for child in cell:
|
||||||
|
if child.tag == f"{{{namespace}}}v":
|
||||||
|
value_node = child
|
||||||
|
break
|
||||||
|
if value_node is None:
|
||||||
|
value_node = ET.SubElement(cell, f"{{{namespace}}}v")
|
||||||
|
value_node.text = format_number_for_excel(value)
|
||||||
|
|
||||||
|
|
||||||
def format_number_for_excel(value):
|
def format_number_for_excel(value):
|
||||||
if isinstance(value, int):
|
if isinstance(value, int):
|
||||||
return str(value)
|
return str(value)
|
||||||
|
|
@ -415,6 +447,11 @@ def unique_archive_dir(path):
|
||||||
index += 1
|
index += 1
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup_output_dir(output_dir):
|
||||||
|
if output_dir.exists():
|
||||||
|
shutil.rmtree(output_dir)
|
||||||
|
|
||||||
|
|
||||||
def cleanup_pycache():
|
def cleanup_pycache():
|
||||||
pycache_dir = Path("__pycache__")
|
pycache_dir = Path("__pycache__")
|
||||||
if pycache_dir.exists():
|
if pycache_dir.exists():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user