当前位置:首页>python>Python/财务自动化之合并报表债权债务抵消

Python/财务自动化之合并报表债权债务抵消

  • 2026-09-10 10:46:20
Python/财务自动化之合并报表债权债务抵消

一、业务场景

上周一介绍合并报表自动化框架时提到,内部抵销是其中工作量最大,也是通常提效最有价值的模块。这里我以其中较为麻烦的“债权债务抵销”为例,做了个抵消的自动化demo样本,其他的科目可以参照类似的逻辑处理。

此处以其他应收款、其他应付款为例,假设里面都是往来款,有两种抵消方式:

1、其他应收/付款的所属公司与对方单位,都是合并范围内的公司,可以直接在合并范围内抵消;比如:合并内的A 借给 合并内的B100万,A账上记应收B100万,B账上记应付A100万。合并层面这100万既不是真正的债权也不是真正的债务,必须抵消。

2、合并范围内的相同/不同公司对同一个客户单位有其他应收款和其他应付款,这里如果是不同公司,签订一份债权债务抵消协议,通常也可以抵消。

合并内的A对外部单位C有债权100万,合并内的B对外部单位C有债务100万,此时三方可以签订债权债务抵消协议,那这两笔也可以抵消掉。

以下对整个方案进行简要拆解,并写了下第一种抵消方式的参考提示词,可以发给DeepSeek试试。

二、抵消逻辑

1、首先要从主数据里获取合并范围清单,如:

2、导出其他应收款和其他应付款的明细,如:

3、根据“合并范围”清单,判断两个科目里“公司名称”和“对方单位”是否属于合并内的公司;

第一类抵消:

1、单边科目里,如果“公司名称”和“对方单位”都属于合并内公司,则金额可以全部抵消,即抵消金额为金额列的负数;

2、用原金额-抵消金额,剩余即为同科目抵消后的余额。

第二类抵消:

1、将其他应收和其他应付两个科目,分别按照对方单位的抵消余额进行汇总后,放在同一张表上列示,取小抵消。如:

2、将可抵消金额按比例回填到原明细表中,计算抵消余额,即同科目抵消后余额-相同客商抵消金额=抵消后余额。

三、报告输出

运行后生成一个Excel文件,包含5个Sheet:

① 合并范围 — 原样保留,方便核对

② 应收明细 — 每笔应收的抵消过程:内部抵消多少、客商抵消多少、抵消后余额

③ 应付明细 — 每笔应付的抵消过程:内部抵消多少、客商抵消多少、抵消后余额

④ 相同客商抵消 — 按客商汇总的应收余额、应付余额、可抵消金额

⑤ 汇总表 — 一页看全局:

四、参考代码及第一类抵消的参考提示词

参考代码:

