295 lines
15 KiB
Python
295 lines
15 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
import calendar
|
|
from dateutil.relativedelta import relativedelta
|
|
from odoo.tools.float_utils import float_round
|
|
from odoo import models, fields, api, exceptions, _
|
|
from odoo.exceptions import ValidationError
|
|
|
|
|
|
class PropertyOpenRent(models.Model):
|
|
_name = 'property.open.rent'
|
|
_description = '公开招租审批'
|
|
_inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin']
|
|
_rec_name = 'name'
|
|
|
|
name = fields.Char(string='标题')
|
|
user_id = fields.Many2one('res.users', string='申请人', default=lambda self: self.env.user.id)
|
|
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('property_open_rent_code'))
|
|
property_documents_ids = fields.Many2many('documents.document', string="物业公开招租文件")
|
|
rental_area = fields.Float(string="出租面积")
|
|
upset = fields.Float(string="底价")
|
|
document_ids = fields.Many2many('ir.attachment', 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())]")
|
|
is_chapter = fields.Selection([('yes', '是'), ('no', '否')], string='是否用章', default='no')
|
|
|
|
# 物业
|
|
property_name = fields.Char(string="物业信息")
|
|
lease_ids = fields.One2many('property.lease.contract.line', 'open_rent_id', string="物业信息明细行")
|
|
|
|
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_open_rent_id': self.id,
|
|
'default_property_ids2': property_ids2,
|
|
}
|
|
}
|
|
|
|
# 租期
|
|
term_start_time = fields.Date(string="租期开始")
|
|
term_end_time = fields.Date(string="租期结束")
|
|
lease_term_year = fields.Integer(string="租期(年)", store=True)
|
|
lease_term_month = fields.Integer(string="租期(月)", store=True)
|
|
lease_term_day = fields.Integer(string="租期(日)", store=True)
|
|
|
|
# 递增
|
|
first_years_begin = fields.Integer(string="第几年开始", default=2)
|
|
increments_every_few_years = fields.Integer(string="每几年递增")
|
|
increment_method = fields.Selection([
|
|
('percentage', '百分比'),
|
|
('increment_price', '递增单价'),
|
|
('increment_amount', '递增金额')
|
|
], string='递增方式', default='percentage')
|
|
increment_value = fields.Float(string="递增值")
|
|
|
|
# 月租金、单价、总租金
|
|
unit_price = fields.Float(string="单价", digits=(16, 4))
|
|
rent = fields.Float(string="月租金")
|
|
total_area = fields.Float(string="总面积", digits=(16, 4))
|
|
rent_free_period_month = fields.Integer(string="免租期(月)")
|
|
rent_free_period_days = fields.Integer(string="免租期(日)")
|
|
breakdown_ids = fields.One2many('property.rent.breakdown.line', 'open_rent_id', string="租金明细行")
|
|
total_rent = fields.Float(string="总租金", compute='_compute_total_rent', store=True)
|
|
|
|
@api.depends('term_start_time', 'term_end_time')
|
|
def _compute_lease_term(self):
|
|
for record in self:
|
|
if record.term_start_time and record.term_end_time:
|
|
start = record.term_start_time
|
|
end = record.term_end_time
|
|
years = end.year - start.year
|
|
months = end.month - start.month
|
|
days = end.day - start.day
|
|
if days < 0:
|
|
months -= 1
|
|
days += 30
|
|
if months < 0:
|
|
years -= 1
|
|
months += 12
|
|
record.lease_term_year = years
|
|
record.lease_term_month = months
|
|
record.lease_term_day = days
|
|
else:
|
|
record.lease_term_year = 0
|
|
record.lease_term_month = 0
|
|
record.lease_term_day = 0
|
|
|
|
@api.depends('breakdown_ids')
|
|
def _compute_total_rent(self):
|
|
for record in self:
|
|
record.total_rent = sum(line.period_rent for line in record.breakdown_ids)
|
|
|
|
@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):
|
|
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)
|
|
|
|
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')
|
|
|
|
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,
|
|
"open_rent_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 if self.total_area else 0
|
|
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,
|
|
"open_rent_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,
|
|
"open_rent_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,
|
|
"open_rent_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,
|
|
"open_rent_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 divide_time_range_fixed(self, start_date, end_date, months):
|
|
"""将时间段按 months 个月切分,返回 [(start, end), ...] 列表"""
|
|
result = []
|
|
current = start_date
|
|
while current < end_date:
|
|
next_date = current + relativedelta(months=months)
|
|
if next_date > end_date:
|
|
next_date = end_date
|
|
result.append((current, next_date))
|
|
current = next_date
|
|
return result
|
|
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
|
|
default='normal')
|
|
active = fields.Boolean('Active', default=True, tracking=True)
|
|
work_end = fields.Boolean(string="结束")
|
|
department_id = fields.Many2one('hr.department', 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])])
|
|
|
|
def action_print_property_open_rent(self):
|
|
"""打印公开招租审批"""
|
|
self.ensure_one()
|
|
report_ref = self.env.ref('yuthon_property_approval.action_property_open_rent_print_report')
|
|
return report_ref.sudo().report_action(self)
|
|
|
|
#
|
|
#
|
|
# class PropertyOpenRentLine(models.Model):
|
|
# _name = 'property.open.rent.line'
|
|
#
|
|
# property_open_rent_id = fields.Many2one('property.open.rent', string='关联审批')
|
|
# product_id = fields.Many2one('product.product', string="物业")
|
|
# property_note = fields.Text(string="物业描述")
|
|
|
|
|
|
|
|
|
|
|
|
|