# -*- coding: utf-8 -*-
"""
利息测算脚本(修正版)
改动说明(相对原第5轮脚本):
1. 参数不再手工抄写:本金、起息日、月利率、已还5,000元及其日期,均从同目录
《起诉状-修正版.txt》正文自动读取并回显核对;另与《证据目录-修正版.txt》
《待核清单-修正版.txt》做交叉一致性检查。
2. 不代选待定口径:起诉日、利率理解(月1%/年10%)、抵充口径(抵息/抵本)、
3,000元性质、LPR数值,文书中均为【待定/待核】——本脚本一律不替承办律师选定,
只把各情景的算术结果分别列出,供选定后填入文书。
3. 日期全部显式写出(ISO与中文并列);天数口径、折算口径在报告"口径与假设"逐条列明。
4. 结果另存本目录《利息计算结果-修正版.txt》,不覆盖、不修改任何其他文件。
用法:python3 利息计算-修正版.py
依赖:仅Python标准库。
"""
import os
import re
import sys
from datetime import date
from decimal import Decimal, ROUND_HALF_UP
# ───────────────────────── 参数区 ─────────────────────────
# 起诉日:起诉状为"暂计至【起诉之日待定】",本脚本不代选。
# 承办律师确定起诉日后,改下一行(如 起诉日 = date(2026, 11, 2))并重跑,
# 报告会另给出"截至起诉日"的各情景金额,供诉请二填列时选用。
起诉日 = None
# 测算截止日:None=取运行日。它只是给算式一个展示截止点,【不是】选定的起诉日;
# 报告中所有以此日截止的金额均按"测算展示"对待。
测算截止日 = None
# 以下两项为待定口径的备用参数(非选定):
年利率备用_一分按年10 = Decimal("0.10") # "一分"按年利率10%理解的备用口径(清单第4项,待定)
LPR备选_年利率 = Decimal("0.030") # 沿用原第5轮脚本所列"2025年5月20日起一年期LPR 3.0%"
# 【待核:以起诉日适用报价为准,本脚本不代核、不更新】
LPR备选_起算日 = date(2025, 7, 1) # 展期届满次日(起诉状备选方案、清单第5项)
# ───────────────────────────────────────────────────────────
BASE = os.path.dirname(os.path.abspath(__file__))
诉状名 = "起诉状-修正版.txt"
证据名 = "证据目录-修正版.txt"
清单名 = "待核清单-修正版.txt"
结果名 = "利息计算结果-修正版.txt"
行 = []
def 输出(s=""):
行.append(s)
print(s)
def 读文本(p):
with open(p, "r", encoding="utf-8") as f:
return f.read()
def 紧(t):
"""去除全部空白(含全角空格),便于对折行文书做跨行匹配。"""
return re.sub(r"\s+", "", t)
D2 = Decimal("0.01")
def 舍(x):
return x.quantize(D2, rounding=ROUND_HALF_UP)
def 天数(起, 止):
"""算头不算尾:起息日计息、截止日不计息。"""
return (止 - 起).days
def 计息(本金, 起, 止, 日利率):
d = 天数(起, 止)
return d, 舍(本金 * 日利率 * d)
def 中(日):
return f"{日.isoformat()}({日.year}年{日.month}月{日.day}日)"
def 打明细(截止, 名义利率, 式样):
"""逐笔列算式;式样 '月'→日利率=名义利率÷30,'年'→日利率=名义利率÷365。"""
日利率 = 名义利率 / 30 if 式样 == "月" else 名义利率 / 365
总 = Decimal("0")
for 序, (本金, 起, 说明) in enumerate(借款, 1):
d, i = 计息(本金, 起, 截止, 日利率)
总 += i
输出(f" 第{序}笔 本金{本金:,.0f}元({说明})")
输出(f" 起止:{中(起)} 至 {中(截止)},算头不算尾共 {d} 天")
除数 = "30" if 式样 == "月" else "365"
输出(f" 算式:{本金:,.0f} × {名义利率:%} ÷ {除数} × {d} = {i:,.2f} 元")
return 总
def 截至已生息(止, 日利率):
return sum(计息(p, d, 止, 日利率)[1] for p, d, _ in 借款)
# ════════════════════════ 主流程 ════════════════════════
缺失 = [n for n in (诉状名, 证据名, 清单名) if not os.path.exists(os.path.join(BASE, n))]
if 缺失:
输出("【错误】以下输入文件缺失,无法从实际文书读取参数,脚本拒绝在无依据下计算:")
for n in 缺失:
输出(f" - {n}")
with open(os.path.join(BASE, 结果名), "w", encoding="utf-8") as f:
f.write("\n".join(行) + "\n")
sys.exit(1)
诉状原文 = 读文本(os.path.join(BASE, 诉状名))
证据原文 = 读文本(os.path.join(BASE, 证据名))
清单原文 = 读文本(os.path.join(BASE, 清单名))
诉紧, 证紧, 清紧 = 紧(诉状原文), 紧(证据原文), 紧(清单原文)
输出("利息测算报告(修正版脚本自动生成)")
输出(f"运行日期:{date.today().isoformat()}")
输出("参数来源:本目录《起诉状-修正版.txt》(计算参数);《证据目录-修正版.txt》"
"《待核清单-修正版.txt》(交叉核对)。")
输出("原则:文书中【待定/待核】的口径本脚本不代选,只分别列出各情景算术结果。")
输出()
# ── 一、从起诉状读取参数 ──
输出("一、从起诉状读取的参数(自动匹配)")
本金项 = re.findall(r"以([\d,]+)元为基数自(\d{4})年(\d{1,2})月(\d{1,2})日起", 诉紧)
月利率匹配 = re.findall(r"按月利率([\d.]+)%计算", 诉紧)
已还匹配 = re.findall(r"已付5,000元((\d{4})年(\d{1,2})月(\d{1,2})日)", 诉紧)
解析通过 = True
if len(本金项) != 3:
输出(f" ✗ 诉请二本金项匹配到 {len(本金项)} 笔(应为3笔),中止计算。")
解析通过 = False
else:
借款 = []
期望 = [("80,000", 2024, 3, 8), ("10,000", 2024, 3, 10), ("20,000", 2024, 3, 12)]
说明表 = {
"80,000": "银行转账,2024-03-08(证据二)",
"10,000": "现金交付,借条出具当日2024-03-10(证据一、证据七;当事人陈述)",
"20,000": "茶行账户转入被告指定公司账户,2024-03-12(证据五)",
}
for 金额串, y, m, d in 本金项:
借款.append((Decimal(金额串.replace(",", "")), date(int(y), int(m), int(d)), 说明表.get(金额串, 金额串)))
for (金额串, y, m, d), (e金额, ey, em, ed) in zip(本金项, 期望):
ok = (金额串 == e金额 and (int(y), int(m), int(d)) == (ey, em, ed))
输出(f" {'✓' if ok else '✗'} 诉请二:以{金额串}元为基数自{y}年{m}月{d}日起"
+ ("" if ok else f"(与预期 {e金额}元/{ey}-{em}-{ed} 不符,请人工核对)"))
if not ok:
解析通过 = False
if len(月利率匹配) == 1 and 月利率匹配[0] == "1":
月利率 = Decimal(月利率匹配[0]) / 100
输出(" ✓ 利率:诉请二'均按月利率1%计算'→ 月利率 1%(该口径本身待定,见清单第4项)")
else:
月利率 = None
输出(f" ✗ 月利率匹配异常:{月利率匹配}(应为['1']),中止计算。")
解析通过 = False
if len(已还匹配) == 1 and 已还匹配[0] == ("2024", "9", "2"):
已还额 = Decimal("5000")
已还日 = date(2024, 9, 2)
输出(" ✓ 已还款:诉请二'已付5,000元(2024年9月2日)依法先行抵充利息'→ 5,000元/2024-09-02"
"(抵息系暂列口径,待定,见清单第3项)")
else:
输出(f" ✗ 已还款匹配异常:{已还匹配}(应为[('2024','9','2')]),中止计算。")
解析通过 = False
待定标记 = ["抵充口径待定", "计息方案待定", "【起诉之日待定】", "款项性质待定"]
for 标记 in 待定标记:
输出(f" · {'检出' if 标记 in 诉紧 else '未检出'}待定标记:{标记}")
输出()
if not 解析通过:
输出("【中止】参数解析未通过,本脚本不输出任何测算金额(避免以错参数算出看似可用的数)。")
with open(os.path.join(BASE, 结果名), "w", encoding="utf-8") as f:
f.write("\n".join(行) + "\n")
sys.exit(1)
# ── 二、未决口径(不代选)──
截止 = 测算截止日 if 测算截止日 is not None else date.today()
输出("二、未决口径清单(本脚本不代选,仅分情景测算)")
输出(" 1. 起诉日:起诉状为【起诉之日待定】,参数区'起诉日'未设定——本报告不含'诉请二"
"应填金额'的选定值;如需暂计,请承办律师确定起诉日填入参数区重跑。")
输出(f" 2. 测算截止日:{中(截止)}"
+ ("(参数区显式指定)" if 测算截止日 is not None else "(未指定,取运行日)")
+ "。它仅为展示算式的截止点,不是选定的起诉日。")
输出(" 3. 利率口径:月1%(诉请二暂列)与年10%(清单第4项待定)两情景均列出。")
输出(" 4. 抵充口径:5,000元抵利息(诉请二暂列)与抵本金(清单第3项待定)两情景均列出。")
输出(" 5. 3,000元(2024-12-31)性质:按诉状暂列口径不作抵减;若认定为还款需另行抵减重算,"
"抵减口径未定,本脚本不代选(附参考数据)。")
输出(f" 6. LPR数值:情景D沿用原第5轮脚本的 {LPR备选_年利率:%}(待核,以起诉日适用报价为准)。")
输出()
# ── 三、情景测算 ──
输出(f"三、情景测算(展示截止:{中(截止)};天数口径:算头不算尾)")
输出()
输出(" 情景A 月利率1% + 5,000元抵利息 + 3,000元按茶叶款不作抵减(诉请二暂列口径,"
"该口径本身待定)")
毛利A = 打明细(截止, 月利率, "月")
截至抵充日 = 截至已生息(已还日, 月利率 / 30)
净利A = 毛利A - 已还额
输出(f" 利息合计(各笔四舍五入至分后加总):{毛利A:,.2f} 元")
输出(f" 减:{中(已还日)}已还 {已还额:,.0f} 元抵利息 → 净利息 {净利A:,.2f} 元")
输出(f" (算术注:截至{中(已还日)}三笔已生息 {截至抵充日:,.2f} 元 ≥ 5,000 元,"
"故抵充时点选择不影响本情景合计。)")
输出(f" 本金110,000元+净利息 = {Decimal('110000') + 净利A:,.2f} 元(抵充口径待定,见清单第3项)")
输出()
输出(" 情景B 月利率1% + 5,000元抵本金(清单第3项待定口径)")
输出(" 本金:105,000 元(5,000元自2024-09-02起从本金中扣减)")
输出(" 【未决】5,000元从哪一笔本金中扣减、扣减后各笔如何计息,文书中未指明——"
"本脚本不代选,不给出选定利息值。")
输出(f" 上限参考(即情景A抵充前利息 {毛利A:,.2f} 元;实际数应低于此值,"
"待扣减口径确定后重算)。")
输出()
输出(" 情景C '一分'按年利率10%理解 + 5,000元抵利息(清单第4项待定口径)")
毛利C = 打明细(截止, 年利率备用_一分按年10, "年")
净利C = 毛利C - 已还额
输出(f" 利息合计:{毛利C:,.2f} 元;抵利息后净利息:{净利C:,.2f} 元"
"(若同时采抵本金口径,参照情景B处理,需重算)")
输出(" 【口径注】本情景按年利率÷365折算天数;与情景A的月利率÷30口径不同——两套折算"
"均为待定假设,全案统一口径待承办律师确定。")
输出()
输出(" 情景D 不主张约定利息:自展期届满次日起按一年期LPR计逾期利息(起诉状备选方案,"
"待承办律师确定)")
基数D = Decimal("105000")
LPR天数 = 天数(LPR备选_起算日, 截止)
LPR利息 = 舍(基数D * LPR备选_年利率 / 365 * LPR天数)
输出(f" 口径:以{基数D:,.0f}元为基数(该备选口径下2025-07-01前无约定利息,5,000元只能"
"抵充本金)、自")
输出(f" {中(LPR备选_起算日)} 起、按一年期LPR {LPR备选_年利率:%}"
"【沿用原第5轮脚本数值,待核】计至")
输出(f" {中(截止)},共 {LPR天数} 天")
输出(f" 算式:{基数D:,.0f} × {LPR备选_年利率:%} ÷ 365 × {LPR天数} = {LPR利息:,.2f} 元")
输出()
输出(" 附注:3,000元(2024-12-31)若被认定为还款")
截至年末 = 截至已生息(date(2024, 12, 31), 月利率 / 30)
输出(f" 各情景均需另行抵减重算;抵利息还是抵本金、如何在三笔间分配,均未定,不代选。")
输出(f" 参考数据:截至{中(date(2024, 12, 31))}三笔已生息 {截至年末:,.2f} 元"
"(月利率1%口径),供判断抵充次序时对照。")
输出()
# ── 四、与起诉日核对(如已设定)──
if 起诉日 is not None:
输出(f"四、截至起诉日 {中(起诉日)} 的各情景金额(供诉请二填列选用,仍不代选口径)")
gA = 打明细(起诉日, 月利率, "月")
nA = gA - 已还额
输出(f" 情景A净利息:{nA:,.2f} 元;本金+利息合计 {Decimal('110000') + nA:,.2f} 元")
gC = 打明细(起诉日, 年利率备用_一分按年10, "年")
输出(f" 情景C净利息(抵息):{gC - 已还额:,.2f} 元")
dD = 天数(LPR备选_起算日, 起诉日)
输出(f" 情景D:{基数D:,.0f} × {LPR备选_年利率:%} ÷ 365 × {dD} = "
f"{舍(基数D * LPR备选_年利率 / 365 * dD):,.2f} 元")
输出()
else:
输出("四、起诉日核对:未执行(起诉状为【起诉之日待定】,参数区未设定,本脚本不代选)。")
输出()
# ── 五、三份文书交叉一致性检查 ──
输出("五、与《证据目录-修正版.txt》《待核清单-修正版.txt》交叉核对")
核对项 = [
("6214****3317", 诉紧, "起诉状载8万元收款账号尾号"),
("6214****3317", 证紧, "证据目录证据二载同一账号尾号"),
("2024年9月2日", 诉紧, "起诉状载5,000元还款日"),
("2024年9月2日", 证紧, "证据目录证据四载同一还款日"),
("19时32分", 证紧, "证据目录载5,000元收款时刻19:32"),
("22时47分", 诉紧, "起诉状载3,000元发起时刻22:47"),
("22时47分", 证紧, "证据目录载同一发起时刻"),
("22时50分", 诉紧, "起诉状载3,000元收款时刻22:50"),
("22时50分", 证紧, "证据目录载同一收款时刻"),
("2024年3月12日", 诉紧, "起诉状载2万元交付日"),
("2024年3月12日9时47分", 证紧, "证据五载同一日及回单时刻09:47"),
("110,000", 清紧, "待核清单第3项本金口径110,000"),
("月利率1%", 清紧, "待核清单第4项月利率1%口径"),
("个体工商户", 清紧, "清单第1项已列茶行主体类型待核"),
("手指遮挡", 清紧, "清单第2项已按'手指遮挡'表述"),
("原告转述", 清紧, "清单第2项'曾住文三路'已标原告转述"),
("15.借条形式细节", 清紧, "清单新增第15项"),
("16.截图补齐与固定", 清紧, "清单新增第16项"),
("能否认定为自认", 清紧, "清单第12项已与起诉状、证据目录口径一致(不再写'自认已覆盖')"),
("的自认,待定", 诉紧, "起诉状对账段保留'能否认定为自认,待定'标注"),
("能否认定为自认", 证紧, "证据三第5项保留'待定'标注"),
]
全过 = True
for 片, 文, 说明 in 核对项:
ok = 片 in 文
全过 = 全过 and ok
输出(f" {'✓' if ok else '✗'} {说明}")
if not 全过:
输出(" ✗ 存在未通过项:请先修正对应文书再重跑,本报告金额不受影响但口径一致性存疑。")
输出()
# ── 六、口径与假设 ──
输出("六、口径与假设(全部显式)")
输出(" 1. 天数=两日期之差(算头不算尾:起息日计息、截止日不计息)。")
输出(" 2. 情景A/B按'月利率÷30'折日利率;情景C/D按'年利率÷365'折算——两套折算并存,"
"均为待定假设(清单未定统一口径)。")
输出(" 3. 各笔利息先四舍五入至分再加总;金额均以起诉状诉请暂列口径为准。")
输出(" 4. 本脚本只做算术与一致性核对,不构成对诉请可获支持程度的法律判断;"
"所有【待定】事项以《待核与待定清单-修正版.txt》及承办律师决定为准。")
输出(" 5. LPR数值沿用原第5轮脚本所列(待核),本脚本不联网、不更新任何外部数据。")
输出()
输出(f"—— 报告完(生成:{date.today().isoformat()};脚本:利息计算-修正版.py)——")
with open(os.path.join(BASE, 结果名), "w", encoding="utf-8") as f:
f.write("\n".join(行) + "\n")
print(f"\n[已另存 {os.path.join(BASE, 结果名)}]")