Files
gzth/yuthon_report/models/pre_advance_report.py
T
2026-06-08 17:17:04 +08:00

147 lines
6.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import datetime
from odoo import api, models
class PreAdvanceReport(models.Model):
_inherit = 'receivable.modify.line'
@api.model
def get_pre_advance_report(self, params):
"""
前期预收报表(数据源:receivable.modify.line):
- 收款日期(reconciliation_date)早于应收日期(due_date)
- 收款日期和应收日期不在同一年同一月(跨月才算预收)
- 查询日期对应应收账单的 due_date(应收日期在查询日之后)
- 金额取收款记录的 amount
- 按应收账单聚合,每张账单只出一行
"""
today = datetime.date.today()
if today.month == 12:
next_month_first = today.replace(year=today.year + 1, month=1, day=1)
else:
next_month_first = today.replace(month=today.month + 1, day=1)
this_month_last = next_month_first - datetime.timedelta(days=1)
date_start = params.get("date_start")
# 应收日期在查询日当月及之后(即未来应收)
cutoff_date = datetime.datetime.fromisoformat(date_start).date() if date_start else this_month_last
# 取查询日所在月的第一天,应收日期 >= 该月第一天
cutoff_month_first = cutoff_date.replace(day=1)
# 核心逻辑:due_date >= 查询月第一天(未来应收),且有收款记录
domain = [
('reconciliation_date', '!=', False),
('receivable_id.due_date', '>=', cutoff_month_first),
('receivable_id.is_invalid', '=', False),
]
keyword = params.get("keyword")
if keyword:
domain += [
'|', '|',
('receivable_id.contract_id.contract_code', 'ilike', keyword),
('receivable_id.property_name', 'ilike', keyword),
('receivable_id.lessee_id.name', 'ilike', keyword),
]
condition = params.get('condition')
partner_id = params.get('partner_id')
company_id = params.get('company_id')
management_type_id = params.get('management_type_id')
property_id = params.get('property_id')
lessee_id = params.get('lessee_id')
contract_id = params.get('contract_id')
if condition:
domain.append(('receivable_id.tenure_type', '=', condition))
if partner_id:
domain.append(('receivable_id.precinct_id', '=', partner_id))
if company_id:
domain.append(('receivable_id.company_id', '=', company_id))
if property_id:
domain.append(('receivable_id.property_ids', 'in', [property_id]))
if lessee_id:
domain.append(('receivable_id.lessee_id', '=', lessee_id))
if contract_id:
domain.append(('receivable_id.contract_id', '=', contract_id))
if management_type_id:
domain.append(('receivable_id.management_type_id', '=', management_type_id))
else:
domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金']))
lines = self.sudo().search(domain, order="receivable_id asc, reconciliation_date asc")
# 预收条件:reconciliation_date < due_date 且不在同一年同一月(跨月才算预收)
lines = lines.filtered(
lambda l: l.reconciliation_date and l.receivable_id.due_date
and l.reconciliation_date < l.receivable_id.due_date
and not (
l.reconciliation_date.year == l.receivable_id.due_date.year
and l.reconciliation_date.month == l.receivable_id.due_date.month
)
)
# 按应收账单聚合
rec_map = {}
for line in lines:
rid = line.receivable_id.id
if rid not in rec_map:
rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0}
rec_map[rid]['amount'] += line.amount or 0.0
rows = []
total_amount = 0.0
for idx, (rid, data) in enumerate(rec_map.items(), start=1):
rec = data['rec']
contract = rec.contract_id
amount = round(data['amount'], 2)
total_amount += amount
# 物业穿透
property_val = ''
if contract and contract.lease_ids and contract.lease_ids[0].address_id:
prop = contract.lease_ids[0].address_id
property_val = {
'model': 'yuthon.property',
'id': prop.id,
'display_name': rec.property_name or prop.name,
}
elif rec:
property_val = rec.property_name or ''
# 应收金额 = original_amount - discount_amount
receivable_amount = round((rec.original_amount or 0.0) - (rec.discount_amount or 0.0), 2)
rows.append({
"序号": idx,
"合同编号": {
'model': 'property.lease.contract',
'id': contract.id,
'display_name': contract.contract_code,
} if contract else "",
"物业名称": property_val,
"承租方名称": {
'model': 'property.tenant.information',
'id': rec.lessee_id.id,
'display_name': rec.lessee_id.name,
} if rec.lessee_id else "",
"收款类型": rec.management_type_id.name if rec.management_type_id else "",
"应收开始": rec.due_date.strftime('%Y-%m-%d') if rec.due_date else '',
"应收结束": rec.due_date_end.strftime('%Y-%m-%d') if rec.due_date_end else '',
"金额": amount,
"应收金额": receivable_amount,
"管理员": {
'model': 'res.users',
'id': rec.admin_id.id,
'display_name': rec.admin_id.name,
} if rec.admin_id else "",
})
stats = [
{'name': '记录总数', 'amount': len(rows)},
{'name': '预收总额', 'amount': round(total_amount, 2)},
]
return {"rows": rows, "stats": stats}