From 3b0a3583ddeb9deea78b5b09777f0808f06dd410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= Date: Wed, 20 May 2026 11:44:07 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8A=BC=E9=87=91=E6=8A=A5=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/deposit_month_receivable_report.py | 81 ++++---- .../models/deposit_month_received_report.py | 184 ++++++------------ .../models/deposit_month_refund_report.py | 85 ++++---- yuthon_report/models/deposit_total_report.py | 96 +++++---- 4 files changed, 191 insertions(+), 255 deletions(-) diff --git a/yuthon_report/models/deposit_month_receivable_report.py b/yuthon_report/models/deposit_month_receivable_report.py index f62441f62..e1eca2fe5 100644 --- a/yuthon_report/models/deposit_month_receivable_report.py +++ b/yuthon_report/models/deposit_month_receivable_report.py @@ -11,11 +11,10 @@ class DepositMonthReceivableReport(models.Model): def get_deposit_month_receivable_report(self, params): """ 押金本月应收报表: + - 数据源:property.accounts.receivable - 管理费用类型为"押金" - 应收日期(due_date)在查询月内 - - 必须有收款记录(reconciliation_date != False) - - 排除跨月预收(reconciliation_date < due_date 且不同年月) - - 金额取收款记录的 amount,按应收账单聚合 + - 非作废记录 """ date_start = params.get("date_start") query_date = datetime.datetime.fromisoformat(date_start).date() if date_start else datetime.date.today() @@ -24,73 +23,59 @@ class DepositMonthReceivableReport(models.Model): month_last = query_date.replace(day=last_day) domain = [ - ('reconciliation_date', '!=', False), - ('receivable_id.due_date', '>=', month_first), - ('receivable_id.due_date', '<=', month_last), - ('receivable_id.is_invalid', '=', False), - ('receivable_id.management_type_id.name', '=', '押金'), + ('due_date', '>=', month_first), + ('due_date', '<=', month_last), + ('is_invalid', '=', False), + ('management_type_id.name', '=', '押金'), ] keyword = params.get("keyword") if keyword: domain += ['|', '|', - ('receivable_id.contract_id.contract_code', 'ilike', keyword), - ('receivable_id.property_name', 'ilike', keyword), - ('receivable_id.lessee_id.name', 'ilike', keyword), + ('contract_id.contract_code', 'ilike', keyword), + ('property_name', 'ilike', keyword), + ('lessee_id.name', 'ilike', keyword), ] condition = params.get('condition') partner_id = params.get('partner_id') company_id = params.get('company_id') if condition: - domain.append(('receivable_id.tenure_type', '=', condition)) + domain.append(('tenure_type', '=', condition)) if partner_id: - domain.append(('receivable_id.precinct_id', '=', partner_id)) + domain.append(('precinct_id', '=', partner_id)) if company_id: - domain.append(('receivable_id.company_id', '=', company_id)) + domain.append(('company_id', '=', company_id)) - lines = self.env['receivable.modify.line'].sudo().search( - domain, order="receivable_id asc, reconciliation_date asc" - ) - - # 排除跨月预收 - lines = lines.filtered( - lambda l: not ( - l.reconciliation_date and l.receivable_id.due_date - and l.reconciliation_date < l.receivable_id.due_date - and not ( - l.reconciliation_date.year == l.receivable_id.due_date.year - and l.reconciliation_date.month == l.receivable_id.due_date.month - ) - ) - ) - - # 按应收账单聚合 - rec_map = {} - for line in lines: - rid = line.receivable_id.id - if rid not in rec_map: - rec_map[rid] = {'rec': line.receivable_id, 'amount': 0.0} - rec_map[rid]['amount'] += line.amount or 0.0 + lines = self.sudo().search(domain, order="contract_id asc") rows = [] total_amount = 0.0 - for idx, (rid, data) in enumerate(rec_map.items(), start=1): - rec = data['rec'] - amount = round(data['amount'], 2) + for idx, rec in enumerate(lines, start=1): + amount = round(rec.original_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': rec.contract_id.id, - 'display_name': rec.contract_id.contract_code, - } if rec.contract_id else "", - "物业名称": { - 'model': 'yuthon.property', - 'id': rec.contract_id.lease_ids[0].address_id.id, - 'display_name': rec.property_name, - } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "", + 'id': contract.id, + 'display_name': contract.contract_code, + } if contract else "", + "物业名称": property_val, "承租方名称": { 'model': 'property.tenant.information', 'id': rec.lessee_id.id, diff --git a/yuthon_report/models/deposit_month_received_report.py b/yuthon_report/models/deposit_month_received_report.py index 7af2692bf..f4e982a78 100644 --- a/yuthon_report/models/deposit_month_received_report.py +++ b/yuthon_report/models/deposit_month_received_report.py @@ -1,156 +1,98 @@ import datetime +import calendar from odoo import api, models class DepositMonthReceivedReport(models.Model): - _inherit = 'receivable.modify.line' + _inherit = 'property.accounts.receivable' @api.model def get_deposit_month_received_report(self, params): """ 押金本月实收报表: - - 数据源: receivable.modify.line(应收类型为押金) - - 金额: penalty.pay.line.amount(支付金额) - - 日期过滤: penalty.pay.line.date 在查询月当月第一天至最后一天 + - 数据源:property.accounts.receivable + - 管理费用类型为"押金" + - 押金状态为"已收" + - 非作废记录 + - 支付日期(payout_date)在查询月内 + - 金额:original_amount - discount_amount """ - today = datetime.date.today() - this_month_first = today.replace(day=1) - if today.month == 12: - next_month_first = today.replace(year=today.year + 1, month=1, day=1) - else: - next_month_first = today.replace(month=today.month + 1, day=1) - this_month_last = next_month_first - datetime.timedelta(days=1) - date_start = params.get("date_start") - if date_start: - query_date = datetime.datetime.fromisoformat(date_start).date() - else: - query_date = today + 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) - query_year = query_date.year - query_month = query_date.month - - # 查询月当月范围:当月第一天 ~ 当月最后一天 - period_start = datetime.date(query_year, query_month, 1) - if query_month == 12: - period_end = datetime.date(query_year + 1, 1, 1) - datetime.timedelta(days=1) - else: - period_end = datetime.date(query_year, query_month + 1, 1) - datetime.timedelta(days=1) - - deposit_type = self.env['yuthon.management.type'].search([('name', '=', '押金')], limit=1) - - domain = [] - if deposit_type: - domain.append(('management_type_id', '=', deposit_type.id)) + domain = [ + ('management_type_id.name', '=', '押金'), + ('deposit_state', '=', '已收'), + ('is_invalid', '=', False), + ('payout_date', '>=', month_first), + ('payout_date', '<=', month_last), + ] keyword = params.get("keyword") if keyword: domain += ['|', '|', - ('receivable_id.contract_id.contract_code', 'ilike', keyword), + ('contract_id.contract_code', 'ilike', keyword), ('property_name', 'ilike', keyword), - ('receivable_id.lessee_id.name', 'ilike', keyword), + ('lessee_id.name', 'ilike', keyword), ] condition = params.get('condition') partner_id = params.get('partner_id') company_id = params.get('company_id') if condition: - domain.append(('receivable_id.tenure_type', '=', condition)) + domain.append(('tenure_type', '=', condition)) if partner_id: - domain.append(('receivable_id.precinct_id', '=', partner_id)) + domain.append(('precinct_id', '=', partner_id)) if company_id: - domain.append(('receivable_id.company_id', '=', company_id)) + domain.append(('company_id', '=', company_id)) - modify_lines = self.search(domain, order="receivable_id asc") + lines = self.sudo().search(domain, order="contract_id asc") rows = [] total_amount = 0.0 - idx = 1 + 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 '' - for line in modify_lines: - if not line.receivable_id: - continue - receivable_id = line.receivable_id.id - - rec = line.receivable_id - wizards = self.env['penalty.line.wizard'].search( - [('receivable_id', '=', receivable_id)] - ) - if wizards: - # 处理有wizard关联的记录,确保使用penalty.pay.line的字段 - for wizard in wizards: - for pay in wizard.pay_line_ids: - if not pay.date: - continue - # 确保支付类型是押金 - if pay.management_type_id and pay.management_type_id.name != '押金': - continue - if pay.date >= period_start and pay.date <= period_end: - amount = round(pay.amount, 2) - total_amount += amount - rows.append({ - "序号": idx, - "合同编号": { - 'model': 'property.lease.contract', - 'id': rec.contract_id.id if rec.contract_id else None, - 'display_name': rec.contract_id.contract_code if rec.contract_id else "", - } if rec.contract_id else "", - "物业名称": { - 'model': 'yuthon.property', - 'id': rec.contract_id.lease_ids[0].address_id.id if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else None, - 'display_name': rec.property_name, - } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "", - "承租方名称": { - 'model': 'property.tenant.information', - 'id': rec.lessee_id.id if rec.lessee_id else None, - 'display_name': rec.lessee_id.name if rec.lessee_id else "", - } if rec.lessee_id else "", - "收款日期": pay.date.strftime("%Y-%m-%d"), - "金额": amount, - "所属公司": rec.company_id.name if rec.company_id else "", - "管理员": { - 'model': 'res.users', - 'id': rec.admin_id.id if rec.admin_id else None, - 'display_name': rec.admin_id.name if rec.admin_id else "", - } if rec.admin_id else "", - }) - idx += 1 - else: - # 如果没有关联的wizard,尝试直接从line获取信息 - if line.delivered1 and (line.receivable_id.payout_date or line.create_date): - # 使用payout_date作为收款日期,如果没有则使用create_date - payment_date = line.receivable_id.payout_date or line.create_date.date() - if period_start <= payment_date <= period_end: - amount = round(line.delivered1, 2) - total_amount += amount - rows.append({ - "序号": idx, - "合同编号": { - 'model': 'property.lease.contract', - 'id': rec.contract_id.id if rec.contract_id else None, - 'display_name': rec.contract_id.contract_code if rec.contract_id else "", - } if rec.contract_id else "", - "物业名称": { - 'model': 'yuthon.property', - 'id': rec.contract_id.lease_ids[0].address_id.id if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else None, - 'display_name': rec.property_name, - } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "", - "承租方名称": { - 'model': 'property.tenant.information', - 'id': rec.lessee_id.id if rec.lessee_id else None, - 'display_name': rec.lessee_id.name if rec.lessee_id else "", - } if rec.lessee_id else "", - "收款日期": payment_date.strftime("%Y-%m-%d"), - "金额": amount, - "所属公司": rec.company_id.name if rec.company_id else "", - "管理员": { - 'model': 'res.users', - 'id': rec.admin_id.id if rec.admin_id else None, - 'display_name': rec.admin_id.name if rec.admin_id else "", - } if rec.admin_id else "", - }) - idx += 1 + 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, + "所属公司": 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)}, diff --git a/yuthon_report/models/deposit_month_refund_report.py b/yuthon_report/models/deposit_month_refund_report.py index 7613f96da..588bd86a8 100644 --- a/yuthon_report/models/deposit_month_refund_report.py +++ b/yuthon_report/models/deposit_month_refund_report.py @@ -1,85 +1,81 @@ import datetime +import calendar from odoo import api, models class DepositMonthRefundReport(models.Model): - _inherit = 'receivable.modify.line' + _inherit = 'property.bills.list' @api.model def get_deposit_month_refund_report(self, params): """ 押金本月已退报表: - - 数据源:receivable.modify.line - - 应收类型为"押金" - - has_date(退款日期)有值且在查询月范围内 - - is_invalid = False - - 金额 = receivable_id.original_amount(当期金额,即押金收了多少退多少) + - 数据源:property.bills.list + - 管理费用类型为"押金" + - actual_date有值且在查询月内 """ - today = datetime.date.today() - this_month_first = today.replace(day=1) - if today.month == 12: - next_month_first = today.replace(year=today.year + 1, month=1, day=1) - else: - next_month_first = today.replace(month=today.month + 1, day=1) - this_month_last = next_month_first - datetime.timedelta(days=1) - date_start = params.get("date_start") - date_end = params.get("date_end") - start_dt = datetime.datetime.fromisoformat(date_start).date() if date_start else this_month_first - end_dt = datetime.datetime.fromisoformat(date_end).date() if date_end else this_month_last - - deposit_type = self.env['yuthon.management.type'].search([('name', '=', '押金')], limit=1) + 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 = [ - ('receivable_id.has_date', '!=', False), - ('receivable_id.has_date', '>=', start_dt), - ('receivable_id.has_date', '<=', end_dt), - ('receivable_id.is_invalid', '=', False), + ('management_type_id.name', '=', '押金'), + ('actual_date', '!=', False), + ('actual_date', '>=', month_first), + ('actual_date', '<=', month_last), ] - if deposit_type: - domain.append(('management_type_id', '=', deposit_type.id)) keyword = params.get("keyword") if keyword: domain += ['|', '|', - ('receivable_id.contract_id.contract_code', 'ilike', keyword), + ('contract_id.contract_code', 'ilike', keyword), ('property_name', 'ilike', keyword), - ('receivable_id.lessee_id.name', 'ilike', keyword), + ('lessee_id.name', 'ilike', keyword), ] condition = params.get('condition') partner_id = params.get('partner_id') company_id = params.get('company_id') if condition: - domain.append(('receivable_id.tenure_type', '=', condition)) + domain.append(('tenure_type', '=', condition)) if partner_id: - domain.append(('receivable_id.precinct_id', '=', partner_id)) + domain.append(('precinct_id', '=', partner_id)) if company_id: - domain.append(('receivable_id.company_id', '=', company_id)) + domain.append(('company_id', '=', company_id)) - lines = self.search(domain, order="receivable_id asc") + lines = self.sudo().search(domain, order="contract_id asc") rows = [] total_amount = 0.0 - idx = 1 - for line in lines: - rec = line.receivable_id - amount = round(rec.original_amount or 0.0, 2) + for idx, rec in enumerate(lines, start=1): + amount = round(rec.amount_actual 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, - "退押日期": rec.has_date.strftime("%Y-%m-%d") if rec.has_date else "", + "退押日期": rec.actual_date.strftime("%Y-%m-%d") if rec.actual_date else "", "合同编号": { 'model': 'property.lease.contract', - 'id': rec.contract_id.id, - 'display_name': rec.contract_id.contract_code, - } if rec.contract_id else "", - "物业名称": { - 'model': 'yuthon.property', - 'id': rec.contract_id.lease_ids[0].address_id.id, - 'display_name': rec.property_name, - } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "", + 'id': contract.id, + 'display_name': contract.contract_code, + } if contract else "", + "物业名称": property_val, "承租方名称": { 'model': 'property.tenant.information', 'id': rec.lessee_id.id, @@ -93,7 +89,6 @@ class DepositMonthRefundReport(models.Model): 'display_name': rec.admin_id.name, } if rec.admin_id else "", }) - idx += 1 stats = [ {'name': '记录总数', 'amount': len(rows)}, diff --git a/yuthon_report/models/deposit_total_report.py b/yuthon_report/models/deposit_total_report.py index 043758236..742af17d5 100644 --- a/yuthon_report/models/deposit_total_report.py +++ b/yuthon_report/models/deposit_total_report.py @@ -1,82 +1,97 @@ import datetime +import calendar from odoo import api, models class DepositTotalReport(models.Model): - _inherit = 'receivable.modify.line' + _inherit = 'property.accounts.receivable' @api.model def get_deposit_total_report(self, params): """ 累计押金报表: - - 数据源:receivable.modify.line - - 应收类型为"押金" - - due_date 在查询月所在年全年(1月1日 ~ 12月31日) - - 金额取 receivable_id.delivered1(已收金额) - - is_invalid = False + - 数据源:property.accounts.receivable + - 管理费用类型为"押金" + - 押金状态为"已收" + - 非作废记录 + - 支付日期(payout_date)在查询月内 + - 金额:original_amount - discount_amount + - 排除已退款的押金(即property.bills.list中有actual_date的押金记录) """ - today = datetime.date.today() - date_start = params.get("date_start") - if date_start: - query_date = datetime.datetime.fromisoformat(date_start).date() - else: - query_date = today + 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) - year = query_date.year - year_start = datetime.date(year, 1, 1) - year_end = datetime.date(year, 12, 31) - - deposit_type = self.env['yuthon.management.type'].search([('name', '=', '押金')], limit=1) + # 查询已退款的押金记录(从property.bills.list中获取) + refund_bills = self.env['property.bills.list'].sudo().search([ + ('management_type_id.name', '=', '押金'), + ('actual_date', '!=', False), + ]) + # 获取已退款押金对应的contract_id列表 + refund_contract_ids = [bill.contract_id.id for bill in refund_bills if bill.contract_id] domain = [ - ('payout_date', '>=', year_start), - ('payout_date', '<=', year_end), - ('receivable_id.is_invalid', '=', False), + ('management_type_id.name', '=', '押金'), + ('deposit_state', '=', '已收'), + ('is_invalid', '=', False), + ('payout_date', '>=', month_first), + ('payout_date', '<=', month_last), ] - if deposit_type: - domain.append(('management_type_id', '=', deposit_type.id)) + + # 排除已退款的押金 + if refund_contract_ids: + domain.append(('contract_id', 'not in', refund_contract_ids)) keyword = params.get("keyword") if keyword: domain += ['|', '|', - ('receivable_id.contract_id.contract_code', 'ilike', keyword), + ('contract_id.contract_code', 'ilike', keyword), ('property_name', 'ilike', keyword), - ('receivable_id.lessee_id.name', 'ilike', keyword), + ('lessee_id.name', 'ilike', keyword), ] condition = params.get('condition') partner_id = params.get('partner_id') company_id = params.get('company_id') if condition: - domain.append(('receivable_id.tenure_type', '=', condition)) + domain.append(('tenure_type', '=', condition)) if partner_id: - domain.append(('receivable_id.precinct_id', '=', partner_id)) + domain.append(('precinct_id', '=', partner_id)) if company_id: - domain.append(('receivable_id.company_id', '=', company_id)) + domain.append(('company_id', '=', company_id)) - lines = self.search(domain, order="receivable_id asc") + lines = self.sudo().search(domain, order="contract_id asc") rows = [] total_amount = 0.0 - idx = 1 - for line in lines: - rec = line.receivable_id - amount = round(rec.delivered1 or 0.0, 2) + 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': rec.contract_id.id, - 'display_name': rec.contract_id.contract_code, - } if rec.contract_id else "", - "物业名称": { - 'model': 'yuthon.property', - 'id': rec.contract_id.lease_ids[0].address_id.id, - 'display_name': rec.property_name, - } if rec.contract_id and rec.contract_id.lease_ids and rec.contract_id.lease_ids[0].address_id else rec.property_name or "", + 'id': contract.id, + 'display_name': contract.contract_code, + } if contract else "", + "物业名称": property_val, "承租方名称": { 'model': 'property.tenant.information', 'id': rec.lessee_id.id, @@ -90,7 +105,6 @@ class DepositTotalReport(models.Model): 'display_name': rec.admin_id.name, } if rec.admin_id else "", }) - idx += 1 stats = [ {'name': '记录总数', 'amount': len(rows)},