import pandas as pdfrom openpyxl import load_workbookfrom openpyxl.styles import Font, Alignment, PatternFill, Border, Side# ============ 文件路径(按需修改)=============file_path = r".\债权债务抵消_其他.xlsx"output_path = r".\债权债务抵消_其他_抵消结果.xlsx"# ============ 读取数据 ============# 从Excel中读取三个sheet:合并范围、应收明细、应付明细df_scope = pd.read_excel(file_path, sheet_name="合并范围")df_ar = pd.read_excel(file_path, sheet_name="应收")df_ap = pd.read_excel(file_path, sheet_name="应付")# 把合并范围整理成字典,方便后面查找:{公司名称: 是否并表}scope_dict = dict(zip(df_scope["公司名称"], df_scope["是否并表"]))# ============ 核心处理函数 ============def process_sheet(df_self, df_other, sheet_type="应收"):    """    处理应收或应付明细表    df_self: 当前科目明细(比如应收)    df_other: 对方科目明细(比如应付)    sheet_type: "应收" 或 "应付"    """    df = df_self.copy()    # ---- 第一步:补充并表信息 ----    # 查本公司是否在合并范围内,查不到就填"否"    df["是否并表"] = df["公司名称"].map(scope_dict).fillna("否")    # 查对方单位是否在合并范围内,查不到就填"否"    df["客商是否并表"] = df["对方单位"].map(scope_dict).fillna("否")    # ---- 第二步:第一类抵消——本科目内部抵消 ----    # 规则:本公司和对方单位都在合并范围内 → 全额抵消    # 比如A、B都是合并内公司,A借B 100万,这100万在合并层面要抵消掉    df["本科目内部抵消"] = 0.0    for idx, row in df.iterrows():        if row["是否并表"] == "是" and row["客商是否并表"] == "是":            df.at[idx, "本科目内部抵消"] = row["金额"] * -1  # 负数表示抵消    # 内部抵消后还剩多少    df["内部抵消后金额"] = df["金额"] + df["本科目内部抵消"]    # ---- 第三步:对方科目也做一遍内部抵消 ----    # 这样才能知道对方科目"内部抵消后"的余额,用于第二类抵消计算    df_other_proc = df_other.copy()    df_other_proc["是否并表"] = df_other_proc["公司名称"].map(scope_dict).fillna("否")    df_other_proc["客商是否并表"] = df_other_proc["对方单位"].map(scope_dict).fillna("否")    df_other_proc["本科目内部抵消"] = 0.0    for idx, row in df_other_proc.iterrows():        if row["是否并表"] == "是" and row["客商是否并表"] == "是":            df_other_proc.at[idx, "本科目内部抵消"] = row["金额"] * -1    df_other_proc["内部抵消后金额"] = df_other_proc["金额"] + df_other_proc["本科目内部抵消"]    # ---- 第四步:按对方单位汇总"内部抵消后金额" ----    # 把当前科目的余额,按对方单位汇总    self_bal = df.groupby("对方单位")["内部抵消后金额"].sum().reset_index()    # 把对方科目的余额,按对方单位汇总    other_bal = df_other_proc.groupby("对方单位")["内部抵消后金额"].sum().reset_index()    # 给两列起个好懂的名字    if sheet_type == "应收":        self_bal.columns = ["对方单位", "应收余额"]        other_bal.columns = ["对方单位", "应付余额"]    else:        self_bal.columns = ["对方单位", "应付余额"]        other_bal.columns = ["对方单位", "应收余额"]    # ---- 第五步:第二类抵消——相同客商,取小抵消 ----    # 把应收和应付的余额拼到一张表上,同一个客商的应收应付,取较小的那个抵消    merged = self_bal.merge(other_bal, on="对方单位", how="outer").fillna(0)    merged["可抵消金额"] = merged[["应收余额", "应付余额"]].min(axis=1)    # 算一下抵消比例:可抵消金额 ÷ 当前科目余额    # 这个比例用来把可抵消金额"分摊"回每一笔明细上    merged["抵消率"] = 0.0    if sheet_type == "应收":        for idx, row in merged.iterrows():            if row["应收余额"] != 0:                merged.at[idx, "抵消率"] = row["可抵消金额"] / row["应收余额"]    else:        for idx, row in merged.iterrows():            if row["应付余额"] != 0:                merged.at[idx, "抵消率"] = row["可抵消金额"] / row["应付余额"]    # 整理成字典,方便后面按对方单位查找抵消率    rate_dict = dict(zip(merged["对方单位"], merged["抵消率"]))    # ---- 第六步:把相同客商抵消金额回填到明细 ----    # 只对"客商不在合并范围内"且有余额的明细做第二类抵消    df["相同客商抵消"] = 0.0    for idx, row in df.iterrows():        if row["客商是否并表"] != "是" and row["内部抵消后金额"] != 0:            ratio = rate_dict.get(row["对方单位"], 0)            df.at[idx, "相同客商抵消"] = -row["内部抵消后金额"] * ratio    # ---- 第七步:最终结果 ----    df["抵消总数"] = df["本科目内部抵消"] + df["相同客商抵消"]    df["抵消后余额"] = df["内部抵消后金额"] + df["相同客商抵消"]    return df, merged# ============ 开始处理 ============# 处理应收明细df_ar_result, ar_rate = process_sheet(df_ar, df_ap, "应收")# 处理应付明细df_ap_result, ap_rate = process_sheet(df_ap, df_ar, "应付")# ============ 相同客商抵消汇总表 ============# 把应收和应付的客商余额放一起,算出每个客商能抵消多少customer = ar_rate[["对方单位", "应收余额"]].merge(    ap_rate[["对方单位", "应付余额"]], on="对方单位", how="outer").fillna(0)customer["可抵消金额"] = customer[["应收余额", "应付余额"]].min(axis=1)# ============ 准备输出列 ============output_cols = [    "序号", "科目名称", "公司名称", "是否并表", "对方单位", "客商是否并表",    "金额", "本科目内部抵消", "相同客商抵消", "抵消总数", "抵消后余额"]# 如果原始数据没有序号列,自动补一个(序号为数字)if "序号" not in df_ar_result.columns:    df_ar_result.insert(0, "序号", range(1, len(df_ar_result) + 1))if "序号" not in df_ap_result.columns:    df_ap_result.insert(0, "序号", range(1, len(df_ap_result) + 1))# 确保序号列为数字类型df_ar_result["序号"] = pd.to_numeric(df_ar_result["序号"], errors='coerce')df_ap_result["序号"] = pd.to_numeric(df_ap_result["序号"], errors='coerce')df_ar_output = df_ar_result[output_cols]df_ap_output = df_ap_result[output_cols]# ============ 汇总表(删除了合计行)============# 应收的汇总数ar_orig = df_ar_result["金额"].sum()ar_internal = abs(df_ar_result["本科目内部抵消"].sum())ar_cust = abs(df_ar_result["相同客商抵消"].sum())ar_total = abs(df_ar_result["抵消总数"].sum())ar_balance = df_ar_result["抵消后余额"].sum()# 应付的汇总数ap_orig = df_ap_result["金额"].sum()ap_internal = abs(df_ap_result["本科目内部抵消"].sum())ap_cust = abs(df_ap_result["相同客商抵消"].sum())ap_total = abs(df_ap_result["抵消总数"].sum())ap_balance = df_ap_result["抵消后余额"].sum()# 拼成汇总表(只有应收和应付两行)df_summary = pd.DataFrame({    "项目": ["应收", "应付"],    "明细总额(原)": [ar_orig, ap_orig],    "抵消金额": [ar_total, ap_total],    "其中:同科目内部抵消": [ar_internal, ap_internal],    "其中:相同客商抵消": [ar_cust, ap_cust],    "抵消后余额": [ar_balance, ap_balance]})# ============ 保存到Excel ============with pd.ExcelWriter(output_path, engine='openpyxl') as writer:    df_scope.to_excel(writer, sheet_name="合并范围", index=False)    df_ar_output.to_excel(writer, sheet_name="应收明细", index=False)    df_ap_output.to_excel(writer, sheet_name="应付明细", index=False)    customer.to_excel(writer, sheet_name="相同客商抵消", index=False)    df_summary.to_excel(writer, sheet_name="汇总表", index=False)# ============ 美化格式 ============wb = load_workbook(output_path)# 通用样式设置hdr_font = Font(bold=True, color="FFFFFF", size=11)hdr_fill = PatternFill(start_color="366092", end_color="366092", fill_type="solid")align_c = Alignment(horizontal="center", vertical="center")align_r = Alignment(horizontal="right", vertical="center")border = Border(    left=Side('thin'), right=Side('thin'),    top=Side('thin'), bottom=Side('thin'))# ---- 汇总表单独美化 ----ws = wb["汇总表"]ws.column_dimensions['A'].width = 8for col in ['B', 'C', 'D', 'E', 'F']:    ws.column_dimensions[col].width = 22# 表头样式for cell in ws[1]:    cell.font, cell.fill, cell.alignment, cell.border = hdr_font, hdr_fill, align_c, border# 数据行样式(第2行是应收,第3行是应付)for row in ws.iter_rows(min_row=2, max_row=3):    for cell in row:        cell.border = border        cell.alignment = align_r if isinstance(cell.value, (int, float)) else align_c        if isinstance(cell.value, (int, float)):            cell.number_format = '#,##0.00'# ---- 其他Sheet美化 ----for name in ["合并范围", "应收明细", "应付明细", "相同客商抵消"]:    ws = wb[name]    # 表头样式    for cell in ws[1]:        cell.font, cell.fill, cell.alignment, cell.border = hdr_font, hdr_fill, align_c, border    # 自动调整列宽    for col in ws.columns:        max_len = max(len(str(cell.value or "")) for cell in col)        ws.column_dimensions[col[0].column_letter].width = min(max_len + 3, 30)    # 数据行样式    for row in ws.iter_rows(min_row=2):        for cell in row:            cell.border = border            if isinstance(cell.value, (int, float)):                cell.number_format = '#,##0.00'                cell.alignment = align_r# 保存wb.save(output_path)

