Files
gzth/yuthon_report/models/month_receivable_report.py
T
2026-06-17 18:01:58 +08:00

141 lines
6.1 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
import calendar
from odoo import api, models
from .report_utils import _id_list # 导入工具函数:将参数转换为列表格式,支持多选筛选
class MonthReceivableReport(models.Model):
_inherit = 'receivable.modify.line'
@api.model
def get_month_receivable_report(self, params):
"""本月应收(数据源:receivable.modify.line):
- 应收日期(due_date)在查询月内(本月该收的账单)
- 有收款记录(reconciliation_date != False)
- 排除跨月预收:reconciliation_date < due_date 且不在同年同月
- 金额取收款记录的 amount
- 按应收账单聚合,每张账单只出一行
"""
# 解析查询月
query_date = datetime.datetime.fromisoformat(params['date_start']).date() if params.get('date_start') else datetime.date.today().replace(day=1)
summary_only = params.get("summary_only", False)
month_first = query_date.replace(day=1)
last_day = calendar.monthrange(query_date.year, query_date.month)[1]
month_last = query_date.replace(day=last_day)
domain = [
('reconciliation_date', '!=', False),
('receivable_id.due_date', '>=', month_first),
('receivable_id.due_date', '<=', month_last),
('receivable_id.is_invalid', '!=', True),
]
if params.get('keyword'):
keyword = params['keyword']
domain += ['|', '|',
('receivable_id.lessee_id.name', 'ilike', keyword),
('receivable_id.property_name', 'ilike', keyword),
('receivable_id.contract_id.contract_code', 'ilike', keyword)]
condition = params.get('condition')
partner_id = _id_list(params.get('partner_id')) # 将partner_id转换为列表,用于多选筛选
company_id = _id_list(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', 'in', partner_id)) # 使用in操作符支持多选片区筛选
if company_id:
domain.append(('receivable_id.company_id', 'in', 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))
lines = self.sudo().search(domain, order='receivable_id asc, reconciliation_date asc')
# 排除跨月预收:收款日期早于应收日期且不在同年同月
lines = lines.filtered(
lambda l: not (
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
if summary_only:
total_amount = sum(round(data['amount'], 2) for data in rec_map.values())
stats = [{'name': '合计', 'amount': round(total_amount, 2)}]
return {'rows': [], 'stats': stats}
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': round(total_amount, 2)}]
return {'rows': rows, 'stats': stats}