169 lines
9.4 KiB
Python
169 lines
9.4 KiB
Python
from odoo import models, fields, api, Command
|
||
from odoo.exceptions import UserError
|
||
|
||
|
||
# 已进入签约流程的业务状态:这些物业不再放入挂牌申报表
|
||
SIGN_FLOW_STATES = ('to_sign', 'signing', 'signed')
|
||
|
||
|
||
class PropertyRentalForm(models.Model):
|
||
_name = 'property.rental.form'
|
||
_description = '挂牌申报表'
|
||
_rec_name = 'name'
|
||
_inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin']
|
||
|
||
name = fields.Char(string="名称", required=True)
|
||
reason = fields.Text(string="正文")
|
||
documents_ids = fields.Many2many('ir.attachment', string="附件")
|
||
listing_method = fields.Selection([('enterprise', '企业自挂牌'), ('makeup', '广交所挂牌')], 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="部门")
|
||
property_rental_form_line_ids = fields.One2many('property.rental.form.line', 'property_rental_form_id', string="关联挂牌申报表明细行")
|
||
is_issues = fields.Boolean(string='是否上会')
|
||
issues_result = fields.Html(string="会议结果")
|
||
related_issues_id = fields.Many2one('issue.library', string="关联议题")
|
||
code = fields.Char(string="编号",
|
||
default=lambda self: self.env['ir.sequence'].next_by_code('property_rental_form_code'))
|
||
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
|
||
default='normal')
|
||
active = fields.Boolean('Active', default=True, tracking=True)
|
||
work_end = fields.Boolean(string="结束")
|
||
|
||
def _get_default_name_title(self):
|
||
return self._description if self._description else self._name
|
||
|
||
name_title = fields.Char(default=_get_default_name_title)
|
||
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
|
||
# 「经办人 / 审批状态」取自本单据的工作流记录(口径同 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='property_rental_form_line_ids.property_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.model
|
||
def _get_listable_properties(self, properties):
|
||
"""剔除已进入签约流程(待签约 / 签约中 / 已签约)的物业 —— 这些不放进挂牌申报表"""
|
||
return properties.filtered(lambda prop: prop.business_state not in SIGN_FLOW_STATES)
|
||
|
||
@api.model
|
||
def _check_listing_available(self, properties):
|
||
"""挂牌申请的前置校验:
|
||
① 物业尚未进入挂牌流程(业务状态为 挂牌中/已挂牌 时不可再提交;待签约/签约中/已签约
|
||
已由 `_get_listable_properties()` 在入口处剔除,此处作兜底);
|
||
② 同一物业不能重复申请 —— 已存在「未进回收站」的挂牌申报表即视为已申请过。
|
||
"""
|
||
labels = dict(self.env['yuthon.property']._fields['business_state'].selection)
|
||
locked_states = ('listing', 'listed', 'to_sign', 'signing', 'signed')
|
||
not_ready = properties.filtered(lambda prop: prop.business_state in locked_states)
|
||
if not_ready:
|
||
detail = '、'.join(
|
||
'%s(%s)' % (prop.name, labels.get(prop.business_state) or '未设置')
|
||
for prop in not_ready)
|
||
raise UserError('以下物业已进入挂牌/签约流程,不能提交挂牌申请:%s' % detail)
|
||
|
||
duplicated = self._find_duplicated_properties(properties)
|
||
if duplicated:
|
||
raise UserError('以下物业已提交过挂牌申请(未进回收站),不能重复申请:%s'
|
||
% '、'.join(duplicated.mapped('name')))
|
||
|
||
@api.model
|
||
def _find_duplicated_properties(self, properties):
|
||
"""已存在「未进回收站」的挂牌申报表的物业(判断依据:该单据有有效的工作流记录)"""
|
||
forms = self.env['property.rental.form'].search([
|
||
('property_rental_form_line_ids.property_id', 'in', properties.ids),
|
||
])
|
||
alive = forms.filtered(lambda form: form._has_active_workflow_record())
|
||
return alive.mapped('property_rental_form_line_ids.property_id') & properties
|
||
|
||
@api.model_create_multi
|
||
def create(self, vals_list):
|
||
# 已进入签约流程(待签约 / 签约中 / 已签约)的物业**不放进挂牌申报表**:在建表前直接剔除这些明细行
|
||
prop_ids = []
|
||
for vals in vals_list:
|
||
cmds = vals.get('property_rental_form_line_ids') or []
|
||
kept = []
|
||
for cmd in cmds:
|
||
if cmd[0] == Command.CREATE and len(cmd) > 2 and cmd[2].get('property_id'):
|
||
prop = self.env['yuthon.property'].browse(cmd[2]['property_id'])
|
||
if prop.business_state in SIGN_FLOW_STATES:
|
||
continue
|
||
prop_ids.append(prop.id)
|
||
kept.append(cmd)
|
||
if len(kept) != len(cmds):
|
||
if not kept:
|
||
raise UserError('所选物业均已进入签约流程(待签约/签约中/已签约),不能在挂牌申报表中提交')
|
||
vals['property_rental_form_line_ids'] = kept
|
||
# 再校验(在建表之前):已进入挂牌/签约流程的物业不能提交
|
||
if prop_ids:
|
||
self._check_listing_available(self.env['yuthon.property'].browse(prop_ids))
|
||
|
||
forms = super().create(vals_list)
|
||
# 保存时业务状态为「待挂牌」;推进到「挂牌中」是在**转交**时(见 _on_workflow_transfer)
|
||
props = forms.mapped('property_rental_form_line_ids.property_id')
|
||
waiting = props.filtered(
|
||
lambda prop: prop.business_state not in ('listing', 'listed', 'to_sign', 'signing', 'signed'))
|
||
if waiting:
|
||
waiting.write({'business_state': 'to_list'})
|
||
return forms
|
||
|
||
def _on_workflow_transfer(self):
|
||
"""转交(工作流弹窗触发,仅挂牌申报表/成交确认书):关联物业业务状态「待挂牌」→「挂牌中」"""
|
||
props = self.mapped('property_rental_form_line_ids.property_id')
|
||
waiting = props.filtered(lambda prop: prop.business_state in (False, '', 'to_list'))
|
||
if waiting:
|
||
waiting.write({'business_state': 'listing'})
|
||
|
||
def end_approval(self):
|
||
"""审批结束:关联物业的业务状态推进为「已挂牌」"""
|
||
props = self.mapped('property_rental_form_line_ids.property_id')
|
||
waiting = props.filtered(lambda prop: prop.business_state in (False, '', 'listing'))
|
||
if waiting:
|
||
waiting.write({'business_state': 'listed'})
|
||
|
||
def action_transaction_confirmed(self):
|
||
"""成交确认书:把本单的物业带进「成交确认审批」(property.confirm) 的物业列表"""
|
||
self.ensure_one()
|
||
properties = self.property_rental_form_line_ids.mapped('property_id')
|
||
if not properties:
|
||
raise UserError('该挂牌申报表未关联物业,无法生成成交确认书')
|
||
form_id = self.env.ref('yuthon_property_approval.view_property_confirm_form').id
|
||
return {
|
||
'name': '成交确认审批',
|
||
'type': 'ir.actions.act_window',
|
||
'res_model': 'property.confirm',
|
||
'view_mode': 'form',
|
||
'views': [(form_id, 'form')],
|
||
'target': 'current',
|
||
'context': {
|
||
'default_lease_ids': [(0, 0, {'address_id': prop.id}) for prop in properties],
|
||
},
|
||
}
|
||
|
||
|
||
class PropertyRentalFormLine(models.Model):
|
||
_name = 'property.rental.form.line'
|
||
_description = '挂牌申报表明细行'
|
||
|
||
property_rental_form_id = fields.Many2one('property.rental.form', string="关联挂牌申报表")
|
||
property_id = fields.Many2one('yuthon.property', string='物业名称', required=True)
|
||
registered_id = fields.Many2one(related='property_id.registered_id', string='证载用途')
|
||
evaluation_area = fields.Float(related='property_id.evaluation_area', string='出租面积(m²)')
|
||
current_status = fields.Date(related='property_id.current_status', string='租聘到期日')
|
||
now_rent_price = fields.Float(related='property_id.rental_unit_price',string='现租价(元/m² •月)')
|
||
evaluate_rent_price = fields.Float(string='评估租(元/m² •月)')
|
||
upset_square = fields.Float(string='底价(元/m² •月)')
|
||
upset = fields.Float(string='底价(元/月)')
|
||
lease_period = fields.Char(string='租凭年限')
|
||
increment_rate = fields.Float(string='递增率')
|
||
rental_use = fields.Many2one('yuthon.rental.purpose',string='出租用途')
|
||
other = fields.Char(string='其他')
|
||
remarks = fields.Text(string='备注') |