参考提示词:

我是一个Python小白,请帮我写一个完整的Python脚本。【我要做什么】我在做合并报表,需要计算债权债务中"其他收/付款的内部抵消"。【我有什么数据】一个Excel文件叫"债权债务抵消_其他.xlsx",放在桌面:里面有一个sheet叫"合并范围",里面有公司名称、是否并表(填"是"或"否")两列;另有一个sheet叫"应收",一个sheet叫"应付",里面有序号、科目名称、公司名称、对方单位、金额五列;【我要实现的功能】1. 根据"合并范围"表格,给"应收" "应付"表格增加两列:   - "是否并表":看公司名称列在合并范围里是否并表   - "客商是否并表":看客商名称列在合并范围里是否并表   (如果公司名称或客商名称不在合并范围表里,就填"否")2. 再增加一列"本科目内部抵消":   - 如果"是否并表"是"是" 并且 "客商是否并表"也是"是",这一列等于"金额"列数据的负数;   - 否则填 03. 再增加一列"内部抵消后金额":   - 金额 + 本科目内部抵消4. 最后把结果保存到一个新的Excel文件,叫"同科目抵消结果.xlsx"【要求】- 每行代码要写注释,告诉我这行是干什么的- 文件路径放代码开头,让我能自己修改

以上仅作参考,只看看大致的自动化或信息化逻辑就行,仅供学习使用哦。

最新文章

随机文章