From e38108db6b4167857a4f78a0151dd8baebbacd45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Thu, 18 Jun 2026 19:25:09 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=A5=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yuthon_report/models/pre_arrears_report.py | 79 ++++++++-------------- 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/yuthon_report/models/pre_arrears_report.py b/yuthon_report/models/pre_arrears_report.py index 2125832bb..163cd0ddc 100644 --- a/yuthon_report/models/pre_arrears_report.py +++ b/yuthon_report/models/pre_arrears_report.py @@ -13,18 +13,14 @@ class PreArrearsReport(models.Model): @api.model def get_pre_arrears_report(self, params): """ - 前期欠收报表(数据源:receivable.modify.line): - - 查询条件的日期对应应收账单的 due_date(应收日期在查询月之前,不包含查询月) - - 欠收条件(二选一): - - 收款日期(payout_date)为空: 从未收款 → 欠收 - - 收款日期所在月 >= 查询月 且 收款日期所在月 > 应收日期所在月: 收款跨月且查询月才收到 → 欠收 - - 同月收款不算欠收(如1月15日收1月1日应收的款) - - 金额取值: - - 如果 not_collected > 0,取 not_collected (当前还欠的金额) - - 否则取 amount (已对金额) - - 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额) - - 补充: 对于真正从未对过账(在 modify.line 表中无任何记录)但 submitted > 0 的应收账单, - 直接从 accounts.receivable 取数补齐 + 前期欠收报表: + - Domain: due_date(应收开始)所在月 < 查询月(不含查询月) + - 数据源分两部分: + 1. receivable.modify.line: 有 reconciliation_date 且 reconciliation_date月 > due_date月 + 且 reconciliation_date月 >= 查询月 → 欠收金额取 amount + 2. property.accounts.receivable: is_reconciliation=False 且 due_date月 < 查询月 + → 从未对过账,欠收金额取 submitted + - 按应收账单聚合,每张账单只出一行 """ today = datetime.date.today() this_month_first = today.replace(day=1) @@ -88,19 +84,16 @@ class PreArrearsReport(models.Model): _logger.info("query_month_start=%s, query_month_end=%s", query_month_start, query_month_end) _logger.info("Part1 domain: %s", domain) - lines = self.sudo().search(domain, order="receivable_id asc, payout_date asc") + lines = self.sudo().search(domain, order="receivable_id asc, reconciliation_date asc") _logger.info("Part1 search found %s modify.line records", len(lines)) - # 欠收条件(二选一): - # 1. 没有收款日期(从未收款)→ 欠收 - # 2. 收款日期所在月 >= 查询月 且 收款日期所在月 > 应收日期所在月 → 欠收 - # 即:收款跨月(交晚了)且收款在查询月或之后才到 - # 同月收款不算欠收(如1月15日收1月1日应收的款) + # 欠收条件:reconciliation_date 有值 且 所在月 > due_date月 且 >= 查询月 + # (交晚了且查询月才收到,取amount) + due_month_start = query_month_start.replace(day=1) lines = lines.filtered( - lambda l: not l.payout_date or ( - l.payout_date.replace(day=1) >= query_month_start and - l.payout_date.replace(day=1) > l.receivable_id.due_date.replace(day=1) - ) + lambda l: l.reconciliation_date and + l.reconciliation_date.replace(day=1) > l.receivable_id.due_date.replace(day=1) and + l.reconciliation_date.replace(day=1) >= due_month_start ) _logger.info("Part1 after欠收filter: %s records remain", len(lines)) @@ -110,44 +103,25 @@ class PreArrearsReport(models.Model): rid = line.receivable_id.id if rid not in rec_map: rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0, 'payout_dates': [], 'discount_amount': 0.0} - # 金额取值:有未收金额取not_collected,否则取amount - rec_map[rid]['amount'] += (line.not_collected if (line.not_collected and line.not_collected > 0) else line.amount) or 0.0 - # 收集收款日期 - if line.payout_date: - rec_map[rid]['payout_dates'].append(line.payout_date) + # 有 reconciliation_date(交晚了),欠收金额取 amount + rec_map[rid]['amount'] += line.amount or 0.0 + rec_map[rid]['payout_dates'].append(line.reconciliation_date) # 应收金额 = original_amount - discount_amount(取 receivable_id 的值) rec_map[rid]['discount_amount'] = line.receivable_id.discount_amount or 0.0 # ============================================================ - # 第二部分:补充真正从未对过账 but submitted > 0 的应收账单 - # Part 1 只能查到有 modify.line 记录且 payout_date > query_month_end 的数据。 - # 对于那些真正从未对过账(在 modify.line 表中无任何记录)的应收账单, - # 直接从 property.accounts.receivable 取数补齐。 - # - # 关键:需要排除所有在 modify.line 中出现过的 receivable_id, - # 不仅仅是 Part 1 覆盖的那些。否则,有 modify.line 但 payout_date - # 早于查询月的 receivable 会被错误地纳入欠收。 + # 第二部分:从 property.accounts.receivable 取 is_reconciliation=False 的记录 + # 即:未对过账的应收账单,due_date月 < 查询月,欠收金额取 submitted # ============================================================ covered_ids = list(rec_map.keys()) - # 找出所有在 modify.line 中有记录的 receivable_id(不管 payout_date 是什么时候) - # 优化:用 read_group 只取 distinct receivable_id,避免全表加载到内存 - all_line_receivable_groups = self.sudo().read_group( - [('receivable_id', '!=', False)], - ['receivable_id'], - ['receivable_id'], - ) - all_line_receivable_ids = set(g['receivable_id'][0] for g in all_line_receivable_groups if g['receivable_id']) - # Part 2 只查真正"从未对过账"的 receivable - exclude_ids = all_line_receivable_ids # 包含 covered_ids 和 payout_date 被过滤掉的 - receivable_domain = [ + ('is_reconciliation', '=', False), ('due_date', '<', query_month_start), ('is_invalid', '!=', True), - ('submitted', '>', 0), ] - if exclude_ids: - receivable_domain.append(('id', 'not in', list(exclude_ids))) + if covered_ids: + receivable_domain.append(('id', 'not in', list(covered_ids))) # 同样的筛选条件(去掉 receivable_id. 前缀,直接查 accounts.receivable 自身字段) if keyword: @@ -175,12 +149,13 @@ class PreArrearsReport(models.Model): else: receivable_domain.append(('management_type_id.name', 'not in', ['押金', '违约金'])) - uncovered_receivables = self.env['property.accounts.receivable'].sudo().search( + unreconciled_receivables = self.env['property.accounts.receivable'].sudo().search( receivable_domain, order="due_date asc") + _logger.info("Part2 从 accounts.receivable(is_reconciliation=False) 补充 %d 条", len(unreconciled_receivables)) - for rec in uncovered_receivables: + for rec in unreconciled_receivables: rid = rec.id - # 从未对过账:欠收金额 = submitted(未收金额),无收款日期 + # 未对过账的应收账单,欠收金额 = submitted rec_map[rid] = { 'rec': rec, 'amount': rec.submitted or 0.0,