添加功能
This commit is contained in:
@@ -20,7 +20,7 @@ class PropertyLeaseRenewal(models.Model):
|
||||
company_id = fields.Many2one(related='user_id.company_id', string="公司")
|
||||
code = fields.Char(string="编号",
|
||||
default=lambda self: self.env['ir.sequence'].next_by_code('property_lease_renewal_code'))
|
||||
renewal_type = fields.Selection([('early_checkout', '合同终止'), ('lease', '承租方变更'), ('extend', '延长租期')], string='变更类型')
|
||||
renewal_type = fields.Selection([('lease', '承租方变更'), ('extend', '延长租期')], string='变更类型')
|
||||
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
|
||||
default='normal')
|
||||
is_chapter = fields.Selection([('yes', '是'), ('no', '否')], string="是否用章")
|
||||
@@ -53,20 +53,10 @@ class PropertyLeaseRenewal(models.Model):
|
||||
fee = fields.Float(string='变更费用')
|
||||
document_ids = fields.Many2many('ir.attachment', string="变更附件")
|
||||
|
||||
early_explain = fields.Text(string="退租说明")
|
||||
early_reason = fields.Selection([('normal', '正常退租'), ('agree', '协商一致'), ('settle', '违约结清'), ('other', '其他')], string="退租原因")
|
||||
early_quitting_date = fields.Date(string="退租日期")
|
||||
|
||||
active = fields.Boolean('Active', default=True, tracking=True)
|
||||
work_end = fields.Boolean(string="结束")
|
||||
|
||||
deposit = fields.Float(string="原押金")
|
||||
refund_amount = fields.Float(string="退款金额")
|
||||
deposit_treatment = fields.Selection([('refund', '全额退押'), ('part_refund', '部分退租'), ('no_refund', '全额没收')], string="押金处理方式", default='refund')
|
||||
total_receivables = fields.Float(string="应收金额", compute="_compute_total_receivables")
|
||||
forfeit = fields.Float(string="没收金额")
|
||||
|
||||
receivables_ids = fields.One2many('early.receivables.line', 'renewal_id', string='应收明细')
|
||||
|
||||
# 延长租期
|
||||
actual_end_date = fields.Date(string='实际结束日期')
|
||||
@@ -92,11 +82,6 @@ class PropertyLeaseRenewal(models.Model):
|
||||
# 需求调整:不做自动填充,保留用户手动输入的联系人
|
||||
return
|
||||
|
||||
@api.onchange('refund_amount')
|
||||
def _onchange_forfeit(self):
|
||||
for rec in self:
|
||||
rec.forfeit = rec.deposit - rec.refund_amount
|
||||
|
||||
@api.onchange('contact')
|
||||
def _onchange_contact_fill_info(self):
|
||||
"""填写联系人后,按员工信息带出身份证号与联系电话;不再从承租方带出。"""
|
||||
@@ -114,14 +99,6 @@ class PropertyLeaseRenewal(models.Model):
|
||||
rec.phone = False
|
||||
rec.card = False
|
||||
|
||||
@api.depends('receivables_ids', 'receivables_ids.original_amount', 'receivables_ids.reduction_amount',
|
||||
'receivables_ids.void')
|
||||
def _compute_total_receivables(self):
|
||||
for renewal in self:
|
||||
valid_receivable_lines = renewal.receivables_ids.filtered(lambda line: not line.void and line.is_reconciliation == False)
|
||||
total = sum(line.original_amount - line.reduction_amount for line in valid_receivable_lines)
|
||||
renewal.total_receivables = total
|
||||
|
||||
def action_print_lease_renewal(self):
|
||||
"""打印租赁变更审批"""
|
||||
self.ensure_one()
|
||||
@@ -201,305 +178,6 @@ class PropertyLeaseRenewal(models.Model):
|
||||
'management_type_id': management_type_id.id,
|
||||
'due_date': rec.effective_date,
|
||||
})
|
||||
elif rec.renewal_type == 'early_checkout':
|
||||
workflow_record_id = self.env["soong.workflow.record"].search(
|
||||
[("res_model", "=", self._name), ("res_id", "=", self.id)])
|
||||
lessor_id = rec.contract_id.lessor_id
|
||||
company_id = self.env['res.company'].search([('name', '=', '集团本部')], limit=1)
|
||||
if lessor_id.referred in ['天河投资', '天投城建']:
|
||||
company_id = self.env['res.company'].search([('name', '=', '集团本部')], limit=1)
|
||||
elif lessor_id.referred in ['天河物管']:
|
||||
company_id = self.env['res.company'].browse(3)
|
||||
elif lessor_id.referred in ['天河粮储']:
|
||||
company_id = self.env['res.company'].search([('name', '=', '天河粮储')], limit=1)
|
||||
|
||||
# 取本审批最后一条流程日志的操作时间,作为账单 due_date
|
||||
operation_log = self.env['soong.workflow.log'].search([
|
||||
('model', '=', self._name),
|
||||
('res_id', '=', rec.id),
|
||||
], order='lase_click_date DESC, id DESC', limit=1)
|
||||
operation_date = operation_log.lase_click_date.date() if operation_log.lase_click_date else fields.Date.today()
|
||||
|
||||
# 非押金退款明细(除押金外的退款,原逻辑保留)
|
||||
if rec.receivables_ids:
|
||||
refund_lines = rec.receivables_ids.filtered(lambda l: l.refund_amount > 0 and l.management_type_id.name != '押金')
|
||||
bills_line_list = []
|
||||
if refund_lines:
|
||||
for refund_line in refund_lines:
|
||||
bills_line_list.append({
|
||||
'lessor_id': rec.contract_id.lessor_id.id,
|
||||
'due_date': operation_date,
|
||||
'management_type_id': refund_line.management_type_id.id,
|
||||
'amount': refund_line.refund_amount,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'receivables_id': refund_line.id,
|
||||
'remake': rec.early_explain
|
||||
})
|
||||
if bills_line_list:
|
||||
self.env['property.bills.list'].create(bills_line_list)
|
||||
|
||||
# 押金处理(根据押金处理方式分三种,先判断去重再创建)
|
||||
deposit_management_type = self.env['yuthon.management.type'].search(
|
||||
[('name', '=', '押金')], limit=1)
|
||||
|
||||
if rec.deposit_treatment == 'refund':
|
||||
# 全额退押金:仅创建 bills.list,金额 = 原押金 deposit
|
||||
if rec.deposit > 0:
|
||||
exist_bill = self.env['property.bills.list'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', deposit_management_type.id),
|
||||
('amount', '=', rec.deposit),
|
||||
('workflow_record_id', '=', workflow_record_id.id),
|
||||
], limit=1)
|
||||
if not exist_bill:
|
||||
self.env['property.bills.list'].create({
|
||||
'lessor_id': rec.contract_id.lessor_id.id,
|
||||
'due_date': operation_date,
|
||||
'management_type_id': deposit_management_type.id,
|
||||
'amount': rec.deposit,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.early_explain,
|
||||
'workflow_record_id': workflow_record_id.id,
|
||||
})
|
||||
|
||||
elif rec.deposit_treatment == 'part_refund':
|
||||
# 部分退租:bills.list 金额 = refund_amount;bank.statements 和 receivable 金额 = forfeit
|
||||
if rec.refund_amount > 0:
|
||||
exist_bill = self.env['property.bills.list'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', deposit_management_type.id),
|
||||
('amount', '=', rec.refund_amount),
|
||||
('workflow_record_id', '=', workflow_record_id.id),
|
||||
], limit=1)
|
||||
if not exist_bill:
|
||||
self.env['property.bills.list'].create({
|
||||
'lessor_id': rec.contract_id.lessor_id.id,
|
||||
'due_date': operation_date,
|
||||
'management_type_id': deposit_management_type.id,
|
||||
'amount': rec.refund_amount,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.early_explain,
|
||||
'workflow_record_id': workflow_record_id.id,
|
||||
})
|
||||
if rec.forfeit > 0:
|
||||
start_time = datetime.combine(rec.early_quitting_date, datetime.min.time().replace(hour=8, minute=00))
|
||||
existing_bank_statement = self.env['property.bank.statements'].sudo().search([
|
||||
('start_time', '=', start_time),
|
||||
('original_amount', '=', rec.forfeit),
|
||||
('name_account', '=', rec.lessee_id.name),
|
||||
('remake', '=', rec.early_explain),
|
||||
('workflow_record_id', '=', workflow_record_id.id),
|
||||
], limit=1)
|
||||
if not existing_bank_statement:
|
||||
bank_accounts = self.env['property.bank.line'].search([
|
||||
('tenant_id', '=', rec.lessee_id.id)
|
||||
]).mapped('bank')
|
||||
filtered_accounts = [acc for acc in bank_accounts if acc]
|
||||
bank_accounts = filtered_accounts[0] if filtered_accounts else None
|
||||
rec.contract_id.write({
|
||||
'actual_end_time': rec.early_quitting_date
|
||||
})
|
||||
bank_id = self.env['property.bank.statements'].sudo().create({
|
||||
'start_time': start_time,
|
||||
'name': bank_accounts,
|
||||
'original_amount': rec.forfeit,
|
||||
'name_account': rec.lessee_id.name,
|
||||
'remake': rec.early_explain,
|
||||
'lending_direction': 'loan',
|
||||
'workflow_record_id': workflow_record_id.id,
|
||||
'company_id': company_id.id,
|
||||
'your_own_unit': lessor_id.referred,
|
||||
'your_own_account': lessor_id.rent_account,
|
||||
})
|
||||
bank_id._compute_property_employee_id()
|
||||
|
||||
management_type_id = self.env['yuthon.management.type'].search([
|
||||
('name', '=', '违约金')
|
||||
], limit=1)
|
||||
exist_receivable = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', management_type_id.id),
|
||||
('due_date', '=', rec.early_quitting_date),
|
||||
('original_amount', '=', rec.forfeit),
|
||||
], limit=1)
|
||||
if not exist_receivable:
|
||||
self.env['property.accounts.receivable'].create({
|
||||
'contract_id': rec.contract_id.id,
|
||||
'management_type_id': management_type_id.id,
|
||||
'due_date': rec.early_quitting_date,
|
||||
'original_amount': rec.forfeit,
|
||||
'remark': rec.early_explain,
|
||||
})
|
||||
deposit_id = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id.name', '=', '押金'),
|
||||
], limit=1)
|
||||
if deposit_id:
|
||||
deposit_id.write({
|
||||
'workflow_record_id': workflow_record_id.id
|
||||
})
|
||||
|
||||
elif rec.deposit_treatment == 'no_refund':
|
||||
# 全额没收:bills.list、bank.statements、receivable 金额均为 deposit
|
||||
if rec.deposit > 0:
|
||||
exist_bill = self.env['property.bills.list'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', deposit_management_type.id),
|
||||
('amount', '=', rec.deposit),
|
||||
('workflow_record_id', '=', workflow_record_id.id),
|
||||
], limit=1)
|
||||
if not exist_bill:
|
||||
bill = self.env['property.bills.list'].create({
|
||||
'lessor_id': rec.contract_id.lessor_id.id,
|
||||
'due_date': operation_date,
|
||||
'management_type_id': deposit_management_type.id,
|
||||
'amount': rec.deposit,
|
||||
'contract_id': rec.contract_id.id,
|
||||
'remake': rec.early_explain,
|
||||
'workflow_record_id': workflow_record_id.id,
|
||||
})
|
||||
else:
|
||||
bill = exist_bill
|
||||
|
||||
start_time = datetime.combine(rec.early_quitting_date, datetime.min.time().replace(hour=8, minute=00))
|
||||
existing_bank_statement = self.env['property.bank.statements'].sudo().search([
|
||||
('start_time', '=', start_time),
|
||||
('original_amount', '=', rec.deposit),
|
||||
('name_account', '=', rec.lessee_id.name),
|
||||
('remake', '=', rec.early_explain),
|
||||
('workflow_record_id', '=', workflow_record_id.id),
|
||||
], limit=1)
|
||||
if not existing_bank_statement:
|
||||
bank_accounts = self.env['property.bank.line'].search([
|
||||
('tenant_id', '=', rec.lessee_id.id)
|
||||
]).mapped('bank')
|
||||
filtered_accounts = [acc for acc in bank_accounts if acc]
|
||||
bank_accounts = filtered_accounts[0] if filtered_accounts else None
|
||||
rec.contract_id.write({
|
||||
'actual_end_time': rec.early_quitting_date
|
||||
})
|
||||
bank_id = self.env['property.bank.statements'].sudo().create({
|
||||
'start_time': start_time,
|
||||
'name': bank_accounts,
|
||||
'original_amount': rec.deposit,
|
||||
'name_account': rec.lessee_id.name,
|
||||
'remake': rec.early_explain,
|
||||
'lending_direction': 'loan',
|
||||
'workflow_record_id': workflow_record_id.id,
|
||||
'company_id': company_id.id,
|
||||
'your_own_unit': lessor_id.referred,
|
||||
'your_own_account': lessor_id.rent_account,
|
||||
})
|
||||
bank_id._compute_property_employee_id()
|
||||
else:
|
||||
bank_id = existing_bank_statement
|
||||
|
||||
management_type_id = self.env['yuthon.management.type'].search([
|
||||
('name', '=', '违约金')
|
||||
], limit=1)
|
||||
exist_receivable = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', management_type_id.id),
|
||||
('due_date', '=', rec.early_quitting_date),
|
||||
('original_amount', '=', rec.deposit),
|
||||
], limit=1)
|
||||
if not exist_receivable:
|
||||
self.env['property.accounts.receivable'].create({
|
||||
'contract_id': rec.contract_id.id,
|
||||
'management_type_id': management_type_id.id,
|
||||
'due_date': rec.early_quitting_date,
|
||||
'original_amount': rec.deposit,
|
||||
'remark': rec.early_explain,
|
||||
})
|
||||
|
||||
# ===== 触发 action_pay + button_reconciliation 的真实逻辑 =====
|
||||
# 说明:action_pay / button_reconciliation 按钮本身只是返回向导弹窗的方法,
|
||||
# 真正的业务在各自 wizard 的 confirm / 对账逻辑里。这里不再手工 write 子集字段,
|
||||
# 而是直接调用 property.bills.wizard 的 _do_pay()(与弹窗 confirm 共用同一份支付逻辑),
|
||||
# 以及复现银行流水对账的核心效果,保证与人工点“核销/对账”完全一致。
|
||||
deposit_receivable = self.env['property.accounts.receivable'].search([
|
||||
('contract_id', '=', rec.contract_id.id),
|
||||
('management_type_id', '=', deposit_management_type.id),
|
||||
], limit=1)
|
||||
|
||||
# 1) 支付效果(action_pay):调用支付弹窗的真实逻辑 —— 实付日期=应付日期、标记已付、
|
||||
# 回写押金应收单实付日期与支付状态、结清合同。全额没收场景下跳过 confirm 的未对账校验。
|
||||
if bill and not bill.actual_date:
|
||||
bill.amount_actual = bill.amount
|
||||
pay_wizard = self.env['property.bills.wizard'].create({
|
||||
'bills_list_id': bill.id,
|
||||
'actual_date': bill.due_date,
|
||||
'receivables_id': deposit_receivable.id if deposit_receivable else False,
|
||||
})
|
||||
pay_wizard._do_pay()
|
||||
|
||||
# 2) 对账效果(button_reconciliation):bank.statements 与押金应收对账
|
||||
if bank_id and bank_id.bank_state != 'reconciled':
|
||||
bank_id.bank_state = 'reconciled'
|
||||
bank_id.yes_amount = bank_id.original_amount
|
||||
bank_id.reconciliation_time = fields.Datetime.now() - timedelta(hours=8)
|
||||
# 自动核销违约金
|
||||
if exist_receivable:
|
||||
exist_receivable.write({
|
||||
'has_date': bill.due_date if bill else operation_date,
|
||||
'is_reconciliation': True,
|
||||
'payout_date': operation_date,
|
||||
'delivered1': rec.deposit,
|
||||
'deposit_state': 'paid',
|
||||
'reconciliation_time': fields.Datetime.now(),
|
||||
'bank_id': bank_id.id,
|
||||
})
|
||||
self.env['receivable.modify.line'].create({
|
||||
'bank_id': bank_id.id,
|
||||
'not_collected': rec.deposit,
|
||||
'reconciliation_date': operation_date,
|
||||
'receivable_id': exist_receivable.id,
|
||||
'is_write': True,
|
||||
'operation_date': fields.Date.today(),
|
||||
'is_penalty': True,
|
||||
'remake1': rec.early_explain,
|
||||
'amount': rec.deposit,
|
||||
})
|
||||
rec.contract_id.contact_state = 'settle'
|
||||
rec.contract_id.compute_is_has()
|
||||
|
||||
# 原有作废/减免逻辑保留
|
||||
for receivable_id in rec.receivables_ids:
|
||||
if receivable_id.void:
|
||||
receivable_id.receivable_id.write({
|
||||
'is_invalid': True,
|
||||
'void_date': operation_date
|
||||
})
|
||||
if receivable_id.reduction_amount:
|
||||
receivable_id.receivable_id.discount_amount = receivable_id.reduction_amount
|
||||
receivable_id.receivable_id.discount_date = operation_date
|
||||
|
||||
@api.onchange('early_quitting_date', 'contract_id')
|
||||
def _onchange_early_quitting_date(self):
|
||||
self.receivables_ids = [(5, 0, 0)]
|
||||
receivable_ids = self.env['property.accounts.receivable'].search([
|
||||
('due_date', '<=', self.early_quitting_date),
|
||||
('contract_id', '=', self.contract_id.id),
|
||||
])
|
||||
deposit_receivables = self.env['property.accounts.receivable']
|
||||
normal_receivables = self.env['property.accounts.receivable']
|
||||
for rec in receivable_ids:
|
||||
if rec.management_type_id and rec.management_type_id.name == '押金':
|
||||
deposit_receivables |= rec
|
||||
else:
|
||||
normal_receivables |= rec
|
||||
|
||||
if deposit_receivables:
|
||||
self.deposit = sum(rec.original_amount for rec in deposit_receivables)
|
||||
|
||||
receivable_list = []
|
||||
for rec in normal_receivables:
|
||||
receivable_list.append([0, 0, {
|
||||
'receivable_id': rec.id,
|
||||
'is_reconciliation': rec.is_reconciliation,
|
||||
}])
|
||||
self.receivables_ids = receivable_list
|
||||
|
||||
|
||||
@api.onchange('contract_id', 'renewal_type')
|
||||
def _onchange_name(self):
|
||||
@@ -511,15 +189,11 @@ class PropertyLeaseRenewal(models.Model):
|
||||
else:
|
||||
self.name = False
|
||||
|
||||
class PropertyEarlyQuitting(models.Model):
|
||||
_name = 'property.early.quitting'
|
||||
|
||||
|
||||
class EarlyReceivablesLine(models.Model):
|
||||
_name = 'early.receivables.line'
|
||||
_description = '应收明细'
|
||||
|
||||
renewal_id = fields.Many2one('property.lease.renewal', string='关联续租审批')
|
||||
checkout_id = fields.Many2one('property.tenant.checkout', string='关联退租表', ondelete='cascade')
|
||||
receivable_id = fields.Many2one('property.accounts.receivable', string='应收账单')
|
||||
management_type_id = fields.Many2one(related='receivable_id.management_type_id', string='类型')
|
||||
is_reconciliation = fields.Boolean(string='对账')
|
||||
@@ -534,3 +208,4 @@ class EarlyReceivablesLine(models.Model):
|
||||
for line in self:
|
||||
line.original_amount = line.receivable_id.original_amount - line.receivable_id.discount_amount
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user