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

170 lines
7.0 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 # partner_id 多选适配工具
class DepositMonthReceivedReport(models.Model):
_inherit = 'property.accounts.receivable'
@api.model
def get_deposit_month_received_report(self, params):
"""
押金本月实收报表:
- 数据源:property.accounts.receivable
- 管理费用类型为"押金"
- 非作废记录
- 金额:original_amount - discount_amount
- 状态取数逻辑(放宽 domain + 内存过滤):
- 已收(paid):payout_date 存在且在查询月内(month_first <= payout_date <= month_last)
- 已退(yes):退款日期(has_date) > 查询月末 且 收款日期(payout_date)在查询月内
→ 与前期实收互补,前期实收取 payout_date < month_first,
本月实收取 payout_date 在查询月内,避免同一记录出现在两个报表
"""
date_start = params.get("date_start")
summary_only = params.get("summary_only", False)
query_date = datetime.datetime.fromisoformat(date_start).date() if date_start else datetime.date.today()
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,只做基础筛选
domain = [
('management_type_id.name', '=', '押金'),
('is_invalid', '!=', True),
('deposit_state', 'in', ['paid', 'yes']),
]
keyword = params.get("keyword")
if keyword:
domain += ['|', '|',
('contract_id.contract_code', 'ilike', keyword),
('property_name', 'ilike', keyword),
('lessee_id.name', 'ilike', keyword),
]
condition = params.get('condition')
partner_id = _id_list(params.get('partner_id')) # 支持多选,转为列表
company_id = _id_list(params.get('company_id'))
property_id = params.get('property_id')
lessee_id = params.get('lessee_id')
contract_id = params.get('contract_id')
if condition:
domain.append(('tenure_type', '=', condition))
if partner_id:
domain.append(('precinct_id', 'in', partner_id)) # 多选用 in
if company_id:
domain.append(('company_id', 'in', company_id))
if property_id:
domain.append(('property_ids', 'in', [property_id]))
if lessee_id:
domain.append(('lessee_id', '=', lessee_id))
if contract_id:
domain.append(('contract_id', '=', contract_id))
lines = self.sudo().search(domain, order="contract_id asc")
# 内存过滤:按状态分别处理
# - 已收(paid):收款日期在查询月内(month_first <= payout_date <= month_last)
# - 已退(yes):退款日期 > 查询月末 且 收款日期在查询月内(与前期实收互补,避免重复)
lines = lines.filtered(
lambda l: (
l.deposit_state == 'paid' and l.payout_date and month_first <= l.payout_date <= month_last
) or (
l.deposit_state == 'yes' and l.has_date and l.has_date > month_last
and l.payout_date and month_first <= l.payout_date <= month_last
)
)
if summary_only:
total_amount = sum(round((rec.original_amount or 0.0) - (rec.discount_amount or 0.0), 2) for rec in lines)
stats = [
{'name': '记录总数', 'amount': len(lines)},
{'name': '合计金额', 'amount': round(total_amount, 2)},
]
return {"rows": [], "stats": stats}
rows = []
total_amount = 0.0
for idx, rec in enumerate(lines, start=1):
amount = round((rec.original_amount or 0.0) - (rec.discount_amount or 0.0), 2)
total_amount += amount
contract = rec.contract_id
# 物业穿透
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 ''
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.payout_date.strftime("%Y-%m-%d") if rec.payout_date else "",
"金额": amount,
"应收金额": round((rec.original_amount or 0.0) - (rec.discount_amount or 0.0), 2),
"所属公司": rec.company_id.name if rec.company_id else "",
"管理员": {
'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}
@api.model
def get_receivable_filter_domains(self, params):
"""押金本月实收报表:返回物业/承租方/合同的候选 ID 集合。"""
domain = [
('management_type_id.name', '=', '押金'),
('is_invalid', '!=', True),
]
company_id = _id_list(params.get('company_id'))
property_id = params.get('property_id')
lessee_id = params.get('lessee_id')
contract_id = params.get('contract_id')
if company_id:
domain.append(('company_id', 'in', company_id))
if property_id:
domain.append(('property_ids', 'in', [property_id]))
if lessee_id:
domain.append(('lessee_id', '=', lessee_id))
if contract_id:
domain.append(('contract_id', '=', contract_id))
receivables = self.sudo().search(domain)
property_ids = set(receivables.mapped('property_ids').ids)
lessee_ids = set(receivables.mapped('lessee_id').ids)
contract_ids = set(receivables.mapped('contract_id').ids)
return {
'property_ids': list(property_ids),
'lessee_ids': list(lessee_ids),
'contract_ids': list(contract_ids),
}