This commit is contained in:
李鹏宇
2026-03-23 10:30:22 +08:00
parent 21670fd173
commit 364efe6c27
+28 -48
View File
@@ -1,4 +1,5 @@
import datetime
import re
from odoo import api, models
@@ -75,8 +76,9 @@ class ReceivableFlowReport(models.Model):
wizard_map = {} # {receivable_id: [wizards]}
for wz in all_wizards:
wizard_map.setdefault(wz.receivable_id.id, []).append(wz)
# 预取所有 pay_line_ids
# 预取所有 pay_line_ids 和 penalty_line_ids
all_pay_lines = all_wizards.mapped('pay_line_ids')
all_wizards.mapped('penalty_line_ids') # 预加载违约金计算明细
# 按 wizard_id 分组
pay_line_map = {} # {wizard_id: [pay_lines]}
for pl in all_pay_lines:
@@ -108,54 +110,32 @@ class ReceivableFlowReport(models.Model):
if rec.submitted == 0:
charge_status = "已收"
# 计算违约金相关信息
# 计算欠租金额(直接使用合同的rent字段,即月租金)
rent_owed = 0.0
if rec.contract_id:
rent_owed = rec.contract_id.rent or 0.0
rent_owed = rent_owed or rec.rent_owed or 0.0
# 计算每天违约金(欠租金额 × 违约金比例)
per_day = 0.0
if rent_owed > 0 and rec.contract_id and rec.contract_id.percentage_liquidated_damages:
penalty_ratio = rec.contract_id.percentage_liquidated_damages.name or "0"
try:
penalty_ratio = float(penalty_ratio)
per_day = rent_owed * penalty_ratio
except ValueError:
per_day = 0.0
per_day = per_day or rec.difference_amount or rec.per_day or 0.0
# 计算违约金金额(每天违约金 × 违约天数)
penalty_amount = 0.0
billing_period = rec.charging_range or ""
days_diff = 0
if billing_period:
try:
# 兼容中文“到”和英文“~”两种分隔符
if ' 到 ' in billing_period:
date_parts = billing_period.split(' 到 ')
elif ' ~ ' in billing_period:
date_parts = billing_period.split(' ~ ')
else:
date_parts = []
if len(date_parts) == 2:
start_date_str = date_parts[0].strip()
end_date_str = date_parts[1].strip()
start_date = datetime.datetime.strptime(start_date_str, "%Y-%m-%d").date()
end_date = datetime.datetime.strptime(end_date_str, "%Y-%m-%d").date()
days_diff = (end_date - start_date).days + 1
billing_period = f"{days_diff} {start_date_str} ~ {end_date_str}"
except Exception:
billing_period = rec.charging_range or ""
days_diff = 0
# 计算违约金金额
penalty_amount = round(days_diff * per_day, 2)
# 获取违约金收款信息(从预加载字典取)
# 从 penalty.line.wizard 取违约金信息(唯一数据源)
wz_list = wizard_map.get(rec.id, [])
# 违约金字段:有 wizard 才显示,否则全为空/0
billing_period = ""
days_diff = 0
penalty_amount = 0.0
if wz_list:
wz = wz_list[0]
days_diff = wz.days_overdue or 0
penalty_amount = round(wz.total_penalty or 0.0, 2)
# 计算时间:取 penalty > 0 的明细行,从每行的 remake 解析起止日期
penalty_lines = [pl for pl in wz.penalty_line_ids if pl.penalty > 0]
if penalty_lines:
# remake 格式: "违约金:2026-02-22至2026-03-23"
# 每行 remake 都包含起止日期,收集所有行的日期取最早和最晚
all_dates = []
for pl in penalty_lines:
dates_in_remake = re.findall(r'(\d{4}-\d{2}-\d{2})', pl.remake or '')
for d in dates_in_remake:
try:
all_dates.append(datetime.datetime.strptime(d, '%Y-%m-%d').date())
except ValueError:
pass
if all_dates:
billing_period = f"{min(all_dates).strftime('%Y-%m-%d')} ~ {max(all_dates).strftime('%Y-%m-%d')}"
penalty_pay_lines = []
for wz in wz_list:
penalty_pay_lines.extend(pay_line_map.get(wz.id, []))