From 301cd54c3c43ee57042249296dafe25070ed088e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=B9=8F=E5=AE=87?= <9664676+pengyuthon@user.noreply.gitee.com> Date: Wed, 19 Nov 2025 11:53:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/property_accounts_receivable.py | 16 ++++ .../models/contract_accounts_receivable.py | 86 +++++++++++++++---- .../models/inherit_yuthon_property.py | 1 + .../models/property_lease_contract.py | 1 + .../models/property_lease_renewal.py | 3 +- .../contract_accounts_receivable_viwes.xml | 7 ++ .../views/inherit_yuthon_property_views.xml | 4 + .../views/property_lease_contract.xml | 18 ++++ .../views/property_lease_renewal.xml | 1 + 9 files changed, 117 insertions(+), 20 deletions(-) diff --git a/yuthon_property/models/property_accounts_receivable.py b/yuthon_property/models/property_accounts_receivable.py index b04afd19f..dc510fe2f 100644 --- a/yuthon_property/models/property_accounts_receivable.py +++ b/yuthon_property/models/property_accounts_receivable.py @@ -22,6 +22,7 @@ class PropertyAccountsReceivable(models.Model): ('12', '十二月')], string='选择月份') original_amount = fields.Float(string='当期金额') discount_amount = fields.Float(string='减免金额') + discount_date = fields.Date(string='减免日期') multiplier = fields.Integer(string='季度') remark = fields.Text(string='备注') red_date = fields.Date(string='红冲日期') @@ -50,6 +51,21 @@ class PropertyAccountsReceivable(models.Model): receivable_log = fields.Text(string='应收日志') + @api.onchange('is_invalid') + def _onchange_is_invalid(self): + if self.is_invalid: + self.void_date = fields.Date.today() + else: + self.void_date = False + + @api.depends('discount_amount') + def _onchange_discount_amount(self): + for record in self: + if record.discount_amount: + record.discount_date = fields.Date.today() + else: + record.discount_date = False + def update_submitted(self): record_ids = self.env["property.accounts.receivable"].browse( self._context.get("active_ids", self._context.get("active_id")) diff --git a/yuthon_property_approval/models/contract_accounts_receivable.py b/yuthon_property_approval/models/contract_accounts_receivable.py index 3608398c1..96e66a3ea 100644 --- a/yuthon_property_approval/models/contract_accounts_receivable.py +++ b/yuthon_property_approval/models/contract_accounts_receivable.py @@ -1,4 +1,5 @@ from odoo import models, fields, api +from datetime import datetime, timedelta, date import json @@ -10,6 +11,7 @@ class ContractAccountsReceivable(models.Model): lessee_id = fields.Many2one(related="contract_id.lessee_id", string='承租方') property_name = fields.Char(related="contract_id.property_name", string='物业信息') contract_accounts_ids = fields.One2many('property.accounts.receivable', 'contract_accounts_id', string='关联应收账单') + contract_date = fields.Date(string="日期") is_print = fields.Boolean(string="打印") json_display = fields.Char( @@ -18,26 +20,72 @@ class ContractAccountsReceivable(models.Model): store=True ) - # @api.onchange('contract_id') - # def onchange_contract_id(self): - # accounts = self.env['property.accounts.receivable'].search([('contract_id', '=', self.contract_id.id)]) - # receivable_list = [] - # for account in accounts: - # receivable_list.append([0, 0, { - # 'contract_accounts_id': account.id, - # 'management_type_id': account.management_type_id.id, - # 'last_month_table': account.last_month_table, - # 'this_month_table': account.this_month_table, - # 'ratio': account.ratio, - # 'billable_quantity': account.billable_quantity, - # 'due_date': account.due_date, - # 'due_date_end': account.due_date_end, - # 'original_amount': account.original_amount, - # 'pre_collection': account.pre_collection, - # 'remark': account.remark, - # }]) - # self.contract_accounts_ids = receivable_list + def batch_create_by_contract_and_month(self): + """ + 按“合同+年月”分组创建账单,创建时即设置contract_date为分组最早due_date + """ + all_receivables = self.env['property.accounts.receivable'].search([ + ('contract_id', '!=', False), + ('due_date', '!=', False), + ('is_invalid', '=', False), + ('is_reconciliation', '=', True) + ]) + # 按“合同ID+年月”分组 + grouped_data = {} + for receivable in all_receivables: + year_month = receivable.due_date.strftime('%Y-%m') + key = (receivable.contract_id.id, year_month) + if key not in grouped_data: + grouped_data[key] = self.env['property.accounts.receivable'] + grouped_data[key] += receivable + for (contract_id, year_month), receivables in grouped_data.items(): + if not contract_id: + continue + earliest_due_date = min(receivables.mapped('due_date')) + start_date, end_date = self._get_month_date_range(year_month) + existing_bill = self.search([ + ('contract_id', '=', contract_id), + ('contract_date', '>=', start_date), + ('contract_date', '<=', end_date) + ], limit=1) + if not existing_bill: + existing_bill = self.create({ + 'contract_id': contract_id, + 'contract_date': earliest_due_date, + 'is_print': False + }) + accounts = self.env['property.accounts.receivable'].search([('contract_id', '=', contract_id), + ('due_date', '>=', start_date), + ('due_date', '<', end_date), + ('is_invalid', '=', False), + ('is_reconciliation', '=', True) + ]) + receivable_list = [] + for account in accounts: + receivable_list.append([0, 0, { + 'contract_accounts_id': existing_bill.id, + 'management_type_id': account.management_type_id.id, + 'last_month_table': account.last_month_table, + 'this_month_table': account.this_month_table, + 'ratio': account.ratio, + 'billable_quantity': account.billable_quantity, + 'due_date': account.due_date, + 'due_date_end': account.due_date_end, + 'original_amount': account.original_amount, + 'pre_collection': account.pre_collection, + 'remark': account.remark, + }]) + existing_bill.contract_accounts_ids = receivable_list + + + def _get_month_date_range(self, year_month): + """获取年月对应的起止日期""" + year, month = map(int, year_month.split('-')) + start_date = fields.Date.from_string(f"{year}-{month}-01") + next_month = f"{year + 1}-01-01" if month == 12 else f"{year}-{month + 1}-01" + end_date = fields.Date.from_string(next_month) - timedelta(days=1) + return start_date, end_date @api.depends( 'contract_accounts_ids.management_type_id', diff --git a/yuthon_property_approval/models/inherit_yuthon_property.py b/yuthon_property_approval/models/inherit_yuthon_property.py index 1f10de41b..39ceb4509 100644 --- a/yuthon_property_approval/models/inherit_yuthon_property.py +++ b/yuthon_property_approval/models/inherit_yuthon_property.py @@ -623,6 +623,7 @@ class PropertyAccountsReceivable(models.Model): _rec_name = 'contract_id' property_ids = fields.Many2many('yuthon.property', string='物业', compute='_compute_property_ids', store=True) + lease_contract_id = fields.Many2one('property.lease.contract', string="关联租赁合同") contract_accounts_id = fields.Many2one('contract.accounts.receivable', string="合同") property_name = fields.Text(string='物业', compute="_compute_property_name") is_penalty = fields.Boolean(string='是否违约金', default=True, compute = '_compute_is_penalty', store=True) diff --git a/yuthon_property_approval/models/property_lease_contract.py b/yuthon_property_approval/models/property_lease_contract.py index 363ae0e39..c83d93d82 100644 --- a/yuthon_property_approval/models/property_lease_contract.py +++ b/yuthon_property_approval/models/property_lease_contract.py @@ -107,6 +107,7 @@ class PropertyLeaseContract(models.Model): string="租赁合同文件" ) title_address = fields.Char(string="产权地址") + receivable_ids = fields.One2many('property.accounts.receivable', 'lease_contract_id', string="应收账单") handling_opinions = fields.Text(string="经办意见") lessor_id = fields.Many2one('yuthon.property.company', string="出租方公司") rent_company = fields.Char(related='lessor_id.name', string="收租公司名称") diff --git a/yuthon_property_approval/models/property_lease_renewal.py b/yuthon_property_approval/models/property_lease_renewal.py index dbe2f43ee..e5e8e5a7c 100644 --- a/yuthon_property_approval/models/property_lease_renewal.py +++ b/yuthon_property_approval/models/property_lease_renewal.py @@ -143,4 +143,5 @@ class EarlyReceivablesLine(models.Model): receivable_id = fields.Many2one('property.accounts.receivable', string='应收账单') management_type_id = fields.Many2one(related='receivable_id.management_type_id', string='类型') due_date = fields.Date(related='receivable_id.due_date', string='应收日期') - original_amount = fields.Float(related='receivable_id.original_amount', string='金额') \ No newline at end of file + original_amount = fields.Float(related='receivable_id.original_amount', string='金额') + void = fields.Boolean(string='作废', default=False) \ No newline at end of file diff --git a/yuthon_property_approval/views/contract_accounts_receivable_viwes.xml b/yuthon_property_approval/views/contract_accounts_receivable_viwes.xml index 6097e8708..becdf6558 100644 --- a/yuthon_property_approval/views/contract_accounts_receivable_viwes.xml +++ b/yuthon_property_approval/views/contract_accounts_receivable_viwes.xml @@ -47,6 +47,13 @@ + + + 更新 + + + code + action = model.batch_create_by_contract_and_month() 应收账单(合同) diff --git a/yuthon_property_approval/views/inherit_yuthon_property_views.xml b/yuthon_property_approval/views/inherit_yuthon_property_views.xml index 8c45e0f40..8f1b070d5 100644 --- a/yuthon_property_approval/views/inherit_yuthon_property_views.xml +++ b/yuthon_property_approval/views/inherit_yuthon_property_views.xml @@ -403,6 +403,10 @@ + + + + diff --git a/yuthon_property_approval/views/property_lease_contract.xml b/yuthon_property_approval/views/property_lease_contract.xml index 5828ab609..952985e0c 100644 --- a/yuthon_property_approval/views/property_lease_contract.xml +++ b/yuthon_property_approval/views/property_lease_contract.xml @@ -839,6 +839,24 @@ + + + + + + + + + + + + + + + + + + diff --git a/yuthon_property_approval/views/property_lease_renewal.xml b/yuthon_property_approval/views/property_lease_renewal.xml index b67ad84d3..f2b29af0e 100644 --- a/yuthon_property_approval/views/property_lease_renewal.xml +++ b/yuthon_property_approval/views/property_lease_renewal.xml @@ -99,6 +99,7 @@ +