From 48a7a301d2ea3464787b3ce6ceba373af2c175a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Wed, 8 Jul 2026 16:37:46 +0800 Subject: [PATCH] =?UTF-8?q?=E7=B4=AF=E8=AE=A1=E6=AC=A0=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_report/models/cum_arrears_report.py | 80 +++++++++++++++++++--- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/yuthon_report/models/cum_arrears_report.py b/yuthon_report/models/cum_arrears_report.py index c3b891548..bd55dd11f 100644 --- a/yuthon_report/models/cum_arrears_report.py +++ b/yuthon_report/models/cum_arrears_report.py @@ -1,9 +1,12 @@ import calendar import datetime +import logging from odoo import api, models from .report_utils import _id_list # 导入工具函数:将参数转换为列表格式,支持多选筛选 +_logger = logging.getLogger(__name__) + class CumArrearsReport(models.Model): _inherit = 'receivable.modify.line' @@ -11,15 +14,16 @@ class CumArrearsReport(models.Model): @api.model def get_cum_arrears_report(self, params): """ - 累计欠收报表(数据源:receivable.modify.line): - - 查询条件的日期对应应收账单的 due_date(应收日期在查询月及之前,包含查询月) - - 欠收条件: - - 收款日期在查询月及之后(查询月时点还没收到钱) - - 或者 not_collected > 0 (部分收款,还没交完) - - 金额取值: - - 如果 not_collected > 0,取 not_collected (当前还欠的金额) - - 否则取 amount (已收金额) - - 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额) + 累计欠收报表(两路取数): + - Part1: receivable.modify.line — 有收款记录但欠收的账单 + - due_date <= query_month_end(含查询月) + - 欠收条件: reconciliation_date >= 查询月1号 且 (reconciliation_date > 查询月末 或 not_collected > 0) + - 金额取值: not_collected > 0 取 not_collected,否则取 amount + - Part2: property.accounts.receivable — 从未对账且从未收款的账单 + - is_reconciliation=False, payout_date=False, due_date <= query_month_end + - 金额取值: submitted(未收金额) + - 排除 Part1 已覆盖的 receivable_id + - 按应收账单聚合,每张账单只出一行 """ today = datetime.date.today() this_month_first = today.replace(day=1) @@ -101,6 +105,64 @@ class CumArrearsReport(models.Model): if line.reconciliation_date: rec_map[rid]['reconciliation_dates'].append(line.reconciliation_date) + # ============================================================ + # 第二部分:从 property.accounts.receivable 取 is_reconciliation=False 的记录 + # 即:未对过账且未收款(payout_date为空)的应收账单,due_date <= query_month_end(含查询月) + # 这类账单没有 modify.line 收款记录,Part1 查不到,需要补充 + # 欠收金额取 submitted(未收金额字段) + # ============================================================ + covered_ids = list(rec_map.keys()) # Part1 已覆盖的 receivable_id + + receivable_domain = [ + ('is_reconciliation', '=', False), # 未对过账 + ('due_date', '<=', query_month_end), # 累计欠收:含查询月 + ('payout_date', '=', False), # 从未收款 + ('is_invalid', '!=', True), # 排除作废 + ] + if covered_ids: + receivable_domain.append(('id', 'not in', list(covered_ids))) # 排除 Part1 已有的 + + # 同样的筛选条件(去掉 receivable_id. 前缀,直接查 accounts.receivable 自身字段) + if keyword: + receivable_domain += [ + '|', '|', + ('contract_id.contract_code', 'ilike', keyword), + ('property_name', 'ilike', keyword), + ('lessee_id.name', 'ilike', keyword), + ] + if condition: + receivable_domain.append(('tenure_type', '=', condition)) + if partner_id: + receivable_domain.append(('precinct_id', 'in', partner_id)) # 多选:片区管理员用 in 操作符 + if company_id: + receivable_domain.append(('company_id', 'in', company_id)) + if property_id: + receivable_domain.append(('property_ids', 'in', [property_id])) + if lessee_id: + receivable_domain.append(('lessee_id', '=', lessee_id)) + if contract_id: + receivable_domain.append(('contract_id', '=', contract_id)) + if management_type_id: + receivable_domain.append(('management_type_id', '=', management_type_id)) + else: + receivable_domain.append(('management_type_id.name', 'not in', ['押金', '违约金'])) + + unreconciled_receivables = self.env['property.accounts.receivable'].sudo().search( + receivable_domain, order="due_date asc") + _logger.info("[CUM_ARREARS] Part2 从 accounts.receivable(is_reconciliation=False) 补充 %d 条", len(unreconciled_receivables)) + + for rec in unreconciled_receivables: + rid = rec.id + # 未对过账的应收账单,欠收金额 = submitted + rec_map[rid] = { + 'rec': rec, + 'amount': rec.submitted or 0.0, + 'reconciliation_dates': [], + } + + # ============================================================ + # 构建返回数据 + # ============================================================ rows = [] total_amount = 0.0 if summary_only: