From 0e3e6072fc1f5f8c085441a4f0e26e0e9bede3fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Tue, 23 Jun 2026 14:57:36 +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 --- .../views/property_fee_form_views.xml | 4 + .../models/assessment_fee_monthly_report.py | 76 +++++++++--------- .../models/assessment_fee_yearly_report.py | 76 +++++++++--------- .../models/maintenance_fee_monthly_report.py | 76 +++++++++--------- .../models/maintenance_fee_yearly_report.py | 76 +++++++++--------- .../models/management_fee_monthly_report.py | 78 +++++++++---------- .../models/management_fee_yearly_report.py | 76 +++++++++--------- yuthon_report/models/yuthon_dashboard.py | 78 ++++++++++--------- yuthon_report/views/assessment_fee_report.xml | 13 ++-- .../views/assessment_fee_yearly_report.xml | 13 ++-- .../views/maintenance_fee_report.xml | 13 ++-- .../views/maintenance_fee_yearly_report.xml | 13 ++-- yuthon_report/views/management_fee_report.xml | 13 ++-- .../views/management_fee_yearly_report.xml | 13 ++-- 14 files changed, 300 insertions(+), 318 deletions(-) diff --git a/yuthon_property_approval/views/property_fee_form_views.xml b/yuthon_property_approval/views/property_fee_form_views.xml index 84dccba7d..cb4f38664 100644 --- a/yuthon_property_approval/views/property_fee_form_views.xml +++ b/yuthon_property_approval/views/property_fee_form_views.xml @@ -11,6 +11,10 @@ + + + + diff --git a/yuthon_report/models/assessment_fee_monthly_report.py b/yuthon_report/models/assessment_fee_monthly_report.py index 3a922c3bd..22285d18e 100644 --- a/yuthon_report/models/assessment_fee_monthly_report.py +++ b/yuthon_report/models/assessment_fee_monthly_report.py @@ -8,18 +8,19 @@ from .report_utils import _id_list # 导入 ID 列表解析工具函数,支 _logger = logging.getLogger(__name__) -class PropertyBillsList(models.Model): - _inherit = 'property.bills.list' +class PropertyFeeForm(models.Model): + # 改为继承 property.fee.form 模型 + _inherit = 'property.fee.form' @api.model def get_assessment_fee_monthly_report(self, params): """评估费本月支出报表。 - 数据源:property.bills.list + 数据源:property.fee.form 过滤条件: - - management_type_id.name = '评估费' - - actual_date(实付日期)在查询月本月范围内(月初~月末) - 字段:应付日期、实付日期、应付、实付、标题 + - expenses_type.name = '评估费' + - pay_date(支付日期)在查询月本月范围内(月初~月末) + 字段:标题、所属公司、支付金额、申请人、支付日期、权属类型 """ # ========== 一、参数解析 ========== date_start = params.get("date_start") @@ -41,68 +42,61 @@ class PropertyBillsList(models.Model): # ========== 三、构建domain ========== domain = [ - ('management_type_id.name', '=', '评估费'), - ('actual_date', '>=', month_first), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', '评估费'), # 支出类型为评估费 + ('pay_date', '>=', month_first), # 支付日期在查询月月初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月月末及以前 ] - # 关键字过滤 + # 关键字过滤:按标题模糊搜索 if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword), - ] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - # 公司/片区过滤 + # 公司过滤:company_id1 为所属公司字段 company_id = _id_list(params.get('company_id')) partner_id = _id_list(params.get('partner_id')) # 解析片区 ID 为整数列表(多选支持) if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) + # 片区(partner_id):通过 precinct.message -> employee -> user 关联申请人 if partner_id: - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), # 合同片区过滤(多选支持) - ('receivables_id.precinct_id', 'in', partner_id), # 应收记录片区过滤(多选支持) - ] + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + domain.append(('id', '=', False)) # 查询记录 - records = self.sudo().search(domain) + records = self.sudo().search(domain, order='pay_date asc') # ========== 四、构建报表行 ========== rows = [] - total_amount = 0.0 # 应付合计 - total_amount_actual = 0.0 # 实付合计 + total_fee = 0.0 # 支付金额合计 for idx, rec in enumerate(records, start=1): - due_date_str = rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "" - actual_date_str = rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "" - amount_val = round(rec.amount or 0.0, 2) - amount_actual_val = round(rec.amount_actual or 0.0, 2) - - total_amount += amount_val - total_amount_actual += amount_actual_val + pay_date_str = rec.pay_date.strftime("%Y-%m-%d") if rec.pay_date else "" + fee_val = round(rec.form_fee or 0.0, 2) + total_fee += fee_val rows.append({ "序号": idx, - "应付日期": due_date_str, - "实付日期": actual_date_str, - "应付": amount_val, - "实付": amount_actual_val, "标题": rec.name or "", + "所属公司": rec.company_id1.name if rec.company_id1 else "", + "支付金额": fee_val, + "申请人": rec.users_id.name if rec.users_id else "", + "支付日期": pay_date_str, + "权属类型": dict(rec._fields['tenure_type'].selection).get(rec.tenure_type, rec.tenure_type or ""), }) # ========== 五、构建统计汇总数据 ========== stats = [ {'name': '记录总数', 'amount': len(rows)}, - {'name': '应付合计', 'amount': round(total_amount, 2)}, - {'name': '实付合计', 'amount': round(total_amount_actual, 2)}, + {'name': '支付合计', 'amount': round(total_fee, 2)}, ] _logger.info( - "[ASSESSMENT_FEE_MONTHLY] query_date=%s, month_range=[%s, %s], rows=%d, " - "total_amount=%.2f, total_amount_actual=%.2f", - query_date, month_first, month_last, len(rows), total_amount, total_amount_actual, + "[ASSESSMENT_FEE_MONTHLY] query_date=%s, month_range=[%s, %s], rows=%d, total_fee=%.2f", + query_date, month_first, month_last, len(rows), total_fee, ) return {"rows": rows, "stats": stats} diff --git a/yuthon_report/models/assessment_fee_yearly_report.py b/yuthon_report/models/assessment_fee_yearly_report.py index bdfc5d630..bc272cfc5 100644 --- a/yuthon_report/models/assessment_fee_yearly_report.py +++ b/yuthon_report/models/assessment_fee_yearly_report.py @@ -8,18 +8,19 @@ from .report_utils import _id_list # 导入 ID 列表解析工具函数,支 _logger = logging.getLogger(__name__) -class PropertyBillsList(models.Model): - _inherit = 'property.bills.list' +class PropertyFeeForm(models.Model): + # 改为继承 property.fee.form 模型 + _inherit = 'property.fee.form' @api.model def get_assessment_fee_yearly_report(self, params): """评估费本年累计报表。 - 数据源:property.bills.list + 数据源:property.fee.form 过滤条件: - - management_type_id.name = '评估费' - - actual_date(实付日期)在查询月所在年的1月1日~查询月末 - 字段:应付日期、实付日期、应付、实付、标题 + - expenses_type.name = '评估费' + - pay_date(支付日期)在查询月所在年的1月1日~查询月末 + 字段:标题、所属公司、支付金额、申请人、支付日期、权属类型 """ # ========== 一、参数解析 ========== date_start = params.get("date_start") @@ -41,68 +42,61 @@ class PropertyBillsList(models.Model): # ========== 三、构建domain ========== domain = [ - ('management_type_id.name', '=', '评估费'), - ('actual_date', '>=', year_start), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', '评估费'), # 支出类型为评估费 + ('pay_date', '>=', year_start), # 支付日期在年初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月末及以前 ] - # 关键字过滤 + # 关键字过滤:按标题模糊搜索 if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword), - ] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - # 公司/片区过滤 + # 公司过滤:company_id1 为所属公司字段 company_id = _id_list(params.get('company_id')) partner_id = _id_list(params.get('partner_id')) # 解析片区 ID 为整数列表(多选支持) if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) + # 片区(partner_id):通过 precinct.message -> employee -> user 关联申请人 if partner_id: - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), # 合同片区过滤(多选支持) - ('receivables_id.precinct_id', 'in', partner_id), # 应收记录片区过滤(多选支持) - ] + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + domain.append(('id', '=', False)) # 查询记录 - records = self.sudo().search(domain) + records = self.sudo().search(domain, order='pay_date asc') # ========== 四、构建报表行 ========== rows = [] - total_amount = 0.0 # 应付合计 - total_amount_actual = 0.0 # 实付合计 + total_fee = 0.0 # 支付金额合计 for idx, rec in enumerate(records, start=1): - due_date_str = rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "" - actual_date_str = rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "" - amount_val = round(rec.amount or 0.0, 2) - amount_actual_val = round(rec.amount_actual or 0.0, 2) - - total_amount += amount_val - total_amount_actual += amount_actual_val + pay_date_str = rec.pay_date.strftime("%Y-%m-%d") if rec.pay_date else "" + fee_val = round(rec.form_fee or 0.0, 2) + total_fee += fee_val rows.append({ "序号": idx, - "应付日期": due_date_str, - "实付日期": actual_date_str, - "应付": amount_val, - "实付": amount_actual_val, "标题": rec.name or "", + "所属公司": rec.company_id1.name if rec.company_id1 else "", + "支付金额": fee_val, + "申请人": rec.users_id.name if rec.users_id else "", + "支付日期": pay_date_str, + "权属类型": dict(rec._fields['tenure_type'].selection).get(rec.tenure_type, rec.tenure_type or ""), }) # ========== 五、构建统计汇总数据 ========== stats = [ {'name': '记录总数', 'amount': len(rows)}, - {'name': '应付合计', 'amount': round(total_amount, 2)}, - {'name': '实付合计', 'amount': round(total_amount_actual, 2)}, + {'name': '支付合计', 'amount': round(total_fee, 2)}, ] _logger.info( - "[ASSESSMENT_FEE_YEARLY] query_date=%s, year_range=[%s, %s], rows=%d, " - "total_amount=%.2f, total_amount_actual=%.2f", - query_date, year_start, month_last, len(rows), total_amount, total_amount_actual, + "[ASSESSMENT_FEE_YEARLY] query_date=%s, year_range=[%s, %s], rows=%d, total_fee=%.2f", + query_date, year_start, month_last, len(rows), total_fee, ) return {"rows": rows, "stats": stats} diff --git a/yuthon_report/models/maintenance_fee_monthly_report.py b/yuthon_report/models/maintenance_fee_monthly_report.py index 15b5c3537..a38ea13c6 100644 --- a/yuthon_report/models/maintenance_fee_monthly_report.py +++ b/yuthon_report/models/maintenance_fee_monthly_report.py @@ -8,18 +8,19 @@ from .report_utils import _id_list # 导入 ID 列表解析工具函数,支 _logger = logging.getLogger(__name__) -class PropertyBillsList(models.Model): - _inherit = 'property.bills.list' +class PropertyFeeForm(models.Model): + # 改为继承 property.fee.form 模型 + _inherit = 'property.fee.form' @api.model def get_maintenance_fee_monthly_report(self, params): """维修费本月支出报表。 - 数据源:property.bills.list + 数据源:property.fee.form 过滤条件: - - management_type_id.name = '维修费' - - actual_date(实付日期)在查询月本月范围内(月初~月末) - 字段:应付日期、实付日期、应付、实付、标题 + - expenses_type.name = '维修费' + - pay_date(支付日期)在查询月本月范围内(月初~月末) + 字段:标题、所属公司、支付金额、申请人、支付日期、权属类型 """ # ========== 一、参数解析 ========== date_start = params.get("date_start") @@ -41,68 +42,61 @@ class PropertyBillsList(models.Model): # ========== 三、构建domain ========== domain = [ - ('management_type_id.name', '=', '维修费'), - ('actual_date', '>=', month_first), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', '维修费'), # 支出类型为维修费 + ('pay_date', '>=', month_first), # 支付日期在查询月月初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月月末及以前 ] - # 关键字过滤 + # 关键字过滤:按标题模糊搜索 if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword), - ] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - # 公司/片区过滤 + # 公司过滤:company_id1 为所属公司字段 company_id = _id_list(params.get('company_id')) partner_id = _id_list(params.get('partner_id')) # 解析片区 ID 为整数列表(多选支持) if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) + # 片区(partner_id):通过 precinct.message -> employee -> user 关联申请人 if partner_id: - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), # 合同片区过滤(多选支持) - ('receivables_id.precinct_id', 'in', partner_id), # 应收记录片区过滤(多选支持) - ] + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + domain.append(('id', '=', False)) # 查询记录 - records = self.sudo().search(domain) + records = self.sudo().search(domain, order='pay_date asc') # ========== 四、构建报表行 ========== rows = [] - total_amount = 0.0 # 应付合计 - total_amount_actual = 0.0 # 实付合计 + total_fee = 0.0 # 支付金额合计 for idx, rec in enumerate(records, start=1): - due_date_str = rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "" - actual_date_str = rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "" - amount_val = round(rec.amount or 0.0, 2) - amount_actual_val = round(rec.amount_actual or 0.0, 2) - - total_amount += amount_val - total_amount_actual += amount_actual_val + pay_date_str = rec.pay_date.strftime("%Y-%m-%d") if rec.pay_date else "" + fee_val = round(rec.form_fee or 0.0, 2) + total_fee += fee_val rows.append({ "序号": idx, - "应付日期": due_date_str, - "实付日期": actual_date_str, - "应付": amount_val, - "实付": amount_actual_val, "标题": rec.name or "", + "所属公司": rec.company_id1.name if rec.company_id1 else "", + "支付金额": fee_val, + "申请人": rec.users_id.name if rec.users_id else "", + "支付日期": pay_date_str, + "权属类型": dict(rec._fields['tenure_type'].selection).get(rec.tenure_type, rec.tenure_type or ""), }) # ========== 五、构建统计汇总数据 ========== stats = [ {'name': '记录总数', 'amount': len(rows)}, - {'name': '应付合计', 'amount': round(total_amount, 2)}, - {'name': '实付合计', 'amount': round(total_amount_actual, 2)}, + {'name': '支付合计', 'amount': round(total_fee, 2)}, ] _logger.info( - "[MAINTENANCE_FEE_MONTHLY] query_date=%s, month_range=[%s, %s], rows=%d, " - "total_amount=%.2f, total_amount_actual=%.2f", - query_date, month_first, month_last, len(rows), total_amount, total_amount_actual, + "[MAINTENANCE_FEE_MONTHLY] query_date=%s, month_range=[%s, %s], rows=%d, total_fee=%.2f", + query_date, month_first, month_last, len(rows), total_fee, ) return {"rows": rows, "stats": stats} diff --git a/yuthon_report/models/maintenance_fee_yearly_report.py b/yuthon_report/models/maintenance_fee_yearly_report.py index b915ac4d6..bf18ad720 100644 --- a/yuthon_report/models/maintenance_fee_yearly_report.py +++ b/yuthon_report/models/maintenance_fee_yearly_report.py @@ -8,18 +8,19 @@ from .report_utils import _id_list # 导入 ID 列表解析工具函数,支 _logger = logging.getLogger(__name__) -class PropertyBillsList(models.Model): - _inherit = 'property.bills.list' +class PropertyFeeForm(models.Model): + # 改为继承 property.fee.form 模型 + _inherit = 'property.fee.form' @api.model def get_maintenance_fee_yearly_report(self, params): """维修费本年累计报表。 - 数据源:property.bills.list + 数据源:property.fee.form 过滤条件: - - management_type_id.name = '维修费' - - actual_date(实付日期)在查询月所在年的1月1日~查询月末 - 字段:应付日期、实付日期、应付、实付、标题 + - expenses_type.name = '维修费' + - pay_date(支付日期)在查询月所在年的1月1日~查询月末 + 字段:标题、所属公司、支付金额、申请人、支付日期、权属类型 """ # ========== 一、参数解析 ========== date_start = params.get("date_start") @@ -41,68 +42,61 @@ class PropertyBillsList(models.Model): # ========== 三、构建domain ========== domain = [ - ('management_type_id.name', '=', '维修费'), - ('actual_date', '>=', year_start), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', '维修费'), # 支出类型为维修费 + ('pay_date', '>=', year_start), # 支付日期在年初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月末及以前 ] - # 关键字过滤 + # 关键字过滤:按标题模糊搜索 if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword), - ] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - # 公司/片区过滤 + # 公司过滤:company_id1 为所属公司字段 company_id = _id_list(params.get('company_id')) partner_id = _id_list(params.get('partner_id')) # 解析片区 ID 为整数列表(多选支持) if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) + # 片区(partner_id):通过 precinct.message -> employee -> user 关联申请人 if partner_id: - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), # 合同片区过滤(多选支持) - ('receivables_id.precinct_id', 'in', partner_id), # 应收记录片区过滤(多选支持) - ] + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + domain.append(('id', '=', False)) # 查询记录 - records = self.sudo().search(domain) + records = self.sudo().search(domain, order='pay_date asc') # ========== 四、构建报表行 ========== rows = [] - total_amount = 0.0 # 应付合计 - total_amount_actual = 0.0 # 实付合计 + total_fee = 0.0 # 支付金额合计 for idx, rec in enumerate(records, start=1): - due_date_str = rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "" - actual_date_str = rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "" - amount_val = round(rec.amount or 0.0, 2) - amount_actual_val = round(rec.amount_actual or 0.0, 2) - - total_amount += amount_val - total_amount_actual += amount_actual_val + pay_date_str = rec.pay_date.strftime("%Y-%m-%d") if rec.pay_date else "" + fee_val = round(rec.form_fee or 0.0, 2) + total_fee += fee_val rows.append({ "序号": idx, - "应付日期": due_date_str, - "实付日期": actual_date_str, - "应付": amount_val, - "实付": amount_actual_val, "标题": rec.name or "", + "所属公司": rec.company_id1.name if rec.company_id1 else "", + "支付金额": fee_val, + "申请人": rec.users_id.name if rec.users_id else "", + "支付日期": pay_date_str, + "权属类型": dict(rec._fields['tenure_type'].selection).get(rec.tenure_type, rec.tenure_type or ""), }) # ========== 五、构建统计汇总数据 ========== stats = [ {'name': '记录总数', 'amount': len(rows)}, - {'name': '应付合计', 'amount': round(total_amount, 2)}, - {'name': '实付合计', 'amount': round(total_amount_actual, 2)}, + {'name': '支付合计', 'amount': round(total_fee, 2)}, ] _logger.info( - "[MAINTENANCE_FEE_YEARLY] query_date=%s, year_range=[%s, %s], rows=%d, " - "total_amount=%.2f, total_amount_actual=%.2f", - query_date, year_start, month_last, len(rows), total_amount, total_amount_actual, + "[MAINTENANCE_FEE_YEARLY] query_date=%s, year_range=[%s, %s], rows=%d, total_fee=%.2f", + query_date, year_start, month_last, len(rows), total_fee, ) return {"rows": rows, "stats": stats} diff --git a/yuthon_report/models/management_fee_monthly_report.py b/yuthon_report/models/management_fee_monthly_report.py index 20ae5804e..f3b0cd868 100644 --- a/yuthon_report/models/management_fee_monthly_report.py +++ b/yuthon_report/models/management_fee_monthly_report.py @@ -8,18 +8,19 @@ from .report_utils import _id_list # 导入 ID 列表解析工具函数,支 _logger = logging.getLogger(__name__) -class PropertyBillsList(models.Model): - _inherit = 'property.bills.list' +class PropertyFeeForm(models.Model): + # 改为继承 property.fee.form 模型 + _inherit = 'property.fee.form' @api.model def get_management_fee_monthly_report(self, params): """管理费本月支出报表。 - 数据源:property.bills.list + 数据源:property.fee.form 过滤条件: - - management_type_id.name = '管理费' - - actual_date(实付日期)在查询月本月范围内(月初~月末) - 字段:应付日期、实付日期、应付、实付、标题 + - expenses_type.name = '管理费' + - pay_date(支付日期)在查询月本月范围内(月初~月末) + 字段:标题、所属公司、支付金额、申请人、支付日期、权属类型 """ # ========== 一、参数解析 ========== date_start = params.get("date_start") @@ -41,68 +42,63 @@ class PropertyBillsList(models.Model): # ========== 三、构建domain ========== domain = [ - ('management_type_id.name', '=', '管理费'), - ('actual_date', '>=', month_first), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', '管理费'), # 支出类型为管理费 + ('pay_date', '>=', month_first), # 支付日期在查询月月初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月月末及以前 ] - # 关键字过滤 + # 关键字过滤:按标题模糊搜索 if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword), - ] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - # 公司/片区过滤 + # 公司过滤:company_id1 为所属公司字段 company_id = _id_list(params.get('company_id')) partner_id = _id_list(params.get('partner_id')) # 解析片区 ID 为整数列表(多选支持) if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) + # 片区(partner_id):通过 precinct.message -> employee -> user 关联申请人 if partner_id: - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), # 合同片区过滤(多选支持) - ('receivables_id.precinct_id', 'in', partner_id), # 应收记录片区过滤(多选支持) - ] + # partner_id 是 yuthon.precinct.message 的 ID,需转换为 res.users ID + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + # 片区没有关联到任何用户,返回空结果 + domain.append(('id', '=', False)) # 查询记录 - records = self.sudo().search(domain) + records = self.sudo().search(domain, order='pay_date asc') # ========== 四、构建报表行 ========== rows = [] - total_amount = 0.0 # 应付合计 - total_amount_actual = 0.0 # 实付合计 + total_fee = 0.0 # 支付金额合计 for idx, rec in enumerate(records, start=1): - due_date_str = rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "" - actual_date_str = rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "" - amount_val = round(rec.amount or 0.0, 2) - amount_actual_val = round(rec.amount_actual or 0.0, 2) - - total_amount += amount_val - total_amount_actual += amount_actual_val + pay_date_str = rec.pay_date.strftime("%Y-%m-%d") if rec.pay_date else "" + fee_val = round(rec.form_fee or 0.0, 2) + total_fee += fee_val rows.append({ "序号": idx, - "应付日期": due_date_str, - "实付日期": actual_date_str, - "应付": amount_val, - "实付": amount_actual_val, "标题": rec.name or "", + "所属公司": rec.company_id1.name if rec.company_id1 else "", + "支付金额": fee_val, + "申请人": rec.users_id.name if rec.users_id else "", + "支付日期": pay_date_str, + "权属类型": dict(rec._fields['tenure_type'].selection).get(rec.tenure_type, rec.tenure_type or ""), }) # ========== 五、构建统计汇总数据 ========== stats = [ {'name': '记录总数', 'amount': len(rows)}, - {'name': '应付合计', 'amount': round(total_amount, 2)}, - {'name': '实付合计', 'amount': round(total_amount_actual, 2)}, + {'name': '支付合计', 'amount': round(total_fee, 2)}, ] _logger.info( - "[MANAGEMENT_FEE_MONTHLY] query_date=%s, month_range=[%s, %s], rows=%d, " - "total_amount=%.2f, total_amount_actual=%.2f", - query_date, month_first, month_last, len(rows), total_amount, total_amount_actual, + "[MANAGEMENT_FEE_MONTHLY] query_date=%s, month_range=[%s, %s], rows=%d, total_fee=%.2f", + query_date, month_first, month_last, len(rows), total_fee, ) return {"rows": rows, "stats": stats} diff --git a/yuthon_report/models/management_fee_yearly_report.py b/yuthon_report/models/management_fee_yearly_report.py index 9874a5e57..dfdbe1255 100644 --- a/yuthon_report/models/management_fee_yearly_report.py +++ b/yuthon_report/models/management_fee_yearly_report.py @@ -8,18 +8,19 @@ from .report_utils import _id_list # 导入 ID 列表解析工具函数,支 _logger = logging.getLogger(__name__) -class PropertyBillsList(models.Model): - _inherit = 'property.bills.list' +class PropertyFeeForm(models.Model): + # 改为继承 property.fee.form 模型 + _inherit = 'property.fee.form' @api.model def get_management_fee_yearly_report(self, params): """管理费本年累计报表。 - 数据源:property.bills.list + 数据源:property.fee.form 过滤条件: - - management_type_id.name = '管理费' - - actual_date(实付日期)在查询月所在年的1月1日~查询月末 - 字段:应付日期、实付日期、应付、实付、标题 + - expenses_type.name = '管理费' + - pay_date(支付日期)在查询月所在年的1月1日~查询月末 + 字段:标题、所属公司、支付金额、申请人、支付日期、权属类型 """ # ========== 一、参数解析 ========== date_start = params.get("date_start") @@ -41,68 +42,61 @@ class PropertyBillsList(models.Model): # ========== 三、构建domain ========== domain = [ - ('management_type_id.name', '=', '管理费'), - ('actual_date', '>=', year_start), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', '管理费'), # 支出类型为管理费 + ('pay_date', '>=', year_start), # 支付日期在年初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月末及以前 ] - # 关键字过滤 + # 关键字过滤:按标题模糊搜索 if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword), - ] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - # 公司/片区过滤 + # 公司过滤:company_id1 为所属公司字段 company_id = _id_list(params.get('company_id')) partner_id = _id_list(params.get('partner_id')) # 解析片区 ID 为整数列表(多选支持) if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) + # 片区(partner_id):通过 precinct.message -> employee -> user 关联申请人 if partner_id: - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), # 合同片区过滤(多选支持) - ('receivables_id.precinct_id', 'in', partner_id), # 应收记录片区过滤(多选支持) - ] + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + domain.append(('id', '=', False)) # 查询记录 - records = self.sudo().search(domain) + records = self.sudo().search(domain, order='pay_date asc') # ========== 四、构建报表行 ========== rows = [] - total_amount = 0.0 # 应付合计 - total_amount_actual = 0.0 # 实付合计 + total_fee = 0.0 # 支付金额合计 for idx, rec in enumerate(records, start=1): - due_date_str = rec.due_date.strftime("%Y-%m-%d") if rec.due_date else "" - actual_date_str = rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "" - amount_val = round(rec.amount or 0.0, 2) - amount_actual_val = round(rec.amount_actual or 0.0, 2) - - total_amount += amount_val - total_amount_actual += amount_actual_val + pay_date_str = rec.pay_date.strftime("%Y-%m-%d") if rec.pay_date else "" + fee_val = round(rec.form_fee or 0.0, 2) + total_fee += fee_val rows.append({ "序号": idx, - "应付日期": due_date_str, - "实付日期": actual_date_str, - "应付": amount_val, - "实付": amount_actual_val, "标题": rec.name or "", + "所属公司": rec.company_id1.name if rec.company_id1 else "", + "支付金额": fee_val, + "申请人": rec.users_id.name if rec.users_id else "", + "支付日期": pay_date_str, + "权属类型": dict(rec._fields['tenure_type'].selection).get(rec.tenure_type, rec.tenure_type or ""), }) # ========== 五、构建统计汇总数据 ========== stats = [ {'name': '记录总数', 'amount': len(rows)}, - {'name': '应付合计', 'amount': round(total_amount, 2)}, - {'name': '实付合计', 'amount': round(total_amount_actual, 2)}, + {'name': '支付合计', 'amount': round(total_fee, 2)}, ] _logger.info( - "[MANAGEMENT_FEE_YEARLY] query_date=%s, year_range=[%s, %s], rows=%d, " - "total_amount=%.2f, total_amount_actual=%.2f", - query_date, year_start, month_last, len(rows), total_amount, total_amount_actual, + "[MANAGEMENT_FEE_YEARLY] query_date=%s, year_range=[%s, %s], rows=%d, total_fee=%.2f", + query_date, year_start, month_last, len(rows), total_fee, ) return {"rows": rows, "stats": stats} diff --git a/yuthon_report/models/yuthon_dashboard.py b/yuthon_report/models/yuthon_dashboard.py index 5b74626cc..78d696a18 100644 --- a/yuthon_report/models/yuthon_dashboard.py +++ b/yuthon_report/models/yuthon_dashboard.py @@ -313,18 +313,19 @@ class YuthonDashboard(models.Model): amount = row.get('金额', 0) monthly_precollection.append({'text': f"{idx}. {prop_name}本月预收:{self._format_amount(amount)}元。"}) - # 支出:调用三个费用报表方法,从 rows 取标题和实付金额 + # 支出:调用三个费用报表方法,从 rows 取标题和支付金额 + # 数据源已改为 property.fee.form,金额字段为 支付金额 expense = [] fee_methods = [ - ('管理费', 'property.bills.list', 'get_management_fee_monthly_report'), - ('维修费', 'property.bills.list', 'get_maintenance_fee_monthly_report'), - ('评估费', 'property.bills.list', 'get_assessment_fee_monthly_report'), + ('管理费', 'property.fee.form', 'get_management_fee_monthly_report'), + ('维修费', 'property.fee.form', 'get_maintenance_fee_monthly_report'), + ('评估费', 'property.fee.form', 'get_assessment_fee_monthly_report'), ] for fee_label, model_name, method_name in fee_methods: fee_result = getattr(self.env[model_name], method_name)(base_params) for row in fee_result.get('rows', []): title = row.get('标题', '') - amount_actual = row.get('实付', 0) + amount_actual = row.get('支付金额', 0) # 新模型金额字段为 支付金额 if amount_actual > 0: expense.append(f"{title}{fee_label}支出{self._format_amount(amount_actual)}元。") @@ -392,18 +393,18 @@ class YuthonDashboard(models.Model): return '未知' def _get_fee_expense_data(self, base_params, query_date): - """费用支出:管理费、维修费、评估费及其它""" + """费用支出:管理费、维修费、评估费及其它(数据源改为 property.fee.form)""" try: 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) company_id = _id_list(base_params.get('company_id')) - # 多选标准化:partner_id 统一为列表 + # 多选标准化:partner_id 统一为列表(fee.form 无片区关联,暂保留以备扩展) partner_id = _id_list(base_params.get('partner_id')) keyword = base_params.get('keyword') - # 按费用类型分别统计(数据源:property.bills.list) + # 按费用类型分别统计(数据源:property.fee.form) fee_types = ['管理费', '维修费', '评估费'] cards = [] @@ -411,47 +412,52 @@ class YuthonDashboard(models.Model): row_labels_explanations = [] for label in fee_types: - # 费用支出数据来源:property.bills.list + # 费用支出数据来源:property.fee.form + # expenses_type.name = 费用类型,pay_date = 支付日期,form_fee = 支付金额 domain = [ - ('management_type_id.name', '=', label), - ('actual_date', '>=', month_first), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', label), # 支出类型匹配 + ('pay_date', '>=', month_first), # 支付日期在查询月月初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月月末及以前 ] if company_id: - domain.append(('lessor_id', 'in', company_id)) + domain.append(('company_id1', 'in', company_id)) # 所属公司字段为 company_id1 + # 片区过滤:partner_id 是 precinct.message ID,需转换为 res.users ID if partner_id: - # 多选:片区管理员用 'in' 操作符 - domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), - ('receivables_id.precinct_id', 'in', partner_id), - ] + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + domain.append(('users_id', 'in', user_ids)) + else: + domain.append(('id', '=', False)) if keyword: - domain += ['|', '|', '|', - ('name', 'ilike', keyword), - ('contract_id.contract_code', 'ilike', keyword), - ('lessee_id.name', 'ilike', keyword), - ('property_name', 'ilike', keyword)] + domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] - records = self.env['property.bills.list'].sudo().search(domain) - month_total = sum((r.amount_actual or 0.0) for r in records) + records = self.env['property.fee.form'].sudo().search(domain) + month_total = sum((r.form_fee or 0.0) for r in records) # 支付金额字段为 form_fee # 本年累计 year_start = datetime.date(query_date.year, 1, 1) year_domain = [ - ('management_type_id.name', '=', label), - ('actual_date', '>=', year_start), - ('actual_date', '<=', month_last), + ('expenses_type.name', '=', label), # 支出类型匹配 + ('pay_date', '>=', year_start), # 支付日期在年初及以后 + ('pay_date', '<=', month_last), # 支付日期在查询月末及以前 ] if company_id: - year_domain.append(('lessor_id', 'in', company_id)) + year_domain.append(('company_id1', 'in', company_id)) + # 片区过滤:partner_id 是 precinct.message ID,需转换为 res.users ID if partner_id: - # 多选:片区管理员用 'in' 操作符 - year_domain += ['|', - ('contract_id.precinct_id', 'in', partner_id), - ('receivables_id.precinct_id', 'in', partner_id), - ] - year_records = self.env['property.bills.list'].sudo().search(year_domain) - year_total = sum((r.amount_actual or 0.0) for r in year_records) + precincts = self.env['yuthon.precinct.message'].sudo().browse(partner_id) + user_ids = precincts.mapped('employee_id.user_id').ids + if user_ids: + year_domain.append(('users_id', 'in', user_ids)) + else: + year_domain.append(('id', '=', False)) + if keyword: + year_domain += ['|', ('name', 'ilike', keyword), + ('users_id.name', 'ilike', keyword)] + year_records = self.env['property.fee.form'].sudo().search(year_domain) + year_total = sum((r.form_fee or 0.0) for r in year_records) # 本月支出卡片:管理费、维修费绑定报表,其他费用暂不绑定 if label == '管理费': diff --git a/yuthon_report/views/assessment_fee_report.xml b/yuthon_report/views/assessment_fee_report.xml index 6a3290329..cf3323e44 100644 --- a/yuthon_report/views/assessment_fee_report.xml +++ b/yuthon_report/views/assessment_fee_report.xml @@ -8,16 +8,17 @@ { "sideBar": true, "report_config": { - "model": "property.bills.list", + "model": "property.fee.form", "method": "get_assessment_fee_monthly_report", "dateMode": "single", "columns": [ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"}, - {"headerName": "应付日期", "field": "应付日期", "flex": 1.2}, - {"headerName": "实付日期", "field": "实付日期", "flex": 1.2}, - {"headerName": "应付", "field": "应付", "flex": 1, "type": "number"}, - {"headerName": "实付", "field": "实付", "flex": 1, "type": "number"}, - {"headerName": "标题", "field": "标题", "flex": 2.5} + {"headerName": "支付日期", "field": "支付日期", "flex": 1.2}, + {"headerName": "所属公司", "field": "所属公司", "flex": 1.2}, + {"headerName": "标题", "field": "标题", "flex": 2.5}, + {"headerName": "支付金额", "field": "支付金额", "flex": 1, "type": "number"}, + {"headerName": "申请人", "field": "申请人", "flex": 1}, + {"headerName": "权属类型", "field": "权属类型", "flex": 1} ] } } diff --git a/yuthon_report/views/assessment_fee_yearly_report.xml b/yuthon_report/views/assessment_fee_yearly_report.xml index 53c139b69..be99d6d3c 100644 --- a/yuthon_report/views/assessment_fee_yearly_report.xml +++ b/yuthon_report/views/assessment_fee_yearly_report.xml @@ -8,16 +8,17 @@ { "sideBar": true, "report_config": { - "model": "property.bills.list", + "model": "property.fee.form", "method": "get_assessment_fee_yearly_report", "dateMode": "single", "columns": [ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"}, - {"headerName": "应付日期", "field": "应付日期", "flex": 1.2}, - {"headerName": "实付日期", "field": "实付日期", "flex": 1.2}, - {"headerName": "应付", "field": "应付", "flex": 1, "type": "number"}, - {"headerName": "实付", "field": "实付", "flex": 1, "type": "number"}, - {"headerName": "标题", "field": "标题", "flex": 2.5} + {"headerName": "支付日期", "field": "支付日期", "flex": 1.2}, + {"headerName": "所属公司", "field": "所属公司", "flex": 1.2}, + {"headerName": "标题", "field": "标题", "flex": 2.5}, + {"headerName": "支付金额", "field": "支付金额", "flex": 1, "type": "number"}, + {"headerName": "申请人", "field": "申请人", "flex": 1}, + {"headerName": "权属类型", "field": "权属类型", "flex": 1} ] } } diff --git a/yuthon_report/views/maintenance_fee_report.xml b/yuthon_report/views/maintenance_fee_report.xml index 7525aef90..fe7db0308 100644 --- a/yuthon_report/views/maintenance_fee_report.xml +++ b/yuthon_report/views/maintenance_fee_report.xml @@ -8,16 +8,17 @@ { "sideBar": true, "report_config": { - "model": "property.bills.list", + "model": "property.fee.form", "method": "get_maintenance_fee_monthly_report", "dateMode": "single", "columns": [ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"}, - {"headerName": "应付日期", "field": "应付日期", "flex": 1.2}, - {"headerName": "实付日期", "field": "实付日期", "flex": 1.2}, - {"headerName": "应付", "field": "应付", "flex": 1, "type": "number"}, - {"headerName": "实付", "field": "实付", "flex": 1, "type": "number"}, - {"headerName": "标题", "field": "标题", "flex": 2.5} + {"headerName": "支付日期", "field": "支付日期", "flex": 1.2}, + {"headerName": "所属公司", "field": "所属公司", "flex": 1.2}, + {"headerName": "标题", "field": "标题", "flex": 2.5}, + {"headerName": "支付金额", "field": "支付金额", "flex": 1, "type": "number"}, + {"headerName": "申请人", "field": "申请人", "flex": 1}, + {"headerName": "权属类型", "field": "权属类型", "flex": 1} ] } } diff --git a/yuthon_report/views/maintenance_fee_yearly_report.xml b/yuthon_report/views/maintenance_fee_yearly_report.xml index 99b3f6649..617b06b89 100644 --- a/yuthon_report/views/maintenance_fee_yearly_report.xml +++ b/yuthon_report/views/maintenance_fee_yearly_report.xml @@ -8,16 +8,17 @@ { "sideBar": true, "report_config": { - "model": "property.bills.list", + "model": "property.fee.form", "method": "get_maintenance_fee_yearly_report", "dateMode": "single", "columns": [ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"}, - {"headerName": "应付日期", "field": "应付日期", "flex": 1.2}, - {"headerName": "实付日期", "field": "实付日期", "flex": 1.2}, - {"headerName": "应付", "field": "应付", "flex": 1, "type": "number"}, - {"headerName": "实付", "field": "实付", "flex": 1, "type": "number"}, - {"headerName": "标题", "field": "标题", "flex": 2.5} + {"headerName": "支付日期", "field": "支付日期", "flex": 1.2}, + {"headerName": "所属公司", "field": "所属公司", "flex": 1.2}, + {"headerName": "标题", "field": "标题", "flex": 2.5}, + {"headerName": "支付金额", "field": "支付金额", "flex": 1, "type": "number"}, + {"headerName": "申请人", "field": "申请人", "flex": 1}, + {"headerName": "权属类型", "field": "权属类型", "flex": 1} ] } } diff --git a/yuthon_report/views/management_fee_report.xml b/yuthon_report/views/management_fee_report.xml index 3a5765058..c439fe77d 100644 --- a/yuthon_report/views/management_fee_report.xml +++ b/yuthon_report/views/management_fee_report.xml @@ -8,16 +8,17 @@ { "sideBar": true, "report_config": { - "model": "property.bills.list", + "model": "property.fee.form", "method": "get_management_fee_monthly_report", "dateMode": "single", "columns": [ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"}, - {"headerName": "应付日期", "field": "应付日期", "flex": 1.2}, - {"headerName": "实付日期", "field": "实付日期", "flex": 1.2}, - {"headerName": "应付", "field": "应付", "flex": 1, "type": "number"}, - {"headerName": "实付", "field": "实付", "flex": 1, "type": "number"}, - {"headerName": "标题", "field": "标题", "flex": 2.5} + {"headerName": "支付日期", "field": "支付日期", "flex": 1.2}, + {"headerName": "所属公司", "field": "所属公司", "flex": 1.2}, + {"headerName": "标题", "field": "标题", "flex": 2.5}, + {"headerName": "支付金额", "field": "支付金额", "flex": 1, "type": "number"}, + {"headerName": "申请人", "field": "申请人", "flex": 1}, + {"headerName": "权属类型", "field": "权属类型", "flex": 1} ] } } diff --git a/yuthon_report/views/management_fee_yearly_report.xml b/yuthon_report/views/management_fee_yearly_report.xml index 885490122..5d8527011 100644 --- a/yuthon_report/views/management_fee_yearly_report.xml +++ b/yuthon_report/views/management_fee_yearly_report.xml @@ -8,16 +8,17 @@ { "sideBar": true, "report_config": { - "model": "property.bills.list", + "model": "property.fee.form", "method": "get_management_fee_yearly_report", "dateMode": "single", "columns": [ {"headerName": "序号", "field": "序号", "width": 45, "flex": 0, "pinned": "left"}, - {"headerName": "应付日期", "field": "应付日期", "flex": 1.2}, - {"headerName": "实付日期", "field": "实付日期", "flex": 1.2}, - {"headerName": "应付", "field": "应付", "flex": 1, "type": "number"}, - {"headerName": "实付", "field": "实付", "flex": 1, "type": "number"}, - {"headerName": "标题", "field": "标题", "flex": 2.5} + {"headerName": "支付日期", "field": "支付日期", "flex": 1.2}, + {"headerName": "所属公司", "field": "所属公司", "flex": 1.2}, + {"headerName": "标题", "field": "标题", "flex": 2.5}, + {"headerName": "支付金额", "field": "支付金额", "flex": 1, "type": "number"}, + {"headerName": "申请人", "field": "申请人", "flex": 1}, + {"headerName": "权属类型", "field": "权属类型", "flex": 1} ] } }