Files
gzth/yuthon_property_approval/models/property_confirm.py
T
2026-09-24 19:38:13 +08:00

183 lines
9.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models, fields, api, exceptions, _, Command
from odoo.exceptions import UserError
class PropertyConfirm(models.Model):
_name = 'property.confirm'
_description = '物业成交确认审批'
_inherit = ['soong.workflow.mixin', 'mail.thread.main.attachment', 'mail.activity.mixin']
_rec_name = 'name'
name = fields.Char(string='标题')
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('property_confirm_code'))
property_documents_ids = fields.Many2many('documents.document', string="物业成交确认文件")
lessee = fields.Char(string="承租方")
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
active = fields.Boolean('Active', default=True, tracking=True)
work_end = fields.Boolean(string="结束")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度', default='normal')
is_chapter = fields.Selection([('yes', '是'), ('no', '否')], string='是否用章', default='no')
property_name = fields.Char(string='物业信息')
handling_opinions = fields.Text(string="经办意见")
type_stamp_ids = fields.Many2many('seals.type.setting', string='用章类型', domain="['&', ('start_date', '<=', context_today()), '|', ('end_date', '=', False), ('end_date', '>=', context_today())]")
documents_ids = fields.Many2many('ir.attachment', string="附件")
lease_ids = fields.One2many('property.lease.contract.line', 'confirm_id', string="物业列表")
# 面积:下方物业明细行「可租面积(property_area)」的合计
property_area = fields.Float(string="面积", compute="_compute_property_area", digits=(16, 4))
# 租期年限(整型)
lease_term_years = fields.Integer(string="租期年限")
# 免租天数(整型)
rent_free_days = fields.Integer(string="免租天数")
# 每几年递增(整型,与递增百分比组合成「每 __ 年递增 __ %」)
increments_few_years = fields.Integer(string="每几年递增")
# 递增百分比
annual_increase_percentage = fields.Float(string="递增百分比", digits=(6, 2))
# 「经办人 / 审批状态」取自本单据的工作流记录(口径同 property.lease.contract)
employee_ids = fields.Many2many('hr.employee', string="当前经办人", compute='_compute_workflow')
approve_state = fields.Selection([("start", "草稿"), ("pending", "审批中"), ("end", "结束")],
string="审批状态", compute='_compute_workflow')
# 业务状态:取物业明细「第一个」行的物业业务状态(只读展示)
business_state = fields.Selection(
related='lease_ids.address_id.business_state', string='业务状态')
@api.depends('code')
def _compute_workflow(self):
for record in self:
workflow = record._get_active_workflow_record()
record.employee_ids = workflow.employee_ids if workflow else False
record.approve_state = workflow.approve_state if workflow else False
@api.depends('lease_ids', 'lease_ids.property_area')
def _compute_property_area(self):
# 汇总每条成交确认单下所有物业明细行的可租面积
for rec in self:
rec.property_area = sum(rec.lease_ids.mapped('property_area'))
@staticmethod
def _x2m_lease_property_ids(commands):
"""从「物业列表」的一对多命令里取出物业 id(address_id)"""
ids = set()
for cmd in commands or []:
if cmd[0] == Command.CREATE and len(cmd) > 2 and cmd[2].get('address_id'):
ids.add(cmd[2]['address_id'])
return list(ids)
@api.model
def _check_no_duplicate_application(self, properties):
"""前置校验:同一物业不能重复生成成交确认书
(已存在「未进回收站」的成交确认书即视为已申请过)"""
records = self.env['property.confirm'].search([('lease_ids.address_id', 'in', properties.ids)])
alive = records.filtered(lambda rec: rec._has_active_workflow_record())
duplicated = alive.mapped('lease_ids.address_id') & properties
if duplicated:
raise UserError('以下物业已生成过成交确认书(未进回收站),不能重复申请:%s'
% '、'.join(duplicated.mapped('name')))
@api.model_create_multi
def create(self, vals_list):
# 先校验(在建表之前):同一物业不能重复生成成交确认书
prop_ids = []
for vals in vals_list:
prop_ids += self._x2m_lease_property_ids(vals.get('lease_ids'))
if prop_ids:
self._check_no_duplicate_application(self.env['yuthon.property'].browse(set(prop_ids)))
records = super().create(vals_list)
# 保存时业务状态为「待签约」;推进到「签约中」是在**转交**时(见 _on_workflow_transfer)
# 只向前推进:已处于「待签约/签约中/已签约」的不再改动,避免把流程回退
props = records.mapped('lease_ids.address_id').filtered(
lambda prop: prop.business_state not in ('to_sign', 'signing', 'signed'))
if props:
props.write({'business_state': 'to_sign'})
return records
def _on_workflow_transfer(self):
"""转交(工作流弹窗触发,仅挂牌申报表/成交确认书):关联物业业务状态「待签约」→「签约中」"""
props = self.mapped('lease_ids.address_id').filtered(
lambda prop: prop.business_state in (False, '', 'to_sign'))
if props:
props.write({'business_state': 'signing'})
def action_create_contract(self):
"""创建合同:把成交确认书的物业与条件带进租赁合同
字段对应关系:
- 物业 → 合同「物业信息明细行」(`lease_ids.address_id`)
- 面积 → 合同「总面积」(`total_area`)
- 租期年限 → 合同「租期(年)」(`lease_term_year`)
- 免租天数 → 合同「免租期 月/日」;**31 天算 1 个月**(如 32 天 → 1 月 1 日)
- 每 X 年递增 Y% → 合同「每几年递增」+ 递增方式=百分比 + 递增值
(对应合同递增组合字段的后半部分,不涉及「自第 X 年开始」)
"""
self.ensure_one()
# 只有审批状态为「结束」的成交确认书才能创建合同(列表按钮同样按此显隐)
if self.approve_state != 'end':
raise UserError('只有审批状态为「结束」的成交确认书才能创建合同')
properties = self.lease_ids.mapped('address_id')
if not properties:
raise UserError('该成交确认书未关联物业,无法创建合同')
form_id = self.env.ref('yuthon_property_approval.view_property_lease_contract_form').id
# 免租天数换算成「月/日」:31 天 = 1 个月;余数为 0 时借一个月,避免出现「X月0日」
# 例:31 天 → 0月31日;32 天 → 1月1日;62 天 → 1月31日
free_months, free_days = divmod(self.rent_free_days or 0, 31)
if free_months and not free_days:
free_months -= 1
free_days = 31
return {
'name': '合同审批',
'type': 'ir.actions.act_window',
'res_model': 'property.lease.contract',
'view_mode': 'form',
'views': [(form_id, 'form')],
'target': 'current',
'context': {
'default_lease_ids': [(0, 0, {'address_id': prop.id}) for prop in properties],
'default_total_area': self.property_area,
'default_lease_term_year': self.lease_term_years,
'default_rent_free_period_month': free_months,
'default_rent_free_period_days': free_days,
'default_increments_every_few_years': self.increments_few_years,
'default_increment_method': 'percentage',
'default_increment_value': self.annual_increase_percentage,
},
}
def _get_default_name_title(self):
return '成交确认书'
name_title = fields.Char(default=_get_default_name_title)
@api.onchange('property_name')
def _onchange_property_name(self):
if self.property_name:
self.name = '成交确认书-' + self.property_name
else:
self.name = '成交确认书'
def choose_property_button(self):
return {
"type": "ir.actions.act_window",
"name": "批量选择物业信息",
"res_model": "choose.confirm.property.wizard",
"view_mode": "form",
"target": "new",
"context": {
'default_confirm_id': self.id,
}
}
class PropertyConfirm(models.Model):
_inherit = 'property.confirm'
def action_print_property_confirm(self):
"""打印成交确认书"""
self.ensure_one()
report = self.env.ref('yuthon_property_approval.action_property_confirm_report')
return report.report_action(self)