违约金

This commit is contained in:
李鹏宇
2026-06-13 20:17:55 +08:00
parent d0ef60d355
commit ac5f5610c2
2 changed files with 115 additions and 43 deletions
@@ -239,9 +239,10 @@ class PenaltyMonthReceivedReport(models.Model):
})
# ========== 三、来源B:receivable.modify.line 中 is_penalty=True 的记录 ==========
# 通过 charging_range 反查关联租金
# 步骤:取 is_penalty=True 的 modify.line → 读 receivable_id 的 charging_range →
# 解析出最后付款日 → 在 modify.line 中找匹配的租金记录(同承租方+同物业+同合同+同收款日期)
# 核心关系:违约金的 due_date(应收开始)= 关联租金的 payout_date(收款日期)
# 租金的 due_date +1个月 = 违约金收费区间的开始月份
# 反查逻辑:通过违约金的 due_date 直接在 property.accounts.receivable 中查找
# payout_date 等于违约金 due_date 的租金记录
source_b_domain = [
('is_penalty', '=', True), # 标记为违约金付款
@@ -262,37 +263,71 @@ class PenaltyMonthReceivedReport(models.Model):
if not penalty_rec:
continue
# --- 读取 charging_range 并解析日期 ---
charging_range = penalty_rec.charging_range or ""
range_start, range_end = _parse_charging_range(charging_range)
if not range_end:
# 无法从收费区间解析出日期,跳过这条
# --- 通过违约金的 due_date 反查关联租金 ---
# 关键关系:违约金的 due_date = 租金的 payout_date
penalty_due_date = penalty_rec.due_date
if not penalty_due_date:
# 违约金没有应收开始日期,无法关联租金
continue
# --- 通过 charging_range 的结束日期反查租金 modify.line ---
# 匹配条件:同一承租方 + 同一合同 + 收款日期=range_end + 非违约金记录
rent_ml_domain = [
('id', '!=', pml.id), # 排除自身
('is_penalty', '=', False), # 非违约金(即租金)
('reconciliation_date', '=', range_end), # 收款日期 = 收费区间结束日期
# 统一转为 date 对象用于搜索
penalty_due = penalty_due_date.date() if hasattr(penalty_due_date, 'date') else penalty_due_date
# 在 property.accounts.receivable 中查找关联租金
# 条件:payout_date = 违约金的 due_date + 同承租方 + 同合同
rent_domain = [
('payout_date', '=', penalty_due), # 租金收款日期 = 违约金应收开始日期
]
if pml.lessee_id:
rent_ml_domain.append(('lessee_id', '=', pml.lessee_id.id)) # 同一承租方
rent_domain.append(('lessee_id', '=', pml.lessee_id.id)) # 同一承租方
if pml.contract_id:
rent_ml_domain.append(('contract_id', '=', pml.contract_id.id)) # 同一合同
rent_domain.append(('contract_id', '=', pml.contract_id.id)) # 同一合同
rent_mls = self.env['receivable.modify.line'].sudo().search(rent_ml_domain, limit=1)
if not rent_mls:
rent_recs = self.sudo().search(rent_domain)
if not rent_recs:
continue
rent_ml = rent_mls[0]
# 获取租金对应的应收单
rent_receivable = rent_ml.receivable_id
# --- 多候选时用收费区间开始月辅助定位 ---
# 租金 due_date +1个月 ≈ 违约金收费区间开始月
# 选 due_date 与 charging_range 开始日期最接近的租金
rent_receivable = None
if len(rent_recs) == 1:
# 只有1个候选,直接使用
rent_receivable = rent_recs[0]
else:
# 多个候选:解析 charging_range 开始日期,找 due_date 最接近的租金
charging_range = penalty_rec.charging_range or ""
range_start, _range_end = _parse_charging_range(charging_range)
best_rec = None
best_diff = None
for cand in rent_recs:
if not cand.due_date:
continue
cand_due = cand.due_date.date() if hasattr(cand.due_date, 'date') else cand.due_date
if range_start:
# 用 charging_range 开始日期与租金 due_date 比较
# 充电区间开始月 ≈ 租金 due_date +1个月,所以区间开始日 ≈ due_date +30天
diff = abs((cand_due - range_start).days)
else:
# 无 charging_range,无法精确定位,取第一个
diff = 0
if best_diff is None or diff < best_diff:
best_diff = diff
best_rec = cand
if best_rec:
rent_receivable = best_rec
if not rent_receivable:
continue
# 收费区间(从违约金应收单获取)
charging_range = penalty_rec.charging_range or ""
# 物业名称(优先从违约金应收单取)
prop_name = penalty_rec.property_name or (rent_receivable.property_name if rent_receivable else "")
# 内存过滤(用违约金应收单的信息过滤)
# 内存过滤(用违约金 modify.line 的信息过滤)
if not _match_filters_ml(pml, prop_name):
continue
@@ -302,7 +337,7 @@ class PenaltyMonthReceivedReport(models.Model):
continue
processed_keys.add(key)
# --- 构建租金信息(从租金 modify.line 和对应应收单获取)---
# --- 构建租金信息 ---
rent_amount_val = 0.0
rent_collected_amt = 0.0
rent_uncollected_amt = 0.0
+57 -20
View File
@@ -241,7 +241,11 @@ class PenaltyYearCumReport(models.Model):
})
# ========== 三、来源B:receivable.modify.line 中 is_penalty=True 的记录 ==========
# 通过 charging_range 反查关联租金
# 核心关系:违约金的 due_date(应收开始)= 关联租金的 payout_date(收款日期)
# 租金的 due_date +1个月 = 违约金收费区间的开始月份
# 反查逻辑:通过违约金的 due_date 直接在 property.accounts.receivable 中查找
# payout_date 等于违约金 due_date 的租金记录
source_b_domain = [
('is_penalty', '=', True), # 标记为违约金付款
('reconciliation_date', '!=', False), # 有对账日期
@@ -261,32 +265,65 @@ class PenaltyYearCumReport(models.Model):
if not penalty_rec:
continue
# --- 读取 charging_range 并解析日期 ---
charging_range = penalty_rec.charging_range or ""
range_start, range_end = _parse_charging_range(charging_range)
if not range_end:
# 无法从收费区间解析出日期,跳过这条
# --- 通过违约金的 due_date 反查关联租金 ---
# 关键关系:违约金的 due_date = 租金的 payout_date
penalty_due_date = penalty_rec.due_date
if not penalty_due_date:
# 违约金没有应收开始日期,无法关联租金
continue
# --- 通过 charging_range 的结束日期反查租金 modify.line ---
# 匹配条件:同一承租方 + 同一合同 + 收款日期=range_end + 非违约金记录
rent_ml_domain = [
('id', '!=', pml.id), # 排除自身
('is_penalty', '=', False), # 非违约金(即租金)
('reconciliation_date', '=', range_end), # 收款日期 = 收费区间结束日期
# 统一转为 date 对象用于搜索
penalty_due = penalty_due_date.date() if hasattr(penalty_due_date, 'date') else penalty_due_date
# 在 property.accounts.receivable 中查找关联租金
# 条件:payout_date = 违约金的 due_date + 同承租方 + 同合同
rent_domain = [
('payout_date', '=', penalty_due), # 租金收款日期 = 违约金应收开始日期
]
if pml.lessee_id:
rent_ml_domain.append(('lessee_id', '=', pml.lessee_id.id)) # 同一承租方
rent_domain.append(('lessee_id', '=', pml.lessee_id.id)) # 同一承租方
if pml.contract_id:
rent_ml_domain.append(('contract_id', '=', pml.contract_id.id)) # 同一合同
rent_domain.append(('contract_id', '=', pml.contract_id.id)) # 同一合同
rent_mls = self.env['receivable.modify.line'].sudo().search(rent_ml_domain, limit=1)
if not rent_mls:
rent_recs = self.sudo().search(rent_domain)
if not rent_recs:
continue
rent_ml = rent_mls[0]
# 获取租金对应的应收单
rent_receivable = rent_ml.receivable_id
# --- 多候选时用收费区间开始月辅助定位 ---
# 租金 due_date +1个月 ≈ 违约金收费区间开始月
# 选 due_date 与 charging_range 开始日期最接近的租金
rent_receivable = None
if len(rent_recs) == 1:
# 只有1个候选,直接使用
rent_receivable = rent_recs[0]
else:
# 多个候选:解析 charging_range 开始日期,找 due_date 最接近的租金
charging_range = penalty_rec.charging_range or ""
range_start, _range_end = _parse_charging_range(charging_range)
best_rec = None
best_diff = None
for cand in rent_recs:
if not cand.due_date:
continue
cand_due = cand.due_date.date() if hasattr(cand.due_date, 'date') else cand.due_date
if range_start:
# 用 charging_range 开始日期与租金 due_date 比较
diff = abs((cand_due - range_start).days)
else:
# 无 charging_range,无法精确定位,取第一个
diff = 0
if best_diff is None or diff < best_diff:
best_diff = diff
best_rec = cand
if best_rec:
rent_receivable = best_rec
if not rent_receivable:
continue
# 收费区间(从违约金应收单获取)
charging_range = penalty_rec.charging_range or ""
# 物业名称(优先从违约金应收单取)
prop_name = penalty_rec.property_name or (rent_receivable.property_name if rent_receivable else "")
@@ -301,7 +338,7 @@ class PenaltyYearCumReport(models.Model):
continue
processed_keys.add(key)
# --- 构建租金信息(从租金 modify.line 和对应应收单获取)---
# --- 构建租金信息 ---
rent_amount_val = 0.0
rent_collected_amt = 0.0
rent_uncollected_amt = 0.0