diff --git a/yuthon_property_approval/models/property_management.py b/yuthon_property_approval/models/property_management.py index 030206dcb..bcd64c51e 100644 --- a/yuthon_property_approval/models/property_management.py +++ b/yuthon_property_approval/models/property_management.py @@ -5,6 +5,7 @@ from odoo import models, fields, api, exceptions, _ from datetime import timedelta from dateutil.relativedelta import relativedelta import calendar +import re from datetime import datetime, date @@ -44,6 +45,7 @@ class PropertyManagement(models.Model): name_title = fields.Char(default=_get_default_name_title) document_ids = fields.Many2many('ir.attachment', string="附件") + is_generate_new_contract = fields.Boolean(string='是否生成新合同', default=False) self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])]) @api.onchange('precinct_id') @@ -80,8 +82,132 @@ class PropertyManagement(models.Model): 'tenure_type': line.tenure_type })] + def _generate_and_resolve_contracts(self): + """ + 如果勾选"生成新合同",为每个物业对应的合同创建新合同副本。 + 返回 {old_contract_id: new_contract_id} 映射,没勾选返回空字典 + """ + new_contract_map = {} + if not self.is_generate_new_contract: + return new_contract_map + + processed = set() + for manage_line in self.management_line2_ids: + if not manage_line.property_id: + continue + lease_line = self.env['property.lease.contract.line'].search([ + ('address_id', '=', manage_line.property_id.id), + ('lease_id', '!=', False), + ], limit=1) + if not lease_line: + continue + old_contract = lease_line.lease_id + if old_contract.id in processed: + continue + processed.add(old_contract.id) + + # 编号尾部数字+1:租(2023)37号-2 → 租(2023)37号-3 + base_code = old_contract.contract_code or '' + match = re.match(r'^(.+)-(\d+)$', base_code) + if match: + prefix = match.group(1) + counter = int(match.group(2)) + 1 + else: + prefix = base_code + counter = 1 + new_code = f"{prefix}-{counter}" + while self.env['property.lease.contract'].search( + [('contract_code', '=', new_code)], limit=1): + counter += 1 + new_code = f"{prefix}-{counter}" + + new_contract = old_contract.copy({ + 'contract_code': new_code, + 'contract_source_id': old_contract.id, + 'condition': 'new', # 进入合同审批列表 + }) + new_contract_map[old_contract.id] = new_contract.id + + # 手动复制物业明细行(copy 未复制 One2many) + for old_line in old_contract.lease_ids: + old_line.copy({'lease_id': new_contract.id}) + + # 时间处理 + day_before = self.start_time - timedelta(days=1) + old_contract.write({'actual_end_time': day_before}) + new_contract.write({'actual_start_time': self.start_time, + 'is_child_contract': True}) + + # 触发原合同状态更新 + old_contract.contract_time() + new_contract._onchange_action_generate_details() + + return new_contract_map + + def _handle_rent_account_change(self, manage_line, prev_info, new_contract_map): + """ + 收租公司账号变更时触发: + ① 原合同 → property.bills.list 应付账单(押金) + ② 当前合同 → property.accounts.receivable 押金应收 + 勾了生成新合同 → current_contract 直接取 new_contract_map 里的新合同ID + """ + if prev_info.yuthon_property_id.company_id.id == self.company_id.id: + return + if prev_info.yuthon_property_id.company_id.rent_account == self.company_id.rent_account: + return + + # 找现有合同 + lease_line = self.env['property.lease.contract.line'].search([ + ('address_id', '=', manage_line.property_id.id), + ('lease_id', '!=', False), + ('lease_id.contact_state', '=', 'ing'), + ], limit=1) + if not lease_line: + return + + old_contract = lease_line.lease_id + # 勾了新合同 → 直接用新合同ID;没勾 → 用现有合同 + new_cid = new_contract_map.get(old_contract.id) + current_contract = self.env['property.lease.contract'].browse(new_cid) if new_cid else old_contract + original_contract = current_contract.contract_source_id + + # 获取或创建"押金"管理类型 + deposit_type = self.env['yuthon.management.type'].search( + [('name', '=', '押金')], limit=1) + if not deposit_type: + deposit_type = self.env['yuthon.management.type'].create({'name': '押金'}) + + # ① 原合同:创建应付账单 property.bills.list + if original_contract and original_contract.deposit: + existing_bill = self.env['property.bills.list'].search([ + ('contract_id', '=', original_contract.id), + ('management_type_id', '=', deposit_type.id), + ], limit=1) + if not existing_bill: + self.env['property.bills.list'].create({ + 'contract_id': original_contract.id, + 'amount': original_contract.deposit, + 'due_date': self.start_time, + 'management_type_id': deposit_type.id, + }) + + # ② 当前合同:查找或创建押金应收 property.accounts.receivable + if current_contract and current_contract.deposit: + existing_receivable = self.env['property.accounts.receivable'].search([ + ('contract_id', '=', current_contract.id), + ('management_type_id', '=', deposit_type.id), + ], limit=1) + if not existing_receivable: + self.env['property.accounts.receivable'].create({ + 'contract_id': current_contract.id, + 'due_date': self.start_time, + 'original_amount': current_contract.deposit, + 'management_type_id': deposit_type.id, + }) + def approval_end(self): for record in self: + new_contract_map = record._generate_and_resolve_contracts() for manage_line in record.management_line2_ids: # 更新信息行的结束日期 if manage_line.information_line_id: @@ -145,6 +271,9 @@ class PropertyManagement(models.Model): }) lease_contract_ids.version = new_version + # 收租账号变更 → 应付账单 + 押金应收 + record._handle_rent_account_change(manage_line, prev_info, new_contract_map) + existing_info = self.env['manage.information.line'].search([ ('yuthon_property_id', '=', target_property_id), ('start_time', '=', target_start_time) diff --git a/yuthon_property_approval/views/property_management.xml b/yuthon_property_approval/views/property_management.xml index 73df5e8ef..748933cc6 100644 --- a/yuthon_property_approval/views/property_management.xml +++ b/yuthon_property_approval/views/property_management.xml @@ -56,6 +56,7 @@ +