diff --git a/yuthon_report/models/cum_arrears_report.py b/yuthon_report/models/cum_arrears_report.py index 8d5382be9..633253e9f 100644 --- a/yuthon_report/models/cum_arrears_report.py +++ b/yuthon_report/models/cum_arrears_report.py @@ -31,7 +31,7 @@ class CumArrearsReport(models.Model): # 核心逻辑:due_date <= query_month_end(应收日期在查询月及之前,包含查询月) domain = [ ('receivable_id.due_date', '<=', query_month_end), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] keyword = params.get("keyword") diff --git a/yuthon_report/models/cum_income_report.py b/yuthon_report/models/cum_income_report.py index 53cfba32a..17f16bb94 100644 --- a/yuthon_report/models/cum_income_report.py +++ b/yuthon_report/models/cum_income_report.py @@ -31,7 +31,7 @@ class CumIncomeReport(models.Model): domain = [ ('receivable_id.due_date', '>=', year_start), ('receivable_id.due_date', '<=', year_end), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] keyword = params.get("keyword") diff --git a/yuthon_report/models/deposit_cum_arrears_report.py b/yuthon_report/models/deposit_cum_arrears_report.py index 2acbbadca..d7fed7801 100644 --- a/yuthon_report/models/deposit_cum_arrears_report.py +++ b/yuthon_report/models/deposit_cum_arrears_report.py @@ -26,7 +26,7 @@ class DepositCumArrearsReport(models.Model): domain = [ ('management_type_id.name', '=', '押金'), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('due_date', '>=', month_first), ('due_date', '<=', month_last), ('submitted', '>', 0), diff --git a/yuthon_report/models/deposit_month_receivable_report.py b/yuthon_report/models/deposit_month_receivable_report.py index db41271a9..861e32be9 100644 --- a/yuthon_report/models/deposit_month_receivable_report.py +++ b/yuthon_report/models/deposit_month_receivable_report.py @@ -25,7 +25,7 @@ class DepositMonthReceivableReport(models.Model): domain = [ ('due_date', '>=', month_first), ('due_date', '<=', month_last), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('management_type_id.name', '=', '押金'), ] diff --git a/yuthon_report/models/deposit_month_received_report.py b/yuthon_report/models/deposit_month_received_report.py index 8a6a01fb1..22365ae12 100644 --- a/yuthon_report/models/deposit_month_received_report.py +++ b/yuthon_report/models/deposit_month_received_report.py @@ -27,7 +27,7 @@ class DepositMonthReceivedReport(models.Model): domain = [ ('management_type_id.name', '=', '押金'), ('deposit_state', 'in', ['paid', 'no_paid']), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('payout_date', '>=', month_first), ('payout_date', '<=', month_last), ] diff --git a/yuthon_report/models/deposit_pre_received_report.py b/yuthon_report/models/deposit_pre_received_report.py index 7aa9ec208..ca0f43a6c 100644 --- a/yuthon_report/models/deposit_pre_received_report.py +++ b/yuthon_report/models/deposit_pre_received_report.py @@ -25,7 +25,7 @@ class DepositPreReceivedReport(models.Model): domain = [ ('management_type_id.name', '=', '押金'), ('deposit_state', '=', 'paid'), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('payout_date', '!=', False), ('payout_date', '<', month_first), ] diff --git a/yuthon_report/models/deposit_total_report.py b/yuthon_report/models/deposit_total_report.py index 58c0957c1..dce6e57db 100644 --- a/yuthon_report/models/deposit_total_report.py +++ b/yuthon_report/models/deposit_total_report.py @@ -36,7 +36,7 @@ class DepositTotalReport(models.Model): domain = [ ('management_type_id.name', '=', '押金'), ('deposit_state', '=', 'paid'), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('payout_date', '>=', month_first), ('payout_date', '<=', month_last), ] diff --git a/yuthon_report/models/hydropower_report.py b/yuthon_report/models/hydropower_report.py index b348e8a43..310016392 100644 --- a/yuthon_report/models/hydropower_report.py +++ b/yuthon_report/models/hydropower_report.py @@ -30,14 +30,14 @@ class HydropowerReport(models.Model): ('payout_date', '>=', start_date), ('payout_date', '<=', end_date), ('management_type_id.name', '=', '水费'), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ]) electric_records = self.env['property.accounts.receivable'].search([ ('payout_date', '>=', start_date), ('payout_date', '<=', end_date), ('management_type_id.name', '=', '电费'), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ]) # 整合数据,按物业(合同关联的第一个物业)聊合 diff --git a/yuthon_report/models/month_receivable_report.py b/yuthon_report/models/month_receivable_report.py index 901fca5c6..d6ab5cd37 100644 --- a/yuthon_report/models/month_receivable_report.py +++ b/yuthon_report/models/month_receivable_report.py @@ -26,7 +26,7 @@ class MonthReceivableReport(models.Model): ('reconciliation_date', '!=', False), ('receivable_id.due_date', '>=', month_first), ('receivable_id.due_date', '<=', month_last), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] if params.get('keyword'): diff --git a/yuthon_report/models/monthly_precollection_report.py b/yuthon_report/models/monthly_precollection_report.py index 6cea7ec3b..7cb3a4841 100644 --- a/yuthon_report/models/monthly_precollection_report.py +++ b/yuthon_report/models/monthly_precollection_report.py @@ -29,7 +29,7 @@ class MonthlyPrecollectionReport(models.Model): domain = [ ('reconciliation_date', '>=', month_start), ('reconciliation_date', '<=', month_end), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] keyword = params.get("keyword") diff --git a/yuthon_report/models/penalty_arrears_report.py b/yuthon_report/models/penalty_arrears_report.py index 0fb12a2e5..5c907f99c 100644 --- a/yuthon_report/models/penalty_arrears_report.py +++ b/yuthon_report/models/penalty_arrears_report.py @@ -19,7 +19,7 @@ class PenaltyArrearsReport(models.Model): domain = [ ('submitted', '>', 0), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ] date_start = params.get("date_start") diff --git a/yuthon_report/models/penalty_month_received_report.py b/yuthon_report/models/penalty_month_received_report.py index 7e60fc5da..eade5a031 100644 --- a/yuthon_report/models/penalty_month_received_report.py +++ b/yuthon_report/models/penalty_month_received_report.py @@ -32,7 +32,7 @@ class PenaltyMonthReceivedReport(models.Model): domain = [ ('payout_date', '>=', start_dt), ('payout_date', '<=', end_dt), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ] # 违约金过滤 diff --git a/yuthon_report/models/penalty_year_cum_report.py b/yuthon_report/models/penalty_year_cum_report.py index 428b80a98..f15dbfcac 100644 --- a/yuthon_report/models/penalty_year_cum_report.py +++ b/yuthon_report/models/penalty_year_cum_report.py @@ -29,7 +29,7 @@ class PenaltyYearCumReport(models.Model): domain = [ ('payout_date', '>=', start_dt), ('payout_date', '<=', end_dt), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ] # 违约金过滤 diff --git a/yuthon_report/models/pre_advance_report.py b/yuthon_report/models/pre_advance_report.py index 56829a01a..237ce06fa 100644 --- a/yuthon_report/models/pre_advance_report.py +++ b/yuthon_report/models/pre_advance_report.py @@ -33,7 +33,7 @@ class PreAdvanceReport(models.Model): domain = [ ('reconciliation_date', '!=', False), ('receivable_id.due_date', '>=', cutoff_month_first), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] keyword = params.get("keyword") diff --git a/yuthon_report/models/pre_arrears_report.py b/yuthon_report/models/pre_arrears_report.py index bd4ac5799..049977c7d 100644 --- a/yuthon_report/models/pre_arrears_report.py +++ b/yuthon_report/models/pre_arrears_report.py @@ -1,7 +1,10 @@ import datetime +import logging from odoo import api, models +_logger = logging.getLogger(__name__) + class PreArrearsReport(models.Model): _inherit = 'receivable.modify.line' @@ -10,15 +13,17 @@ class PreArrearsReport(models.Model): def get_pre_arrears_report(self, params): """ 前期欠收报表(数据源:receivable.modify.line): - - 查询条件的日期对应应收账单的 due_date(应收日期在查询月及之前) + - 查询条件的日期对应应收账单的 due_date(应收日期在查询月之前,不包含查询月) - 欠收条件: - - 收款日期在查询月之后(查询月时点还没收到钱) - - 或者 not_collected > 0 (部分收款,还没交完) + - 收款日期(payout_date)为空: 从未收款 → 欠收 + - 收款日期在查询月之后: 查询月时点还没收到钱 → 欠收 + - 收款日期 <= 查询月末: 已经交过了 → 不算欠收 - 金额取值: - 如果 not_collected > 0,取 not_collected (当前还欠的金额) - - 否则取 amount (已收金额) + - 否则取 amount (已对金额) - 按应收账单聚合,每张账单只出一行(汇总该账单下所有欠收收款金额) - - 补充: 对于从未对过账但 submitted > 0 的应收账单,直接从 accounts.receivable 取数 + - 补充: 对于真正从未对过账(在 modify.line 表中无任何记录)但 submitted > 0 的应收账单, + 直接从 accounts.receivable 取数补齐 """ today = datetime.date.today() this_month_first = today.replace(day=1) @@ -47,7 +52,7 @@ class PreArrearsReport(models.Model): # 核心逻辑:due_date < query_month_start(应收日期在查询月之前,不包含查询月) domain = [ ('receivable_id.due_date', '<', query_month_start), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] if keyword: @@ -75,19 +80,19 @@ class PreArrearsReport(models.Model): else: domain.append(('receivable_id.management_type_id.name', 'not in', ['押金', '违约金'])) + _logger.info("=== PRE_ARREARS Part1: modify.line search ===") + _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") - - # 欠收条件(同时满足): - # 1. payout_date >= query_month_start (收款日期不能小于查询月) - # 2. 满足以下任一: - # a. payout_date > query_month_end (收款日期在查询月之后,查询月时点还没收到钱) - # b. not_collected > 0 (部分收款,还没交完) + _logger.info("Part1 search found %s modify.line records", len(lines)) + + # 欠收条件:收款日期为空(从未收款) 或 收款日期在查询月之后(查询月时点还没收到钱) + # 如果 payout_date <= query_month_end,说明查询月及之前已经交过了,不算欠收 lines = lines.filtered( - lambda l: l.payout_date and l.payout_date >= query_month_start and ( - (l.payout_date > query_month_end) or - (l.not_collected and l.not_collected > 0) - ) + lambda l: not l.payout_date or l.payout_date > query_month_end ) + _logger.info("Part1 after欠收filter: %s records remain", len(lines)) # 按应收账单聚合 rec_map = {} @@ -104,19 +109,31 @@ class PreArrearsReport(models.Model): rec_map[rid]['discount_amount'] = line.receivable_id.discount_amount or 0.0 # ============================================================ - # 第二部分:补充从未对过账但 submitted > 0 的应收账单 - # modify.line 只能查到已对过账的记录。如果一笔应收账单从未对过账, - # submitted > 0(未收金额>0)但 modify.line 中没有对应记录, - # 直接从 property.accounts.receivable 取数补齐 + # 第二部分:补充真正从未对过账 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 会被错误地纳入欠收。 # ============================================================ covered_ids = list(rec_map.keys()) + + # 找出所有在 modify.line 中有记录的 receivable_id(不管 payout_date 是什么时候) + all_line_receivable_ids = set( + self.sudo().search([('receivable_id', '!=', False)]).mapped('receivable_id.id') + ) + # Part 2 只查真正"从未对过账"的 receivable + exclude_ids = all_line_receivable_ids # 包含 covered_ids 和 payout_date 被过滤掉的 + receivable_domain = [ ('due_date', '<', query_month_start), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('submitted', '>', 0), ] - if covered_ids: - receivable_domain.append(('id', 'not in', covered_ids)) + if exclude_ids: + receivable_domain.append(('id', 'not in', list(exclude_ids))) # 同样的筛选条件(去掉 receivable_id. 前缀,直接查 accounts.receivable 自身字段) if keyword: diff --git a/yuthon_report/models/receivable_flow_report.py b/yuthon_report/models/receivable_flow_report.py index c47687161..9641e63f6 100644 --- a/yuthon_report/models/receivable_flow_report.py +++ b/yuthon_report/models/receivable_flow_report.py @@ -15,7 +15,7 @@ class ReceivableFlowReport(models.Model): - 仅考虑当前公司/日期范围内的应收记录 """ domain = [ - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ] date_start = params.get("date_start") @@ -59,7 +59,7 @@ class ReceivableFlowReport(models.Model): - 包括基本信息、收款情况和违约金相关信息 """ domain = [ - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ] date_start = params.get("date_start") @@ -112,7 +112,7 @@ class ReceivableFlowReport(models.Model): penalty_receivables = self.env['property.accounts.receivable'].sudo().search([ ('contract_id', 'in', receivables.mapped('contract_id').ids), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('management_type_id.name', '=', '违约金'), ]) penalty_source_map = {} @@ -230,7 +230,7 @@ class ReceivableFlowReport(models.Model): 'model': 'property.accounts.receivable', 'display_name': str(round(contract_total_receivable, 2)), 'view_mode': 'tree', - 'domain': [('contract_id', '=', contract.id if contract else 0), ('is_invalid', '=', False)], + 'domain': [('contract_id', '=', contract.id if contract else 0), ('is_invalid', '!=', True)], }, "收款总金额": { 'model': 'receivable.modify.line', diff --git a/yuthon_report/models/receivable_report.py b/yuthon_report/models/receivable_report.py index 87a0734b0..3851c1035 100644 --- a/yuthon_report/models/receivable_report.py +++ b/yuthon_report/models/receivable_report.py @@ -44,7 +44,7 @@ class YuthonProperty(models.Model): @api.model def get_complete_ledger_report(self, params): - domain = [('is_invalid', '=', False)] + domain = [('is_invalid', '!=', True)] if params.get("keyword"): keyword = params["keyword"] domain += [ diff --git a/yuthon_report/models/total_received_report.py b/yuthon_report/models/total_received_report.py index 5648dab89..e263177b3 100644 --- a/yuthon_report/models/total_received_report.py +++ b/yuthon_report/models/total_received_report.py @@ -14,7 +14,7 @@ class TotalReceivedReport(models.Model): """ domain = [ ('reconciliation_date', '!=', False), - ('receivable_id.is_invalid', '=', False), + ('receivable_id.is_invalid', '!=', True), ] # 收款日期在查询月内 diff --git a/yuthon_report/models/yuthon_dashboard.py b/yuthon_report/models/yuthon_dashboard.py index adb14d0f2..da07ffccb 100644 --- a/yuthon_report/models/yuthon_dashboard.py +++ b/yuthon_report/models/yuthon_dashboard.py @@ -296,7 +296,7 @@ class YuthonDashboard(models.Model): domain = [ ('due_date', '>=', month_first), ('due_date', '<=', month_last), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('management_type_id.name', 'ilike', keyword_match), ] if company_id: @@ -317,7 +317,7 @@ class YuthonDashboard(models.Model): year_domain = [ ('due_date', '>=', year_start), ('due_date', '<=', month_last), - ('is_invalid', '=', False), + ('is_invalid', '!=', True), ('management_type_id.name', 'ilike', keyword_match), ] if company_id: