Files
gzth/yuthon_property_approval/models/property_lease_contract.py
T
2025-08-27 12:01:23 +08:00

1726 lines
90 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.
import pandas as pd
import calendar
from dateutil.relativedelta import relativedelta
from datetime import datetime, timedelta, date
from odoo.tools.float_utils import float_round
from numpy.ma.core import default_filler
import re
from odoo import models, fields, api, exceptions, _
from odoo.exceptions import UserError, ValidationError
class PropertyContractLine(models.Model):
_name = 'property.contract.line'
_description = '物业合同明细行'
yuthon_property_id = fields.Many2one('yuthon.property', string="关联物业信息")
lease_contract_id = fields.Many2one('property.lease.contract', string="合同编号")
lessee_id = fields.Many2one('property.tenant.information', string='承租方')
rent = fields.Float(string="租金")
start_time = fields.Date(string="生效日期")
end_date = fields.Date(string="失效日期")
class PropertyTenantLine(models.Model):
_name = 'property.tenant.line'
_description = '物业承租方合同明细行'
tenant_id = fields.Many2one('property.tenant.information', string="关联租户信息")
property_ids = fields.Many2many('yuthon.property', string="物业信息")
lease_contract_id = fields.Many2one('property.lease.contract', string="合同编号")
rent = fields.Float(related='lease_contract_id.rent', string="租金")
start_time = fields.Date(related='lease_contract_id.actual_start_time', string="生效日期")
end_date = fields.Date(related='lease_contract_id.actual_end_time',string="失效日期")
@api.model
def create(self, vals):
"""在创建记录时自动关联合同对应的物业"""
if vals.get('lease_contract_id'):
# 获取合同关联的物业明细行并直接提取物业ID列表
contract = self.env['property.lease.contract'].browse(vals['lease_contract_id'])
property_ids = contract.lease_ids.mapped('address_id.id')
if property_ids:
vals['property_ids'] = [(6, 0, property_ids)]
return super(PropertyTenantLine, self).create(vals)
class PropertyLeaseContract(models.Model):
_name = 'property.lease.contract'
_description = '租赁合同审批'
_inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin']
_rec_name = 'contract_code'
property_name = fields.Char(string='物业信息')
code = fields.Char(string="流水号", default=lambda self: self.env['ir.sequence'].next_by_code('property_lease_contract_code'))
admin_id = fields.Many2one('res.users', string="管理员", compute='_compute_admin_id', store=True)
tenure_type = fields.Selection([('self', '自有'), ('agency', '代管')], string='权属类型')
contract_code = fields.Char(string="合同编号")
contract_date = fields.Date(string="合同签订日期")
property_documents_ids = fields.Many2many(
'ir.attachment',
relation='property_lease_contract_documents_rel',
column1='property_lease_contract_id',
column2='attachment_id',
string="租赁合同文件"
)
title_address = fields.Char(string="产权地址")
handling_opinions = fields.Text(string="经办意见")
lessor_id = fields.Many2one('yuthon.property.company', string="出租方公司")
rent_company = fields.Char(related='lessor_id.name', string="收租公司名称")
rent_account = fields.Char(related='lessor_id.rent_account', string="收租公司账号")
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
department_id = fields.Many2one('hr.department', string="部门", store=True, compute='_compute_department_id')
company_id = fields.Many2one(related='users_id.employee_id.company_id', string="公司")
# 承租方的个人信息
lessee_id = fields.Many2one('property.tenant.information', string='承租方')
lessee_name = fields.Char(related='lessee_id.name', string="承租方姓名")
contact = fields.Char(related='lessee_id.contact', string="联系人")
phone = fields.Char(related='lessee_id.phone', string="联系电话")
email = fields.Char(related='lessee_id.email', string="电子邮箱")
card = fields.Char(related='lessee_id.card', string="身份证号")
invoicing_type = fields.Selection([('spot', '专票'), ('cape', '普票')], related='lessee_id.invoicing_type', string="开票类型")
rental_purposes = fields.Many2one('yuthon.rental.purpose', string="出租用途")
invoicing_begins = fields.Char(related='lessee_id.invoicing_begins', string="开票抬头")
tax_number = fields.Char(related='lessee_id.tax_number', string="税号")
industry_id = fields.Many2one(related='lessee_id.industry_id', string="行业")
address_for_delivery = fields.Char(string="送达地址")
precinct_id = fields.Many2one('yuthon.precinct.message', string="所属片区")
active = fields.Boolean('Active', default=True, tracking=True)
lease_term_year = fields.Integer(string="租期(年)")
lease_term_month = fields.Integer(string="租期(月)")
lease_term_day = fields.Integer(string="租期(日)")
is_less_than_2 = fields.Boolean(string="是否小于2年")
term_start_time = fields.Date(string="合约开始时间", default=fields.Datetime.now)
term_end_time = fields.Date(string="合约结束时间")
actual_start_time = fields.Date(string="实际开始时间")
actual_end_time = fields.Date(string="实际结束时间")
end_comparison = fields.Selection([('red', '红'),('yellow', '黄'),('blue', '蓝')], string="结束时间对比(颜色)", compute='_compute_end_comparison', store=True)
expiration_coming = fields.Selection([('coming', '即将到期'), ('due', '已到期')], string="结束时间对比(状态)", compute='_compute_expiration_coming', store=True)
is_equal = fields.Boolean(string="是否相等", compute='_compute_end_comparison', store=True)
cycle_dict = fields.Selection([('monthly', '月度'), ('quarter', '季度'), ('half', '半年'),('year', '年度')],string='付款方式', default='monthly', help="应收")
cycle_mode = fields.Selection([('fixed_monthly', '合同月'), ('floating_monthly', '自然月'), ('fixed_quarter', '合同季'), ('floating_quarter', '自然季'),
('fixed_year', '合同年'), ('floating_year', '自然年')], string='周期方式', default='fixed_monthly')
expected_reminders = fields.Char(string="逾期提醒", default=25)
increment_method = fields.Selection([('percentage', '百分比'),('increment_price', '递增单价'),('increment_amount', '递增金额')], string='每月递增', default='percentage')
increment_percentage = fields.Float(string="递增百分比")
increment_price = fields.Float(string="递增单价")
increment_amount = fields.Float(string="递增金额")
increment_value = fields.Float(string="递增值")
first_years_begin = fields.Integer(string="第几年开始", default=2)
increments_every_few_years = fields.Integer(string="每几年递增")
rent_free_period = fields.Datetime(string="免租期")
rent_free_period_month = fields.Integer(string="免租期")
rent_free_period_days = fields.Integer(string="免租期")
breach = fields.Integer(string="违约计算时点", default=1)
is_split = fields.Boolean(string="是否合同拆分")
def _get_percentage_liquidated_damages(self):
default_rate = self.env['yuthon.penalty.setting'].search(
[('name', '=', 0.001)], limit=1
)
return default_rate.id if default_rate else False
percentage_liquidated_damages = fields.Many2one('yuthon.penalty.setting', string="违约金比例", default=_get_percentage_liquidated_damages)
percentage_damages= fields.Float(string="违约金")
date_of_payment = fields.Selection([('five', '5'), ('fifteen', '15'), ('twenty', '20'), ('twentyfive', '25')], string="支付日期")
first_pay = fields.Date(string="首次付款日")
unit_price = fields.Float(string="单价", store=True, digits=(16, 4))
deposit_type = fields.Selection([('deposit', '押金'), ('performance', '履约保证金')], string="押金/履约保证金")
deposit_status = fields.Selection([('unpaid', '未支付'), ('paid', '已支付'), ('returned','已退'),('no_paid', '没收')], string='押金状态')
deposit = fields.Float(string="押金/履约保证金", store=True)
performance_bonds_write = fields.Char(string="履约保证金大写")
first_year_rent = fields.Float(string="首年租金")
rent = fields.Float(string="租金", help='第一笔合同的应收')
total_contract_receivables = fields.Float(string="合同总应收", compute="_compute_total_contract_receivables")
def _get_default_tax_rate(self):
default_rate = self.env['yuthon.tariff.setting'].search(
[('name', '=', 0.05)], limit=1
)
return default_rate.id if default_rate else False
tax_rate = fields.Many2one('yuthon.tariff.setting', string="税率", default=_get_default_tax_rate)
use_address = fields.Char(string="财务专用地址")
not_tax_amount = fields.Float(string="不含税价")
tax = fields.Float(string="税金")
is_water = fields.Boolean(string="是否有水费", compute='_compute_lease_ids')
is_electricity = fields.Boolean(string="是否有电费", compute='_compute_lease_ids')
is_mange = fields.Boolean(string="是否有管理费")
miscellaneous = fields.Text(string="其他约定")
water_price = fields.Float(string="水费单价")
ele_price = fields.Float(string="电费单价")
number = fields.Integer(string="次数", default=0)
total_area = fields.Float(string="总面积", digits=(16, 4))
not_received = fields.Float(string="未收", compute="_compute_not_received", store=True)
actual_receivable = fields.Float(string="实际应收")
now_receivable = fields.Float(string="当期应收")
total_receivable = fields.Float(string="总已收")
comparison = fields.Selection([('outweigh', '大于'), ('equal', '等于'), ('less', '小于')], string="对比", compute='_compute_comparison')
progress_percentage = fields.Float(string="合同进度", compute="_compute_progress_percentage")
condition = fields.Selection([('new', '新建'), ('approval', '审批中'), ('cancel', '作废'), ('be_executed', '待执行'), ('executed', '已执行'), ('expired', '已终止')], string="状态", default='new')
contract_type = fields.Selection([('lease_renewal', '续租'), ('interim', '临租'), ('new', '补充协议'), ('first', '首租')], string="合同类型", default='first')
contract_id = fields.Many2one('property.lease.contract', string="原合同")
performance_bonds = fields.Float(string="经营履约保证金")
utility_bills = fields.Float(string="水电费押金")
renovation_deposit = fields.Float(string="装修押金")
lease_ids = fields.One2many('property.lease.contract.line', 'lease_id',string="物业信息明细行")
subset_ids = fields.One2many('property.subset.contract', 'subset_id',string="子集明细")
breakdown_ids = fields.One2many('property.rent.breakdown.line', 'breakdown_id', string="物业租金明细行")
water_fee_ids = fields.One2many('property.water.fee.line', 'contract_id', string="物业水费明细行", compute='_compute_lease_ids', store=True)
electricity_fee_ids = fields.One2many('property.electric.fee.line', 'contract_id', string="物业电费明细行", compute='_compute_lease_ids', store=True)
mange_fee_ids = fields.One2many('property.manage.fee.line', 'contract_id', string="物业管理费明细行")
other_ids = fields.One2many('property.other.fee.line', 'other_id', string="其他费用明细行")
rent_list_ids = fields.One2many('property.rent.list', 'contract_id', string="租金明细行")
lease_bank_ids = fields.One2many('property.bank.line', 'contract_id', string="承租方账户明细行")
bank_statements_ids = fields.One2many('property.bank.statements', 'contract_id', string="银行流水明细行")
management_list_ids = fields.One2many('property.management.list', 'contract_id', string="管理费用明细行")
contact_state = fields.Selection([('to', '待执行' ), ('ing', '执行中'), ('terminate', '中止'), ('complete', '完成'), ('early_termination', '提前终止')], string='状态', default='to')
# 附件
license_id = fields.Many2one('ir.attachment', string="营业执照")
legal_entity_id = fields.Many2one('ir.attachment', string="身份证")
power_attorney_id = fields.Many2one('ir.attachment', string="授权委托书")
asset_valuation_id = fields.Many2one('ir.attachment', string="资产评估结果明细表")
lease_contract = fields.Many2one('ir.attachment', string="合同/协议")
confirmation_transaction_id = fields.Many2one('ir.attachment', string="成交确认书")
responsibility_book_id = fields.Many2one('ir.attachment', string="安全生产责任书(住宅)")
other_ment_ids = fields.Many2many(
'ir.attachment',
relation='property_lease_contract_other_rel',
column1='contract_id',
column2='attachment_id',
string="其他"
)
handover_time = fields.Date(string="交接日期")
contract_source_id = fields.Many2one('property.lease.contract', string="合同来源")
is_child_contract = fields.Boolean(string="是否子合同")
is_contract = fields.Boolean(string="是否主合同")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
work_end = fields.Boolean(string="结束")
name = fields.Char(compute='_compute_name', store=True)
license_name = fields.Char(string="营业执照名称", compute='_compute_attachment_names', store=True)
legal_entity_name = fields.Char(string="身份证名称", compute='_compute_attachment_names', store=True)
asset_valuation_name = fields.Char(string="资产评估结果明细表名称", compute='_compute_attachment_names')
lease_contract_name = fields.Char(string="合同/协议", compute='_compute_attachment_names')
confirmation_transaction_name = fields.Char(string="成交确认书名称", compute='_compute_attachment_names',
store=True)
responsibility_book_name = fields.Char(string="安全生产责任书(住宅)名称", compute='_compute_attachment_names',
store=True)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
title_information = fields.Text(string="产权证信息")
contract_count = fields.Integer(string="联系人数量", compute='_compute_contract_count')
reconciliation_count = fields.Integer(string="对账数量", compute='_compute_reconciliation_count')
process_count = fields.Integer(string="流程数量", compute='_compute_process_count')
@api.depends('users_id')
def _compute_department_id(self):
for record in self:
record.department_id = record.users_id.employee_ids.department_id.id
def _compute_contract_count(self):
for record in self:
record.contract_count = self.env['property.accounts.receivable'].search_count([('contract_id', '=', record.id)])
def _compute_reconciliation_count(self):
for record in self:
record.reconciliation_count = self.env['property.bank.statements'].search_count([('contract_id', '=', record.id),
('name_account', '=', record.lessee_id.name)
])
def _compute_process_count(self):
for record in self:
record.process_count = self.env['soong.workflow.record'].search_count([('code', '=', record.code)])
def action_open_contract(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id("yuthon_property_approval.property_accounts_receivable_action")
action.update({'domain': [('contract_id', '=', self.id)]})
return action
def action_open_reconciliation(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id("yuthon_property.view_property_bank_statements_action1")
action.update({'domain': [('contract_id', '=', self.id),
('name_account', '=', self.lessee_id.name)
]
})
return action
def action_open_process(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id("soong_workflow.soong_workflow_other_record_action")
action.update({'domain': [('code', '=', self.code)]})
return action
@api.depends()
def _compute_not_received(self):
not_reconciled_records = self.env['property.accounts.receivable'].search([
('contract_id', '=', self.id),
('is_reconciliation', '=', False)
])
self.not_received = sum(record.submitted for record in not_reconciled_records)
def update_not_received(self):
contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for rec in contract_ids:
not_reconciled_records = self.env['property.accounts.receivable'].search([
('contract_id', '=', rec.id),
('is_reconciliation', '=', False)
])
rec.not_received = sum(record.submitted for record in not_reconciled_records)
def update_admin_id(self):
contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for rec in contract_ids:
if rec.lease_ids:
rec.admin_id = rec.lease_ids[0].admin_line_id.id
@api.depends("lease_ids")
def _compute_lease_ids(self):
for rec in self:
# 初始化值
rec.is_water = False
rec.is_electricity = False
rec.water_fee_ids = [(5, 0, 0)]
rec.electricity_fee_ids = [(5, 0, 0)]
water_fee_values = []
electricity_fee_values = []
if rec.lease_ids:
# 处理每个租赁记录
for lease in rec.lease_ids:
if lease.address_id:
# 处理水表
if lease.address_id.is_meter:
active_water_meters = lease.address_id.water_meter_ids.filtered(
lambda m: not m.demolition_date or m.demolition_date > fields.Date.today()
)
for meter in active_water_meters:
# 确保meter记录有效
if meter.property_meter_water_id:
water_fee_values.append([0, 0, {
'contract_id': rec.id,
'property_meter_water_id': meter.property_meter_water_id.id,
}])
# 处理电表
if lease.address_id.is_electricity_meter:
rec.is_electricity = True
active_electric_meters = lease.address_id.energy_meter_ids.filtered(
lambda m: not m.demolition_date or m.demolition_date > fields.Date.today()
)
for meter in active_electric_meters:
# 确保meter记录有效
if meter.property_meter_archives_id:
electricity_fee_values.append([0, 0, {
'contract_id': rec.id,
'property_meter_archives_id': meter.property_meter_archives_id.id,
}])
rec.is_water = bool(water_fee_values)
rec.is_electricity = bool(electricity_fee_values)
if water_fee_values:
rec.water_fee_ids = water_fee_values
if electricity_fee_values:
rec.electricity_fee_ids = electricity_fee_values
rec.admin_id = rec.lease_ids[0].admin_line_id.id
rec.users_id = rec.lease_ids[0].admin_line_id.id
@api.depends(
'license_id.name',
'legal_entity_id.name',
'asset_valuation_id.name',
'lease_contract.name',
'confirmation_transaction_id.name',
'responsibility_book_id.name'
)
def _compute_attachment_names(self):
"""计算附件名称字段"""
for record in self:
# 营业执照名称
record.license_name = record.license_id.name if record.license_id else ''
# 身份证名称
record.legal_entity_name = record.legal_entity_id.name if record.legal_entity_id else ''
# 资产评估结果明细表名称
record.asset_valuation_name = record.asset_valuation_id.name if record.asset_valuation_id else ''
# 租赁合同(住宅)名称
record.lease_contract_name = record.lease_contract.name if record.lease_contract else ''
# 成交确认书名称
record.confirmation_transaction_name = record.confirmation_transaction_id.name if record.confirmation_transaction_id else ''
# 安全生产责任书(住宅)名称
record.responsibility_book_name = record.responsibility_book_id.name if record.responsibility_book_id else ''
def all_end_approval(self):
contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for contract in contract_ids:
contract.write({'condition': 'be_executed',
'work_end': True})
logs_to_update = self.env["soong.workflow.log"].search([
("model", "=", self._name),
("res_id", "=", contract.id),
])
if logs_to_update:
last_log = logs_to_update[-1]
last_log.write({
"comment": " ",
"approval_state": "3",
"lase_click_date": fields.Datetime.now()
})
def end_approval(self):
self.write({'condition': 'be_executed'})
def open_record(self):
return {
'type': 'ir.actions.act_window',
'res_model': 'property.lease.contract',
'res_id': self.id,
'view_mode': 'form',
}
@api.depends('contract_code', 'name', 'contract_type')
def _compute_name(self):
contract_dict = {
'lease_renewal': '续租',
'interim': '临租',
'new': '补充协议',
'first': '首租'
}
for record in self:
if record.contract_code and record.property_name and record.contract_type:
record.name = f"{record.contract_code}{contract_dict.get(record.contract_type)}{record.property_name}"
elif record.contract_code and record.property_name:
record.name = f"{record.contract_code}{record.property_name}"
elif record.name:
record.name = record.property_name
else:
record.name = self._description
def update_property(self):
contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for contract_id in contract_ids:
for record in contract_id.lease_ids:
record.address_id.write({'property_contract_ids': [(5, 0, 0)]})
contract_list = []
contract_list.append([0, 0,{
'yuthon_property_id': record.address_id.id,
'lease_contract_id': contract_id.id,
'lessee_id': contract_id.lessee_id.id,
'rent': contract_id.rent,
'start_time': contract_id.actual_start_time,
'end_date': contract_id.actual_end_time,
}])
record.address_id.write({'property_contract_ids': contract_list})
@api.onchange('lessee_id')
def _onchange_lessee_id(self):
for record in self:
if record.lessee_id:
lease_bank_ids = self.env['property.bank.line'].search([('tenant_id', '=', record.lessee_id.id)])
record.lease_bank_ids = lease_bank_ids.ids
def set_actual_time_to_contract_time(self):
contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in contract_ids:
if record.term_start_time:
record.actual_start_time = record.term_start_time
if record.term_end_time:
record.actual_end_time = record.term_end_time
@api.depends('not_received', 'now_receivable')
def _compute_comparison(self):
for record in self:
if record.not_received and record.now_receivable:
if record.not_received > record.now_receivable:
record.comparison = 'outweigh'
elif record.not_received < record.now_receivable:
record.comparison = 'less'
else:
record.comparison = 'equal'
else:
record.comparison = None
@api.depends('term_end_time', 'actual_end_time', 'term_start_time')
def _compute_end_comparison(self):
for record in self:
if record.term_end_time and record.actual_end_time and record.term_start_time:
delta = record.term_end_time - record.actual_end_time
if 60<= abs(delta.days) < 90:
record.end_comparison = 'blue'
elif 30<= abs(delta.days) < 60:
record.end_comparison = 'yellow'
elif 30 > abs(delta.days):
record.end_comparison = 'red'
else:
record.end_comparison = None
if record.actual_end_time == record.term_start_time:
record.is_equal = True
else:
record.end_comparison = None
@api.depends('term_end_time', 'actual_end_time')
def _compute_expiration_coming(self):
for record in self:
if record.term_end_time and record.actual_end_time:
if record.actual_end_time < record.term_end_time:
delta = record.term_end_time - record.actual_end_time
if 30< delta.days < 90:
record.expiration_coming = 'coming'
elif delta.days <=30:
record.expiration_coming = 'due'
else:
record.expiration_coming = None
else:
record.expiration_coming = None
else:
record.expiration_coming = None
@api.onchange('total_area', 'rent')
def _onchange_unit_price(self):
for i in self:
if i.total_area and i.rent:
i.unit_price = i.rent / i.total_area
@api.depends('breakdown_ids')
def _compute_total_contract_receivables(self):
for record in self:
record.total_contract_receivables = sum(line.period_rent for line in record.breakdown_ids)
# @api.onchange("term_start_time", "term_end_time",
# "increments_every_few_years", "unit_price",
# "first_years_begin", "increment_method",
# "increment_price", "increment_percentage", "increment_amount",
# "rent_free_period_year", "rent_free_period_month", "total_area")
# def onchange_first_year_rent(self):
# for record in self:
# if record.term_start_time and record.term_end_time:
# start_date = record.term_start_time
# end_date = record.term_end_time + relativedelta(days=1)
# if start_date + relativedelta(months=12) < end_date:
# end_date = start_date + relativedelta(months=12)
# all_period_rent = record.my_compute_all_period_rent(start_date, end_date)
# record.first_year_rent = all_period_rent
# all_start_date = record.term_start_time
# all_end_date = record.term_end_time + relativedelta(days=1)
# record.total_contract_receivables = record.my_compute_all_period_rent(all_start_date, all_end_date)
@api.onchange("lease_term_year", "lease_term_month", "term_start_time" , "lease_term_day")
def onchange_lease_term_year(self):
for record in self:
if record.lease_term_year < 2:
record.is_less_than_2 = True
else:
record.is_less_than_2 = False
if record.lease_term_year or record.lease_term_month:
if not record.lease_term_day:
if record.term_start_time:
year = record.lease_term_year if record.lease_term_year else 0
month = record.lease_term_month if record.lease_term_month else 0
months = year * 12 + month
record.term_end_time = record.term_start_time + relativedelta(months=months) - relativedelta(days=1)
else:
if record.term_start_time:
year = record.lease_term_year if record.lease_term_year else 0
month = record.lease_term_month if record.lease_term_month else 0
months = year * 12 + month
record.term_end_time = record.term_start_time + relativedelta(months=months) - relativedelta(days=1) + relativedelta(days=record.lease_term_day)
@api.onchange("total_contract_receivables", "tax_rate")
def onchange_total_contract_receivables(self):
for record in self:
if record.total_contract_receivables and record.tax_rate:
record.not_tax_amount = record.total_contract_receivables/(1+float(record.tax_rate.name))
record.tax = record.total_contract_receivables - record.not_tax_amount
@staticmethod
def divide_time_range_fixed(start_time, end_time, months):
time_ranges = []
while start_time < end_time:
end_of_range = start_time + relativedelta(months=months)
if end_of_range > end_time:
end_of_range = end_time
time_range = [start_time, end_of_range]
time_ranges.append(time_range)
start_time = end_of_range
return time_ranges
@api.onchange('cycle_dict')
def onchange_cycle_dict(self):
if self.cycle_dict == 'monthly':
self.cycle_mode = 'fixed_monthly'
elif self.cycle_dict == 'quarter':
self.cycle_mode = 'fixed_quarter'
elif self.cycle_dict == 'year':
self.cycle_mode = 'fixed_year'
# @staticmethod
# def divide_time_range_floating(start_time, end_time, months):
# time_ranges = []
# while start_time < end_time:
# start_time = start_time.replace(day=1)
# end_of_range = start_time + relativedelta(months=months)
# time_range = [start_time, end_of_range - relativedelta(days=1)]
# time_ranges.append(time_range)
# start_time = end_of_range
# return time_ranges
# def my_compute_all_period_rent(self, start_date, end_date):
# first_years_begin = self.first_years_begin if self.first_years_begin else 0
# increments_every_few_years = self.increments_every_few_years
# monthly_amount = self.total_area * self.unit_price # 月租金
# unit_price = self.unit_price # 单价
# rent_free_period_month = 0
# # 先计算免租期
# # if self.rent_free_period_year:
# # rent_free_period_month += self.rent_free_period_year * 12
# if self.rent_free_period_month:
# rent_free_period_month += self.rent_free_period_month
# free_start = start_date # 免租期开始
# if rent_free_period_month:
# free_start = start_date + relativedelta(months=rent_free_period_month)
#
# all_period_rent = 0
# if not increments_every_few_years:
# # 计算剩余日期
# delta = relativedelta(end_date, free_start)
# months = delta.years * 12 + delta.months
# all_period_rent += monthly_amount * months
# else:
# # 不递增年份的计算
# increments_start = free_start # 平稳和递增开始
# all_months = 0 # 第几月份
# # 有免递增年份的计算
# if first_years_begin:
# first_index = 0 # 第几递增周期年
# divided_year_segments = self.divide_time_range_fixed(start_date, end_date, 12)
# for segment_year in divided_year_segments:
# first_index += 1
# increments_start = segment_year[1]
# if first_years_begin and first_index >= first_years_begin:
# # 进入 递增时间 跳出平稳计费极端
# break
# delta = relativedelta(segment_year[1], segment_year[0])
# months = delta.years * 12 + delta.months
# for month in range(months):
# all_months += 1
# # 判断是否是免租期
# if all_months > rent_free_period_month:
# all_period_rent += monthly_amount
# # 开始递增
# divided_increments_segments = self.divide_time_range_fixed(increments_start, end_date, increments_every_few_years * 12)
# index = 0 # 第几递增周期年
# for increments_year in divided_increments_segments:
# index += 1
# """
# increment_percentage = fields.Float(string="递增百分比")
# increment_price = fields.Float(string="递增单价")
# increment_amount = fields.Float(string="递增金额")
# """
# increments_month = 0
# if self.increment_method == "increment_price" and self.increment_value:
# unit_price = unit_price + self.increment_value
# monthly_amount = self.total_area * unit_price
# if self.increment_method == "percentage" and self.increment_value:
# monthly_amount = monthly_amount * self.increment_value
# if self.increment_method == "increment_amount" and self.increment_value:
# monthly_amount = monthly_amount + self.increment_value
# delta = relativedelta(increments_year[1], increments_year[0])
# months = delta.years * 12 + delta.months
# # 判断第几月份进入 付费租期
# for month in range(months):
# all_months += 1
# # 判断是否是免租期
# if all_months > rent_free_period_month:
# increments_month += 1
# if increments_month:
# all_period_rent += monthly_amount * increments_month
# return all_period_rent
def action_generate_rental_charges(self):
"""
跳转租金费用弹窗
:return:
"""
return {
'name': '租金费用弹窗',
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'property.rental.wizard',
'target': 'new',
'context': {
'default_lease_contract_id': self.id,
}
}
def action_generate_administrative_expenses(self):
"""
跳转租金费用弹窗
:return:
"""
return {
'name': '租金费用弹窗',
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'property.rental.wizard',
'target': 'new',
'context': {
'default_lease_contract_id': self.id,
}
}
@api.onchange("term_start_time", "term_end_time", "rent",
"increments_every_few_years", "unit_price",
"first_years_begin", "increment_method", "increment_value",
"rent_free_period_month", "rent_free_period_days", "total_area")
def _onchange_action_generate_details(self):
"""
生产租金明细
:return:
"""
# todo 还没有计算递增递减
# todo 还没有计算首月优惠
# todo 还没有计算开始和结束不足月份和季度的计算比例
for record in self:
if record.term_start_time and record.term_end_time:
record.write({'breakdown_ids': [(5, 0, 0)]})
start_date = record.term_start_time
end_date = record.term_end_time + relativedelta(days=1)
record.do_generate_details_core(start_date, end_date, True)
# 计算首年租金
first_year_end_date = start_date + relativedelta(months=12)
if first_year_end_date > end_date:
first_year_end_date = end_date
all_period_rent = record.do_generate_details_core(start_date, first_year_end_date, False)
record.first_year_rent = all_period_rent
def all_action_generate_details(self):
property_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in property_ids:
if record.term_start_time and record.term_end_time:
record.write({'breakdown_ids': [(5, 0, 0)]})
start_date = record.term_start_time
end_date = record.term_end_time + relativedelta(days=1)
record.do_generate_details_core(start_date, end_date, True)
# 计算首年租金
first_year_end_date = start_date + relativedelta(months=12)
if first_year_end_date > end_date:
first_year_end_date = end_date
all_period_rent = record.do_generate_details_core(start_date, first_year_end_date, False)
record.first_year_rent = all_period_rent
def do_generate_details_core(self, start_date, end_date, write_db=False):
all_period_rent = 0
unit_price = self.unit_price # 单价
unit_price = float_round(unit_price, precision_digits=2, rounding_method='HALF-UP')
monthly_amount = self.rent
monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
# 如果有免租期 月 时间进行到 start_date
free_start_dict = {}
free_start = start_date
if self.rent_free_period_month:
free_start = start_date + relativedelta(months=self.rent_free_period_month)
if free_start > end_date:
free_start = end_date
delta = relativedelta(free_start, start_date)
month_number = delta.years * 12 + delta.months
if delta.days:
month_number += 1
free_start_dict = {
"unit_price": unit_price,
"monthly_amount": monthly_amount,
"breakdown_id": self.id,
"start_data": start_date,
"end_data": free_start - relativedelta(days=1),
"month_number": month_number,
"period_rent": 0,
}
free_day_start = free_start
add_year_index = 0 # 第几年
year_month_index = 0 # 第几个月
free_start_day_dict = {}
monthly_amount_last_dict = {}
monthly_amount_new_dict = {}
# 说明存在免增期 单独计算
if start_date < end_date:
one_years_list = self.divide_time_range_fixed(start_date, end_date, 12)
for one_year in one_years_list:
add_year_index += 1
# 是否存在免增期
first_years_begin = self.first_years_begin if self.first_years_begin else 0
# 存在递增期 并且进入递增金额计算
if self.increments_every_few_years > 0 and add_year_index >= first_years_begin:
if add_year_index % self.increments_every_few_years == 0:
# 单价和金额计算
if self.increment_method == "increment_price" and self.increment_value:
unit_price = unit_price + self.increment_value
unit_price = float_round(unit_price, precision_digits=2, rounding_method='HALF-UP')
monthly_amount = self.total_area * unit_price
monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
if self.increment_method == "percentage" and self.increment_value:
unit_price = unit_price * (1 + (self.increment_value / 100))
unit_price = float_round(unit_price, precision_digits=2, rounding_method='HALF-UP')
monthly_amount = self.total_area * unit_price
monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
if self.increment_method == "increment_amount" and self.increment_value:
monthly_amount = monthly_amount + self.increment_value
monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
unit_price = monthly_amount / self.total_area
unit_price = float_round(unit_price, precision_digits=2, rounding_method='HALF-UP')
# 开始时间, 结束时间
one_year_start = one_year[0]
one_year_end = one_year[1]
one_month_list = self.divide_time_range_fixed(one_year_start, one_year_end, 1)
for one_month in one_month_list:
period_rent = round(monthly_amount)
# 所有月统计
year_month_index += 1
# 如果开始时间 是 免租期月的结束时间,那么进入免租期日
if one_month[0] == free_start:
# 如果免租期有天那么默认增加一个月
if self.rent_free_period_days:
# 免租日的截至日期
free_day_start = one_month[1]
# 计算这个月的天数
total_days = (one_month[1] - one_month[0]).days
current_no_free = (total_days - self.rent_free_period_days) / total_days
period_rent = round(monthly_amount * current_no_free) if monthly_amount * current_no_free > 0 else 0
# 计算 免租期天的比值
free_start_day_dict = {
"unit_price": unit_price,
"monthly_amount": monthly_amount,
"breakdown_id": self.id,
"start_data": one_month[0],
"end_data": one_month[1] - relativedelta(days=1),
"month_number": 1,
"period_rent": period_rent,
}
all_period_rent += period_rent
# 已经跳出 免租期了 开始计费
if one_month[0] >= free_day_start:
current_days = calendar.monthrange(one_month[0].year, one_month[0].month)[1]
total_days = (one_month[1] - one_month[0]).days
# 说明不足月 单独计算
if current_days > total_days:
current_no_free = total_days / current_days
period_rent = round(monthly_amount * current_no_free) if monthly_amount * current_no_free > 0 else 0
monthly_amount_last_dict = {
"unit_price": unit_price,
"monthly_amount": monthly_amount,
"breakdown_id": self.id,
"start_data": one_month[0],
"end_data": one_month[1] - relativedelta(days=1),
"month_number": 1,
"period_rent": period_rent,
}
# 足月的单独进行计算
else:
if str(monthly_amount) in monthly_amount_new_dict:
amount_dict = monthly_amount_new_dict.get(str(monthly_amount))
old_period_rent = amount_dict.get("period_rent")
old_start_data = amount_dict.get("start_data")
old_end_data = amount_dict.get("end_data")
start_data = min(old_start_data, one_month[0])
end_data = max(old_end_data, one_month[1])
delta = relativedelta(end_data, start_data)
month_number = delta.years * 12 + delta.months
if delta.days:
month_number += 1
monthly_amount_new_dict[str(monthly_amount)] = {
"unit_price": unit_price,
"monthly_amount": monthly_amount,
"breakdown_id": self.id,
"start_data": start_data,
"end_data": end_data - relativedelta(days=1),
"month_number": month_number,
"period_rent": old_period_rent + period_rent,
}
else:
monthly_amount_new_dict[str(monthly_amount)] = {
"unit_price": unit_price,
"monthly_amount": monthly_amount,
"breakdown_id": self.id,
"start_data": one_month[0],
"end_data": one_month[1] - relativedelta(days=1),
"month_number": 1,
"period_rent": period_rent,
}
all_period_rent += period_rent
if write_db:
# 是否免租期 月
if free_start_dict:
self.sudo().write({'breakdown_ids': [(0, 0, free_start_dict)]})
# 是否免租期 日
if free_start_day_dict:
self.sudo().write({'breakdown_ids': [(0, 0, free_start_day_dict)]})
# 开始统计月份阶段金额
for k, v in monthly_amount_new_dict.items():
self.sudo().write({'breakdown_ids': [(0, 0, v)]})
# 最后有不足月的单独计算
if monthly_amount_last_dict:
self.sudo().write({'breakdown_ids': [(0, 0, monthly_amount_last_dict)]})
return all_period_rent
# def do_generate_details_core_1(self, start_date, end_date):
# """
# 计算核心算法
# :return:
# """
# all_period_rent = 0 # 总金额
# monthly_amount = self.total_area * self.unit_price
# monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
# # 月租金
# unit_price = self.unit_price # 单价
#
# # 如果有免租期 月 时间进行到 start_date
# free_start = start_date
# if self.rent_free_period_month:
# free_start = start_date + relativedelta(months=self.rent_free_period_month)
# if free_start > end_date:
# free_start = end_date
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": start_date,
# "end_data": free_start - relativedelta(days=1),
# "month_number": self.rent_free_period_month,
# "period_rent": 0,
# })]})
#
# # 如果没有递增 那么计算全部
# if not self.increments_every_few_years:
# # 如果免租期有天那么默认增加一个月
# # 如果有免增期 日
# free_start_day = free_start
# if self.rent_free_period_days:
# free_start_day = free_start + relativedelta(months=self.rent_free_period_days)
# if free_start_day < end_date:
# # 计算这个月的天数
# current_days = calendar.monthrange(free_start.year, free_start.month)[1]
# current_no_free = (current_days - self.rent_free_period_days) / current_days
# period_rent = monthly_amount * 1 * current_no_free if monthly_amount * 1 * current_no_free > 0 else 0
# # 计算 免租期天的比值
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": free_start,
# "end_data": free_start_day - relativedelta(days=1),
# "month_number": 1,
# "period_rent": period_rent,
# })]})
# all_period_rent += period_rent
#
# # 计算 剩余日期的金额
# if free_start_day < end_date:
# delta = relativedelta(end_date, free_start_day)
# months = delta.years * 12 + delta.months
# free_start_day_end = free_start_day + relativedelta(months=months)
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": free_start_day,
# "end_data": free_start_day_end - relativedelta(days=1),
# "month_number": months,
# "period_rent": monthly_amount * months,
# })]})
# all_period_rent += monthly_amount * months
# # 说明最后还有几天
# if delta.days > 0:
# current_days = calendar.monthrange(free_start_day_end.year, free_start_day_end.month)[1]
# current_no_free = delta.days / current_days
# period_rent = monthly_amount * 1 * current_no_free if monthly_amount * 1 * current_no_free > 0 else 0
# # 计算 免租期天的比值
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": free_start_day_end,
# "end_data": end_date,
# "month_number": 1,
# "period_rent": period_rent,
# })]})
#
# # 如果有递增
# else:
# first_years_begin_end = start_date
# # 免递增年份计算
# if self.first_years_begin > 1:
# # 免递增结束时间
# first_years_begin_end = start_date + relativedelta(months=(self.first_years_begin -1) * 12)
# # 免租期结束时间 free_start
# # 计算免租期和免增期的差值, 如果免租期超过免增期那么不存在免增期
# if first_years_begin_end > free_start:
# # 如果免租期有天那么默认增加一个月
# if self.rent_free_period_days:
# # 计算这个月的天数
# current_days = calendar.monthrange(free_start.year, free_start.month)[1]
# current_no_free = (current_days - self.rent_free_period_days) / current_days
# # 计算 免租期天的比值
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": free_start,
# "end_data": free_start + relativedelta(months=1) - relativedelta(days=1),
# "month_number": 1,
# "period_rent": monthly_amount * 1 * current_no_free if monthly_amount * 1 * current_no_free > 0 else 0,
# })]})
# new_free_day_amount = monthly_amount * 1 * current_no_free if monthly_amount * 1 * current_no_free > 0 else 0
# all_period_rent += new_free_day_amount
# # 免租期后退一个月
# free_start = free_start + relativedelta(months=1)
# # 计算剩下的免增期
# delta = relativedelta(first_years_begin_end, free_start)
# first_months = delta.years * 12 + delta.months
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": free_start,
# "end_data": first_years_begin_end - relativedelta(days=1),
# "month_number": first_months,
# "period_rent": first_months * monthly_amount,
# })]})
# all_period_rent += first_months * monthly_amount
# # 免增期结束开始递增
# divided_increments_segments = self.divide_time_range_fixed(first_years_begin_end, end_date, increments_every_few_years*12)
# year_index = 0 # 第几递增周期年
# all_months = 0 # 递增的第几个月
# # 如果免租期 超过 免增期 那么递增期也需要排除
# if first_years_begin_end < free_start:
# delta = relativedelta(free_start, first_years_begin_end)
# free_first_months = delta.years * 12 + delta.months
# # 如果免租期有天那么默认增加一个月
# if self.rent_free_period_days:
# free_first_months = free_first_months + 1
# else:
# free_first_months = 0
#
# for increments_year in divided_increments_segments:
# year_index += 1
# """
# increment_percentage = fields.Float(string="递增百分比")
# increment_price = fields.Float(string="递增单价")
# increment_amount = fields.Float(string="递增金额")
# """
# increments_month = 0
# # delta = relativedelta(increments_year[1], increments_year[0])
# # months = delta.years * 12 + delta.months
# if self.increment_method == "increment_price" and self.increment_value:
# unit_price = unit_price + self.increment_value
# monthly_amount = self.total_area * unit_price
# monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
# if self.increment_method == "percentage" and self.increment_value:
# unit_price = unit_price * (1 + (self.increment_value / 100))
# monthly_amount = self.total_area * unit_price
# monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
# if self.increment_method == "increment_amount" and self.increment_value:
# monthly_amount = monthly_amount + self.increment_value
# monthly_amount = float_round(monthly_amount, precision_digits=0, rounding_method='HALF-UP') # 月租金
# unit_price = monthly_amount / self.total_area
#
# delta = relativedelta(increments_year[1], increments_year[0])
# months = delta.years * 12 + delta.months
# month_index = 0
# # 判断第几月份进入 付费租期
# for month in range(months):
# month_index += 1 # 当前第个月
# # 判断第几月份进入 付费租期
# all_months += 1
# if all_months == free_first_months:
# # 如果免租期有天那么默认增加一个月
# if self.rent_free_period_days:
# current_now = increments_year[0] + relativedelta(months=month_index)
# # 计算这个月的天数
# current_days = calendar.monthrange(current_now.year, current_now.month)[1]
# current_no_free = (current_days - self.rent_free_period_days) / current_days
# # 计算 免租期天的比值
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": current_now,
# "end_data": current_now + relativedelta(months=1) - relativedelta(days=1),
# "month_number": 1,
# "period_rent": monthly_amount * 1 * current_no_free if monthly_amount * 1 * current_no_free > 0 else 0,
# })]})
# new_free_day_amount = monthly_amount * 1 * current_no_free if monthly_amount * 1 * current_no_free > 0 else 0
# all_period_rent += new_free_day_amount
# # 判断是否是免租期
# if all_months > free_first_months:
# increments_month += 1
# if increments_month:
# self.sudo().write({'breakdown_ids': [(0, 0, {
# "unit_price": unit_price,
# "monthly_amount": monthly_amount,
# "breakdown_id": self.id,
# "start_data": increments_year[1] - relativedelta(months=increments_month),
# "end_data": increments_year[1] - relativedelta(days=1),
# "month_number": increments_month,
# "period_rent": monthly_amount * increments_month,
# })]})
# all_period_rent += monthly_amount * increments_month
# return all_period_rent
# @api.onchange("first_year_rent")
# def _onchange_first_year_rent(self):
# for rec in self:
# rec.performance_bonds = rec.first_year_rent * 2
# @api.onchange("total_area", "unit_price")
# def _onchange_deposit(self):
# for record in self:
# record.deposit = record.total_area * record.unit_price * 2 # 月租金
@api.onchange('rent')
def _onchange_deposit(self):
for record in self:
if record.rent:
record.deposit = record.rent * 2
else:
record.deposit = 0.0
def update_lease_ids(self):
property_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for rec in property_ids:
lease_name = []
electricity_list = []
water_list = []
title_address = []
fee_list = []
for record in rec.lease_ids:
if record.address_id and record.address_id.title_address:
lease_name.append(record.address_id.name)
title_address.append(record.address_id.title_address.name)
rec.name = ','.join(lease_name)
rec.use_address = ','.join(lease_name)
rec.title_address = ','.join(title_address)
property_id = self.env['yuthon.property'].search([('id', '=', record.address_id.id)])
if property_id.energy_meter_ids:
rec.is_electricity = True
for electricity_id in property_id.energy_meter_ids:
electricity_list.append([0, 0, {
'fees_id': electricity_id.standard_id.id,
'proportional': electricity_id.rate,
}])
else:
rec.is_electricity = False
if property_id.water_meter_ids:
rec.is_water = True
for water_id in property_id.water_meter_ids:
water_list.append([0, 0, {
'fees_id': water_id.standard_id.id,
'proportional': water_id.rate,
}])
else:
rec.is_water = False
if property_id.is_message_fee:
rec.is_mange = True
standard_id = property_id.message_standard_id
fee_list.append([0, 0, {
'fees_id': standard_id.id,
'proportional': standard_id.amount}])
else:
rec.is_mange = False
rec.electricity_fee_ids = [(5, 0, 0)]
rec.mange_fee_ids = [(5, 0, 0)]
rec.admin_id = rec.lease_ids[0].admin_line_id.id if rec.lease_ids else ''
rec.tenure_type = rec.lease_ids[0].address_id.tenure_type if rec.lease_ids else ''
rec.lessor_id = rec.lease_ids[0].address_id.company_id.id if rec.lease_ids else ''
rec.precinct_id = rec.lease_ids[0].address_id.precinct_id.id if rec.lease_ids else ''
rec.total_area = sum([lease.property_area for lease in rec.lease_ids])
rec.electricity_fee_ids = electricity_list
rec.mange_fee_ids = fee_list
def trigger_lease_ids(self):
property_ids = self.env["property.lease.contract"].browse(self._context.get('active_ids', self._context.get('active_id')))
for record in property_ids:
lessor_id = record.lease_ids[-1].address_id.company_id.id if record.lease_ids else ''
admin_id = record.lease_ids[-1].admin_line_id.id if record.lease_ids else ''
tenure_type = record.lease_ids[-1].address_id.tenure_type if record.lease_ids else ''
record.sudo().write({'lessor_id': lessor_id,
'admin_id': admin_id,
'tenure_type':tenure_type,
'precinct_id': record.lease_ids[0].address_id.precinct_id.id if record.lease_ids else '',})
def action_yuthon_property_contract_wizard(self):
return {
"type": "ir.actions.act_window",
"name": "批量导入物业合同",
"res_model": "property.contract.wizard",
"view_mode": "form",
"target": "new",
}
def action_relevance_property(self):
contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id'))
)
contract_dict = {
'lease_renewal': '续租',
'interim': '临租',
'new': '补充协议',
'first': '首租'
}
for record in contract_ids:
if record.contract_code and record.property_name and record.contract_type:
record.name = f"{record.contract_code}{contract_dict.get(record.contract_type)}{record.property_name}"
elif record.contract_code and record.property_name:
record.name = f"{record.contract_code}{record.property_name}"
elif record.name:
record.name = record.property_name
else:
record.name = self._description
lease_name = []
if record.lease_ids:
for lease in record.lease_ids:
if lease.address_id and lease.address_id.name:
lease_name.append(str(lease.address_id.name))
record.write({
'property_name': ','.join(lease_name) if lease_name else ''
})
def action_update_contract(self):
contract_ids = self.env["property.lease.contract"].browse(self._context.get('active_ids', self._context.get('active_id')))
for record in contract_ids:
record._compute_department_id()
@api.constrains("contract_code")
def _check_contract_code(self):
"""检查合同编号的唯一性(不区分中英文括号)"""
if self.env.context.get('skip_contract_code_check'):
return
for record in self:
normalized_code = self._normalize_contract_code(record.contract_code)
existing_records = self.search([
('id', '!=', record.id),
('contract_code', '!=', False),
])
for existing in existing_records:
if self._normalize_contract_code(existing.contract_code) == normalized_code:
raise ValidationError(_(
f"合同编号必须唯一!已存在编号:{existing.contract_code}",
))
def _normalize_contract_code(self, code):
"""将合同编号中的括号统一为中文括号"""
if not code:
return code
# 替换中英文括号为统一格式
code = re.sub(r'[(]', '(', code) # 替换左括号
code = re.sub(r'[)]', ')', code) # 替换右括号
return code
def action_copy_record1(self):
lease_contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in lease_contract_ids:
if len(lease_contract_ids) > 1:
raise UserError("只能选择一个拆分")
record.is_contract = True
record.is_child_contract = False
record.is_split = True
record.number += 1
contract_id = self.env['property.lease.contract'].create({
'property_name': record.property_name,
'is_child_contract': True,
'is_contract': False,
'contract_source_id': record.id,
'actual_start_time': record.actual_start_time,
'actual_end_time': record.actual_end_time,
'contract_code': record.contract_code+ f'-{record.number}',
'contract_date': record.contract_date,
'lessee_id': record.lessee_id.id,
'use_address': record.use_address,
'condition':'new',
'admin_id': record.admin_id.id,
'lessor_id':record.lessor_id.id,
'rental_purposes': record.rental_purposes.id,
'address_for_delivery': record.address_for_delivery,
# 'lease_term': record.lease_term,
'lease_term_year': record.lease_term_year,
'lease_term_month': record.lease_term_month,
'term_end_time': record.term_end_time,
'cycle_dict': record.cycle_dict,
'cycle_mode': record.cycle_mode,
'increment_method': record.increment_method,
# 'increment_percentage': record.increment_percentage,
# 'increment_price': record.increment_price,
# 'increment_amount': record.increment_amount,
'increment_value': record.increment_value,
'first_years_begin': record.first_years_begin,
'increments_every_few_years': record.increments_every_few_years,
'rent_free_period': record.rent_free_period,
'rent_free_period_month': record.rent_free_period_month,
'rent_free_period_days': record.rent_free_period_days,
'breach': record.breach,
'percentage_liquidated_damages': record.percentage_liquidated_damages.id,
'first_pay': record.first_pay,
'unit_price': record.unit_price,
'deposit_type': record.deposit_type,
'performance_bonds_write': record.performance_bonds_write,
'first_year_rent': record.first_year_rent,
'deposit': record.deposit,
'rent': record.rent,
'total_contract_receivables': record.total_contract_receivables,
'tax_rate': record.tax_rate.id,
'not_tax_amount': record.not_tax_amount,
'tax': record.tax,
'is_water': record.is_water,
'is_electricity': record.is_electricity,
'is_mange': record.is_mange,
'miscellaneous': record.miscellaneous,
'total_area': record.total_area,
'contract_type': record.contract_type,
})
lease_list = []
for lease_id in record.lease_ids:
lease_list.append([0, 0, {
'lease_id':contract_id.id,
'address_id':lease_id.address_id.id,
'evaluate_unit_price': lease_id.evaluate_unit_price,
}])
breakdown_list = []
if record.breakdown_ids:
for breakdown_id in record.breakdown_ids:
breakdown_list.append([0, 0, {
'breakdown_id':contract_id.id,
'charges': breakdown_id.charges,
'unit_price': breakdown_id.unit_price,
'monthly_amount': breakdown_id.monthly_amount,
'start_data': breakdown_id.start_data,
'end_data': breakdown_id.end_data,
'month_number': breakdown_id.month_number,
'period_rent': breakdown_id.period_rent,
}])
water_fee_list = []
if record.water_fee_ids:
for water_fee_id in record.water_fee_ids:
water_fee_list.append([0, 0, {
'contract_id':contract_id.id,
'address_id':water_fee_id.address_id.id,
'charges': water_fee_id.charges,
'fees_id': water_fee_id.fees_id.id,
'proportional': water_fee_id.proportional,
}])
electricity_fee_list = []
if record.electricity_fee_ids:
for electricity_fee_id in record.electricity_fee_ids:
electricity_fee_list.append([0, 0, {
'contract_id':contract_id.id,
'charges': electricity_fee_id.charges,
'fees_id': electricity_fee_id.fees_id.id,
'proportional': electricity_fee_id.proportional,
}])
mange_fee_list = []
if record.mange_fee_ids:
for mange_fee_id in record.mange_fee_ids:
mange_fee_list.append([0, 0, {
'contract_id': contract_id.id,
'charges': mange_fee_id.charges,
'fees_id': mange_fee_id.fees_id.id,
'proportional': mange_fee_id.proportional,
}])
other_list = []
if record.other_ids:
for other_id in record.other_ids:
other_list.append([0, 0, {
'other_id': contract_id.id,
'charges': other_id.charges,
'coping': other_id.coping.id,
'coping_time': other_id.coping_time,
}])
rent_list = []
if record.rent_list_ids:
for rent in record.rent_list_ids:
rent_list.append([0, 0, {
'contract_id': contract_id.id,
}])
# management_list = []
# if record.management_list_ids:
# for record in record.management_list_ids:
# management_list.append([0, 0, {
# 'contract_id': contract_id.id,
# }])
subset_list = []
subset_list.append([0, 0, {
'subset_id': record.id,
'contract_id': contract_id.id}])
record.subset_ids = subset_list
contract_id.write({
'lease_ids': lease_list,
'breakdown_ids': breakdown_list,
'water_fee_ids': water_fee_list,
'electricity_fee_ids': electricity_fee_list,
'mange_fee_ids': mange_fee_list,
'other_ids': other_list,
'rent_list_ids': rent_list,})
# 'management_list_ids':management_list,})
def disposable_button(self):
property_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for record in property_ids:
admin_id = record.admin_id
if admin_id:
record.write({
'users_id': admin_id.id,
'company_id' : admin_id.employee_id.company_id.id,
})
def choose_property_button(self):
address_ids = self.lease_ids.mapped('address_id').filtered(lambda r: r)
property_ids2 = address_ids.ids
return {
"type": "ir.actions.act_window",
"name": "批量选择物业信息",
"res_model": "choose.property.wizard",
"view_mode": "form",
"target": "new",
"context": {
'default_lease_contract_id': self.id,
'default_property_ids2': property_ids2,
}
}
@api.depends('term_start_time', 'term_end_time')
def _compute_progress_percentage(self):
for record in self:
if record.term_start_time and record.term_end_time:
# 将字段值从 Date 类型转换为 datetime 类型(默认为 00:00:00 时间)
start_time = fields.Date.from_string(record.term_start_time)
end_time = fields.Date.from_string(record.term_end_time)
current_time = fields.Date.today()
total_duration = (end_time - start_time).days
elapsed_time = (current_time - start_time).days
if current_time < start_time:
record.progress_percentage = 0
# 如果总天数差不为零,则计算进度百分比
elif total_duration > 0:
record.progress_percentage = (elapsed_time / total_duration) * 100
else:
record.progress_percentage = 0
else:
record.progress_percentage = 0
@api.onchange("name")
def _onchange_name(self):
if self.property_name:
self.address_for_delivery = self.property_name
self.use_address = self.property_name
@api.depends("lease_ids")
def _compute_admin_id(self):
for record in self:
if record.lease_ids:
record.admin_id = record.lease_ids[0].admin_line_id.id
@api.onchange("admin_id")
def _onchange_admin_id(self):
if self.admin_id:
self.users_id = self.admin_id.user_id.id
def get_property_contract_time(self):
records_only_in_tree1 = self.env['property.lease.contract'].search([
('condition', 'not in', ['new', 'approval', 'cancel'])
])
today = fields.Date.today()
for contract in records_only_in_tree1:
# 获取时间字段
actual_start = contract.actual_start_time
actual_end = contract.actual_end_time
term_end = contract.term_end_time
effective_month = None
if actual_end:
# 获取实际结束日期所在月的最后一天
last_day_of_month = calendar.monthrange(actual_end.year, actual_end.month)[1]
if actual_end.day == last_day_of_month:
# 如果是最后一天,生效月份为下月
effective_month = fields.Date.to_date(f"{actual_end.year}-{actual_end.month}-{last_day_of_month}")
else:
# 如果不是最后一天,生效月份为当月
effective_month = fields.Date.to_date(f"{actual_end.year}-{actual_end.month}-01")
# 根据时间条件更新状态
if not actual_start or today < actual_start:
# 待执行:实际开始时间未到或未设置
contract.contact_state = 'to'
elif actual_start and (not actual_end or today < actual_end):
# 执行中:已开始且未结束(或结束时间未设置)
contract.contact_state = 'ing'
elif today >= actual_end == term_end:
contract.contact_state = 'complete'
elif effective_month and today >= effective_month < term_end:
contract.contact_state = 'terminate'
# 续租
def button_lease_extension(self):
lease_contract_ids = self.env["property.lease.contract"].browse(
self._context.get('active_ids', self._context.get('active_id')))
if len(lease_contract_ids) > 1:
raise UserError("只能单个操作合同续租")
for original_contract in lease_contract_ids:
new_contract = original_contract.with_context(skip_contract_code_check=True).copy()
new_term_start = original_contract.term_end_time + timedelta(
days=1) if original_contract.term_end_time else False
new_contract.write({
'admin_id': original_contract.admin_id,
'contract_code': None,
'lease_term_year': None,
'term_start_time': new_term_start,
'term_end_time': None,
'condition':'new',
'contract_id': original_contract.id,
'contract_type': 'lease_renewal'
})
water_lines = self.env['property.water.fee.line'].search([
('contract_id', '=', original_contract.id)
])
for line in water_lines:
line.copy({'contract_id': new_contract.id})
# 复制电费明细行
electric_lines = self.env['property.electric.fee.line'].search([
('contract_id', '=', original_contract.id)
])
for line in electric_lines:
line.copy({'contract_id': new_contract.id})
# 复制物业管理费明细行
manage_lines = self.env['property.manage.fee.line'].search([
('contract_id', '=', original_contract.id)
])
for line in manage_lines:
line.copy({'contract_id': new_contract.id})
# 复制其他费用明细行
other_lines = self.env['property.other.fee.line'].search([
('other_id', '=', original_contract.id)
])
for line in other_lines:
line.copy({'other_id': new_contract.id})
# 复制子合同明细
subset_lines = self.env['property.subset.contract'].search([
('subset_id', '=', original_contract.id)
])
for line in subset_lines:
line.copy({'subset_id': new_contract.id})
lease_lines = self.env['property.lease.contract.line'].search([
('lease_id', '=', original_contract.id)
])
for line in lease_lines:
line.copy({'lease_id': new_contract.id})
new_contract._compute_name()
return {
'type': 'ir.actions.act_window',
'name': '续期合同',
'res_model': 'property.lease.contract',
'view_mode': 'form',
'res_id': new_contract.id, # 指定新合同的ID
'target': 'current',
}
# 变更
def button_lease_change(self):
form_id = self.env.ref('yuthon_property_approval.view_property_lease_renewal_form').id
return {
'name': '变更申请',
"type": "ir.actions.act_window",
'view_mode': 'form',
'res_model': 'property.lease.renewal',
"views": [[form_id, "form"]],
"context": {
'default_renewal_type': 'lease',
'default_contract_id': self.id,
},
}
def read_coming_count(self):
return self.search_count([('expiration_coming', '=', 'coming'), ('admin_id', '=', self.env.user.id)])
def read_due_count(self):
return self.search_count([('expiration_coming', '=', 'due'), ('admin_id', '=', self.env.user.id)])
def put_evaluation_plan(self):
for record in self:
property_ids = []
rent_area = 0
first_address_id = record.lease_ids[0].admin_line_id if record.lease_ids else None
for lease_id in record.lease_ids:
property_ids.append(lease_id.address_id.id)
rent_area += lease_id.address_id.rent_area
self.env['property.evaluation.plan'].create({
'property_name': record.property_name,
'property_ids': [(6, 0, property_ids)],
'evaluation_area': rent_area,
'owner_id': first_address_id.title_information_ids[0].owner_id.id if first_address_id and first_address_id.title_information_ids else None,
'registered_id': first_address_id.title_information_ids[0].registered_id.id if first_address_id and first_address_id.title_information_ids else None,
'rent_id': first_address_id.reference_ids[0].rent_id.id if first_address_id and first_address_id.reference_ids else None,
'lease_period': first_address_id.reference_ids[0].lease_period if first_address_id and first_address_id.reference_ids else None,
'annual_increase_percentage': first_address_id.reference_ids[0].annual_increase_percentage if first_address_id and first_address_id.reference_ids else None,
'remake': first_address_id.remark if first_address_id else None,
'assessment_category': 'rent_money',
})
record.write({'contact_state': 'ing'})
return {
"name": "物业评估方案",
'type': 'ir.actions.act_window',
'res_model': 'property.evaluation.plan',
"view_mode": "tree",
}
def all_put_evaluation_plan(self):
contract_ids = self.env["property.lease.contract"].browse(self._context.get('active_ids', self._context.get('active_id')))
for record in contract_ids:
property_ids = []
property_id = record.lease_ids[0].admin_line_id
if record.contact_state == 'done':
raise UserError(f'{record.property_name}该物业已评估,请勿重复评估')
rent_area = 0
for lease_id in record.lease_ids:
property_ids.append(lease_id.address_id.id)
rent_area += lease_id.address_id.rent_area
self.env['property.evaluation.plan'].create({
'property_name': record.property_name,
'property_ids': property_ids,
'evaluation_area': property_id.rent_area,
'owner_id': property_id.title_information_ids[0].owner_id.id if property_id.title_information_ids else None,
'registered_id': property_id.title_information_ids[0].registered_id.id if property_id.title_information_ids else None,
'rent_id': property_id.reference_ids[0].rent_id.id if property_id.reference_ids else None,
'lease_period': property_id.reference_ids[0].lease_period if property_id.reference_ids else None,
'annual_increase_percentage': property_id.reference_ids[0].annual_increase_percentage if property_id.reference_ids else None,
'remake': property_id.remark,
'assessment_category': 'rent_money',
})
record.write({'contact_state': 'ing'})
return {
"name": "物业评估方案",
'type': 'ir.actions.act_window',
'res_model': 'property.evaluation.plan',
"view_mode": "tree",
}
class PropertyLeaseContractLine(models.Model):
_name = 'property.lease.contract.line'
_description = '物业列表明细行'
lease_id = fields.Many2one('property.lease.contract', string="关联凭租合同审批")
address_id = fields.Many2one('yuthon.property', string="物业地址")
admin_line_id = fields.Many2one(related='address_id.admin_id', string="管理员")
property_area = fields.Float(related='address_id.management_area', string="面积")
message_standard_id = fields.Many2one(related='address_id.message_standard_id', string="管理费标准")
evaluate_unit_price = fields.Float(string="评估单价")
class PropertyRentBreakdownLine(models.Model):
_name = 'property.rent.breakdown.line'
_description = '物业租金明细行'
breakdown_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批")
charges = fields.Char(string="收费项")
unit_price = fields.Float(string="单价")
monthly_amount = fields.Float(string="月租金", digits=(16, 2))
start_data = fields.Date(string="开始日期")
end_data = fields.Date(string="结束日期")
month_number = fields.Integer(string="期间月数")
period_rent = fields.Float(string="期间租金", digits=(16, 2))
@api.onchange('monthly_amount')
def _onchange_monthly_amount(self):
self.period_rent = self.monthly_amount * self.month_number
class PropertyWaterFeeLine(models.Model):
_name = 'property.water.fee.line'
_description = '物业水费明细行'
contract_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批")
property_meter_water_id = fields.Many2one('property.meter.water', string="水表库")
rate = fields.Integer(related='property_meter_water_id.gauge_magnification', string="倍率", store=True)
standard_id = fields.Many2one(related='property_meter_water_id.standards_id', string="标准", store=True)
installation_date = fields.Date(related='property_meter_water_id.start_time', string="安装日期")
demolition_date = fields.Date(related='property_meter_water_id.end_time', string="拆除日期")
location = fields.Char(related='property_meter_water_id.installation_location', string="位置")
class PropertyElectricFeeLine(models.Model):
_name = 'property.electric.fee.line'
_description = '物业电费明细行'
contract_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批")
property_meter_archives_id = fields.Many2one('property.meter.archives', string="电表库")
rate = fields.Integer(related='property_meter_archives_id.gauge_magnification', string="倍率", store=True)
standard_id = fields.Many2one(related='property_meter_archives_id.standards_id', string="标准", store=True)
installation_date = fields.Date(related='property_meter_archives_id.start_time', string="安装日期")
demolition_date = fields.Date(related='property_meter_archives_id.end_time', string="拆除日期")
location = fields.Char(related='property_meter_archives_id.installation_location', string="位置")
class PropertyManageFeeLine(models.Model):
_name = 'property.manage.fee.line'
_description = '物业管理费明细行'
contract_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批")
charges = fields.Char(string="收费项")
fees_id = fields.Many2one('property.message.fee', string="收费标准")
proportional = fields.Float(string="倍率/比例")
class PropertyOtherFeeLine(models.Model):
_name = 'property.other.fee.line'
_description = '物业其他费用明细行'
other_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批")
charges = fields.Char(string="收费项")
coping = fields.Float(string="应收")
coping_time = fields.Date(string="应收日期")
class PropertySubsetContract(models.Model):
_name = 'property.subset.contract'
_description = '物业子合同明细'
subset_id = fields.Many2one('property.lease.contract', string="关联租赁合同审批")
contract_id = fields.Many2one('property.lease.contract', string="合同")
name = fields.Char(related='contract_id.name', string="物业信息")
lessee_id = fields.Many2one(related='contract_id.lessee_id', string="承租方")
rental_purposes = fields.Many2one(related='contract_id.rental_purposes', string="出租用途")