@@ -9,6 +9,7 @@ from odoo.tools.misc import format_date
|
||||
from collections import namedtuple, defaultdict
|
||||
from datetime import date
|
||||
import calendar
|
||||
import logging
|
||||
|
||||
|
||||
class HrLeave(models.Model):
|
||||
@@ -438,6 +439,8 @@ class HrLeave(models.Model):
|
||||
day = day.lstrip('0')
|
||||
return f'{month}月{day}日'
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class HolidaysRequestBatch(models.Model):
|
||||
_name = 'hr.leave.batch'
|
||||
_description = '请假审批'
|
||||
@@ -506,8 +509,7 @@ class HolidaysRequestBatch(models.Model):
|
||||
# 提交
|
||||
def action_submit(self):
|
||||
"""提交请假申请,区分年假和其他假期处理"""
|
||||
# self.leave_ids.action_validate()
|
||||
# self.hour_leave_ids.action_validate()
|
||||
_logger.info(f"开始处理请假申请:{self.code},申请人:{self.users_id.employee_id.name}")
|
||||
|
||||
self._process_specific_leaves('年假', is_annual_leave=True)
|
||||
other_leave_types = [
|
||||
@@ -518,6 +520,8 @@ class HolidaysRequestBatch(models.Model):
|
||||
]
|
||||
for leave_type in other_leave_types:
|
||||
self._process_specific_leaves(leave_type, is_annual_leave=False)
|
||||
|
||||
_logger.info(f"请假申请:{self.code} 处理完成")
|
||||
return True
|
||||
|
||||
def _process_specific_leaves(self, leave_type_name, is_annual_leave):
|
||||
@@ -526,129 +530,209 @@ class HolidaysRequestBatch(models.Model):
|
||||
:param leave_type_name: 假期类型名称
|
||||
:param is_annual_leave: 是否为年假(True/False)
|
||||
"""
|
||||
_logger.info(f"开始处理假期类型:{leave_type_name},是否为年假:{is_annual_leave},申请编号:{self.code}")
|
||||
|
||||
# 收集天假和小时假记录
|
||||
day_leaves = self._get_day_leaves(leave_type_name)
|
||||
hourly_leaves = self._get_hourly_leaves(leave_type_name)
|
||||
|
||||
_logger.debug(f"假期类型:{leave_type_name},天假记录数:{len(day_leaves)},小时假记录数:{len(hourly_leaves)}")
|
||||
|
||||
# 处理天假
|
||||
for leave in day_leaves:
|
||||
date_ranges = self._split_by_month(leave['start'], leave['end']) if not is_annual_leave else [
|
||||
{'start': leave['start'], 'end': leave['end']}]
|
||||
for period in date_ranges:
|
||||
days = self._compute_duration_day(leave['type_id'], period['start'], period['end'])
|
||||
for idx, leave in enumerate(day_leaves):
|
||||
try:
|
||||
# 跨月拆分逻辑(仅非年假)
|
||||
date_ranges = self._split_by_month(leave['start'], leave['end']) if not is_annual_leave else [
|
||||
{'start': leave['start'], 'end': leave['end']}
|
||||
]
|
||||
_logger.debug(
|
||||
f"天假记录 {idx + 1} 拆分后日期段数:{len(date_ranges)},原始起止:{leave['start']}至{leave['end']}")
|
||||
|
||||
for period in date_ranges:
|
||||
days = self._compute_duration_day(leave['type_id'], period['start'], period['end'])
|
||||
_logger.debug(f"日期段 {period['start']}至{period['end']} 计算天数:{days}")
|
||||
|
||||
if days > 0:
|
||||
if is_annual_leave:
|
||||
self._create_annual_leave_line(period['start'], leave, days, period)
|
||||
else:
|
||||
self._create_other_leave_line(period['start'], leave, days, period, leave_type_name)
|
||||
except Exception as e:
|
||||
_logger.error(f"处理天假记录 {idx + 1} 失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
|
||||
# 处理小时假
|
||||
for idx, leave in enumerate(hourly_leaves):
|
||||
try:
|
||||
leave_date = leave['date']
|
||||
days = leave['days']
|
||||
_logger.debug(f"小时假记录 {idx + 1} 日期:{leave_date},转换天数:{days}")
|
||||
|
||||
if days > 0:
|
||||
if is_annual_leave:
|
||||
self._create_annual_leave_line(period['start'], leave, days, period)
|
||||
self._create_annual_leave_line(leave_date, leave, days,
|
||||
{'start': leave_date, 'end': leave_date})
|
||||
else:
|
||||
self._create_other_leave_line(period['start'], leave, days, period, leave_type_name)
|
||||
# 处理小时假
|
||||
for leave in hourly_leaves:
|
||||
leave_date = leave['date']
|
||||
days = leave['days']
|
||||
if days > 0:
|
||||
if is_annual_leave:
|
||||
self._create_annual_leave_line(leave_date, leave, days, {'start': leave_date, 'end': leave_date})
|
||||
else:
|
||||
self._create_other_leave_line(leave_date, leave, days,{'start': leave_date, 'end': leave_date}, leave_type_name)
|
||||
self._create_other_leave_line(leave_date, leave, days, {'start': leave_date, 'end': leave_date},
|
||||
leave_type_name)
|
||||
except Exception as e:
|
||||
_logger.error(f"处理小时假记录 {idx + 1} 失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
|
||||
_logger.info(f"假期类型:{leave_type_name} 处理完成")
|
||||
|
||||
def _create_other_leave_line(self, period_start, leave_data, days, period, leave_type_name):
|
||||
"""为非年假类型创建vacation.other.line记录"""
|
||||
# 查找关联的假期额度记录
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
try:
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
|
||||
self.env['vacation.other.line'].sudo().create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'holiday_type': leave_data['type_id'].id,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_date': fields.Date.today(),
|
||||
'update_type': 'reduce',
|
||||
'lines': days,
|
||||
'text': f"请假审批"
|
||||
})
|
||||
_logger.debug(
|
||||
f"创建非年假明细(类型:{leave_type_name}),关联假期记录:{vacation_report.id if vacation_report else '无'},天数:{days}")
|
||||
|
||||
record = self.env['vacation.other.line'].sudo().create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'holiday_type': leave_data['type_id'].id,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_date': fields.Date.today(),
|
||||
'update_type': 'reduce',
|
||||
'lines': days,
|
||||
'text': f"请假审批"
|
||||
})
|
||||
_logger.info(f"成功创建非年假明细记录:{record.id}(类型:{leave_type_name})")
|
||||
except Exception as e:
|
||||
_logger.error(f"创建非年假明细失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
|
||||
def _get_day_leaves(self, leave_type_name):
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
return [{
|
||||
try:
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
records = [{
|
||||
'start': fields.Date.from_string(leave.request_date_from),
|
||||
'end': fields.Date.from_string(leave.request_date_to),
|
||||
'type_id': leave.holiday_status_id,
|
||||
'workflow_id': workflow_id}
|
||||
for leave in self.leave_ids
|
||||
if leave.holiday_status_id.name == leave_type_name
|
||||
and leave.request_date_from
|
||||
and leave.request_date_to
|
||||
]
|
||||
for leave in self.leave_ids
|
||||
if leave.holiday_status_id.name == leave_type_name
|
||||
and leave.request_date_from
|
||||
and leave.request_date_to
|
||||
]
|
||||
_logger.debug(f"收集天假记录(类型:{leave_type_name}):{len(records)}条")
|
||||
return records
|
||||
except Exception as e:
|
||||
_logger.error(f"收集天假记录失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
return []
|
||||
|
||||
def _get_hourly_leaves(self, leave_type_name):
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
hourly_records = []
|
||||
for line in self.hour_leave_ids:
|
||||
if line.holiday_status_id.name == leave_type_name and line.request_date_from:
|
||||
hours_match = re.search(r'(\d+(?:\.\d+)?)', line.number_of_hours_text or '')
|
||||
hours = float(hours_match.group(1)) if hours_match else 0
|
||||
hourly_records.append({
|
||||
'date': fields.Date.from_string(line.request_date_from),
|
||||
'type_id': line.holiday_status_id,
|
||||
'workflow_id': workflow_id,
|
||||
'days': hours / 8 # 转换为天数
|
||||
})
|
||||
return hourly_records
|
||||
try:
|
||||
workflow_id = self.env['soong.workflow.record'].search([('code', '=', self.code)], limit=1).id
|
||||
hourly_records = []
|
||||
for line in self.hour_leave_ids:
|
||||
if line.holiday_status_id.name == leave_type_name and line.request_date_from:
|
||||
hours_match = re.search(r'(\d+(?:\.\d+)?)', line.number_of_hours_text or '')
|
||||
hours = float(hours_match.group(1)) if hours_match else 0
|
||||
days = hours / 8
|
||||
hourly_records.append({
|
||||
'date': fields.Date.from_string(line.request_date_from),
|
||||
'type_id': line.holiday_status_id,
|
||||
'workflow_id': workflow_id,
|
||||
'days': days
|
||||
})
|
||||
_logger.debug(f"收集小时假记录(类型:{leave_type_name}):{len(hourly_records)}条")
|
||||
return hourly_records
|
||||
except Exception as e:
|
||||
_logger.error(f"收集小时假记录失败(类型:{leave_type_name}):{str(e)}", exc_info=True)
|
||||
return []
|
||||
|
||||
def _split_by_month(self, start_date, end_date):
|
||||
# 跨月拆分逻逻辑
|
||||
date_ranges = []
|
||||
if start_date.month == end_date.month and start_date.year == end_date.year:
|
||||
date_ranges.append({'start': start_date, 'end': end_date})
|
||||
try:
|
||||
date_ranges = []
|
||||
if start_date.month == end_date.month and start_date.year == end_date.year:
|
||||
date_ranges.append({'start': start_date, 'end': end_date})
|
||||
_logger.debug(f"无需跨月拆分:{start_date}至{end_date}")
|
||||
return date_ranges
|
||||
|
||||
first_month_end = date(start_date.year, start_date.month,
|
||||
calendar.monthrange(start_date.year, start_date.month)[1])
|
||||
date_ranges.append({'start': start_date, 'end': first_month_end})
|
||||
|
||||
current_month = start_date.month + 1
|
||||
current_year = start_date.year
|
||||
while (current_year < end_date.year) or (current_year == end_date.year and current_month < end_date.month):
|
||||
if current_month > 12:
|
||||
current_month = 1
|
||||
current_year += 1
|
||||
month_end = date(current_year, current_month, calendar.monthrange(current_year, current_month)[1])
|
||||
date_ranges.append({'start': date(current_year, current_month, 1), 'end': month_end})
|
||||
current_month += 1
|
||||
|
||||
date_ranges.append({'start': date(end_date.year, end_date.month, 1), 'end': end_date})
|
||||
|
||||
_logger.debug(f"跨月拆分完成:原始{start_date}至{end_date},拆分为{len(date_ranges)}段")
|
||||
return date_ranges
|
||||
except Exception as e:
|
||||
_logger.error(f"跨月拆分失败({start_date}至{end_date}):{str(e)}", exc_info=True)
|
||||
return []
|
||||
|
||||
first_month_end = date(start_date.year, start_date.month,
|
||||
calendar.monthrange(start_date.year, start_date.month)[1])
|
||||
date_ranges.append({'start': start_date, 'end': first_month_end})
|
||||
current_month = start_date.month + 1
|
||||
current_year = start_date.year
|
||||
while (current_year < end_date.year) or (current_year == end_date.year and current_month < end_date.month):
|
||||
if current_month > 12:
|
||||
current_month = 1
|
||||
current_year += 1
|
||||
month_end = date(current_year, current_month, calendar.monthrange(current_year, current_month)[1])
|
||||
date_ranges.append({'start': date(current_year, current_month, 1), 'end': month_end})
|
||||
current_month += 1
|
||||
def _compute_duration_day(self, holiday_type_id, start_date, end_date):
|
||||
try:
|
||||
if not start_date or not end_date or start_date > end_date:
|
||||
_logger.warning(f"无效日期范围:{start_date}至{end_date},返回0天")
|
||||
return 0.0
|
||||
|
||||
date_ranges.append({'start': date(end_date.year, end_date.month, 1), 'end': end_date})
|
||||
return date_ranges
|
||||
holiday = self.env['hr.leave.type'].browse(holiday_type_id.id)
|
||||
total_days = (end_date - start_date).days + 1
|
||||
|
||||
if holiday.work_entry_type_id:
|
||||
work_days = 0
|
||||
current_date = start_date
|
||||
while current_date <= end_date:
|
||||
if current_date.isoweekday() not in [6, 7]:
|
||||
work_days += 1
|
||||
current_date += timedelta(days=1)
|
||||
_logger.debug(f"工作日计算:{start_date}至{end_date},共{work_days}天(排除周末)")
|
||||
return work_days
|
||||
|
||||
_logger.debug(f"自然日计算:{start_date}至{end_date},共{total_days}天")
|
||||
return total_days
|
||||
except Exception as e:
|
||||
_logger.error(f"计算天数失败({start_date}至{end_date}):{str(e)}", exc_info=True)
|
||||
return 0.0
|
||||
|
||||
def _create_annual_leave_line(self, period_start, leave_data, days, period):
|
||||
"""更新年假记录"""
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
# 创建年假明细记录
|
||||
self.env['vacation.leave.line'].create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_type': 'reduce',
|
||||
'update_date': fields.Date.today(),
|
||||
'update_lines': days,
|
||||
'is_void': False,
|
||||
'allocation_type': 'vacation',
|
||||
'text': f"请假审批"
|
||||
})
|
||||
try:
|
||||
report_month = date(period_start.year, period_start.month, 1)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', self.users_id.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(report_month)),
|
||||
('vacation_date', '<=', fields.Date.to_string(
|
||||
date(period_start.year, period_start.month,
|
||||
calendar.monthrange(period_start.year, period_start.month)[1]))
|
||||
)
|
||||
], limit=1)
|
||||
|
||||
_logger.debug(f"创建年假明细,关联假期记录:{vacation_report.id if vacation_report else '无'},天数:{days}")
|
||||
|
||||
record = self.env['vacation.leave.line'].create({
|
||||
'vacation_id': vacation_report.id if vacation_report else False,
|
||||
'employee_id': self.users_id.employee_id.id,
|
||||
'workflow_record_id': leave_data['workflow_id'],
|
||||
'update_type': 'reduce',
|
||||
'update_date': fields.Date.today(),
|
||||
'update_lines': days,
|
||||
'is_void': False,
|
||||
'allocation_type': 'vacation',
|
||||
'text': f"请假审批"
|
||||
})
|
||||
_logger.info(f"成功创建年假明细记录:{record.id}")
|
||||
except Exception as e:
|
||||
_logger.error(f"创建年假明细失败:{str(e)}", exc_info=True)
|
||||
|
||||
|
||||
def _compute_duration_day(self, holiday_status_id, start_date, end_date):
|
||||
|
||||
@@ -14,5 +14,18 @@
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
<record forcecreate="True" id="yuthon_vacation_start_end_time" model="ir.cron">
|
||||
<field name="name">定时任务:更新我的考勤确认单实到数据</field>
|
||||
<field name="model_id" ref="model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model.monthly_day_report()</field>
|
||||
<field eval="False" name="active"/>
|
||||
<field name="user_id" ref="base.user_root"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="nextcall" eval="(DateTime.now()).strftime('%Y-%m-%d 00:00:00')"/>
|
||||
<field name="numbercall">-1</field>
|
||||
<field eval="False" name="doall"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -8,6 +8,7 @@ import logging
|
||||
import traceback
|
||||
from odoo import api, fields, models, tools, _
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import date
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -81,6 +82,33 @@ class HrAttendanceDetail(models.Model):
|
||||
"context": {'default_attendance_detail_id': self.id}
|
||||
}
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
record = super(HrAttendanceDetail, self).create(vals)
|
||||
if record.employee_id and record.checkin_time and record.checkin_type != '未打卡':
|
||||
self._update_actual_attendance(record)
|
||||
return record
|
||||
|
||||
def _update_actual_attendance(self, record):
|
||||
"""更新假期日志中的实到天数"""
|
||||
checkin_date = fields.Date.from_string(record.checkin_time)
|
||||
vacation_report = self.env['yuthon.vacation.reports'].search([
|
||||
('employee_id', '=', record.employee_id.id),
|
||||
('vacation_date', '>=', fields.Date.to_string(date(checkin_date.year, checkin_date.month, 1))),
|
||||
('vacation_date', '<=', fields.Date.to_string(date(checkin_date.year, checkin_date.month,calendar.monthrange(checkin_date.year, checkin_date.month)[1])))], limit=1)
|
||||
|
||||
existing_checkins = self.search([
|
||||
('employee_id', '=', record.employee_id.id),
|
||||
('checkin_time', '>=', fields.Datetime.to_string(datetime.combine(checkin_date, time.min))),
|
||||
('checkin_time', '<=', fields.Datetime.to_string(datetime.combine(checkin_date, time.max))),
|
||||
('id', '!=', record.id)
|
||||
])
|
||||
|
||||
# 如果当天没有其他打卡记录,则实到天数+1
|
||||
if not existing_checkins:
|
||||
vacation_report.actual_attendance = (vacation_report.actual_attendance or 0) + 1
|
||||
|
||||
|
||||
# 传参按一个人打卡一次传参
|
||||
# @api.model_create_multi
|
||||
# def create(self, vals_list):
|
||||
|
||||
@@ -114,6 +114,36 @@ class YuthonVacationReports(models.Model):
|
||||
rec.is_abnormal = is_abnormal
|
||||
rec.actual_attendance = actual_attendance
|
||||
|
||||
|
||||
def _compute_attendance_fields1(self):
|
||||
records = self.env["yuthon.vacation.reports"].browse(
|
||||
self._context.get('active_ids', self._context.get('active_id', self.ids))
|
||||
)
|
||||
for rec in records:
|
||||
leave_days = 0
|
||||
actual_attendance = 0
|
||||
if rec.employee_id and rec.vacation_date:
|
||||
year = rec.vacation_date.year
|
||||
month = rec.vacation_date.month
|
||||
days_in_month = calendar.monthrange(year, month)[1]
|
||||
month_start = date(year, month, 1)
|
||||
month_end = date(year, month, days_in_month)
|
||||
leave_days = rec._create_leave_record(month_start, month_end)
|
||||
for day in range(1, days_in_month + 1):
|
||||
current_date = date(year, month, day)
|
||||
attendances = self.env["hr.attendance"].sudo().search([
|
||||
('employee_id', '=', rec.employee_id.id),
|
||||
("current_data", '=', current_date)
|
||||
])
|
||||
if attendances:
|
||||
has_valid_check = any(att.check_in or att.check_out for att in attendances)
|
||||
if has_valid_check:
|
||||
actual_attendance += 1
|
||||
|
||||
rec.should_attendance = leave_days
|
||||
rec.actual_attendance = actual_attendance
|
||||
|
||||
|
||||
@api.depends('other_fee_ids', 'other_fee_ids.holiday_type', 'other_fee_ids.lines',
|
||||
'other_fee_ids.is_void', 'other_fee_ids.update_type')
|
||||
def _compute_other_leave(self):
|
||||
@@ -270,7 +300,7 @@ class YuthonVacationReports(models.Model):
|
||||
|
||||
def disposable_report(self):
|
||||
year = 2025
|
||||
months = range(1, 8) # 1到7月
|
||||
months = range(1, 8)
|
||||
employees = self.env['hr.employee'].search([])
|
||||
for month in months:
|
||||
report_date = fields.Date.from_string(f"{year}-{month:02d}-01")
|
||||
|
||||
@@ -437,7 +437,7 @@
|
||||
<field name="model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="binding_model_id" ref="yuthon_hr_attendance.model_yuthon_vacation_reports"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.batch_compute_leave_and_overtime()</field>
|
||||
<field name="code">action = model._compute_attendance_fields1()</field>
|
||||
</record>
|
||||
<record id="details_tree_view" model="ir.ui.view">
|
||||
<field name="name">details.tree.tree</field>
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<field name="model">yuthon.department.change</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="部门变更审批">
|
||||
<!-- <header>-->
|
||||
<!-- <button name="approval_end" type="object" string="结束" dclass="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
<!-- <header>-->
|
||||
<!-- <button name="approval_end" type="object" string="结束" dclass="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
<field name="code"/>
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
<field name="name">对账</field>
|
||||
<field name="res_model">property.bank.statements</field>
|
||||
<field name="view_mode">tree,search</field>
|
||||
<field name="domain">[('bank_state', '=', 'not_reconciled'), ('is_company', '=', True)]</field>
|
||||
<field name="domain">[('bank_state', 'in', ['not_reconciled', 'registered']), ('is_company', '=', True)]</field>
|
||||
<field name="view_ids" eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_property.view_property_bank_statements_tree')})]"/>
|
||||
</record>
|
||||
|
||||
@@ -100,6 +100,8 @@ class PropertyReconciliationWizard(models.Model):
|
||||
penalty_amount = late_days * round(
|
||||
line.rent * float(line.contract_id.percentage_liquidated_damages.name), 2
|
||||
)
|
||||
start_date_str = fields.Date.to_string(next_month_first)
|
||||
end_date_str = self.actual_date
|
||||
if penalty_amount > 0:
|
||||
# 检查是否已存在相同条件的违约金行
|
||||
is_duplicate = any(
|
||||
@@ -109,7 +111,6 @@ class PropertyReconciliationWizard(models.Model):
|
||||
and pl.collection_type == 'penalty'
|
||||
for pl in existing_penalty_lines
|
||||
)
|
||||
|
||||
if not is_duplicate:
|
||||
# 创建新的违约金记录
|
||||
penalty_line_vals = {
|
||||
@@ -120,7 +121,7 @@ class PropertyReconciliationWizard(models.Model):
|
||||
'rent': penalty_amount,
|
||||
'amount': 0,
|
||||
'collection_type': 'penalty',
|
||||
'remake': f'违约金 ({late_days}天)',
|
||||
'remake': f'违约金({start_date_str}至{end_date_str},共{late_days}天)',
|
||||
'sequence': int(line.sequence) + 1,
|
||||
}
|
||||
new_lines.append((0, 0, penalty_line_vals))
|
||||
@@ -185,7 +186,7 @@ class PropertyReconciliationWizard(models.Model):
|
||||
receivable.write({
|
||||
'is_reconciliation': is_reconciliation,
|
||||
'delivered1': line.amount,
|
||||
'payout_date': rec.bank_id.start_time.date(),
|
||||
'payout_date': self.actual_date,
|
||||
'remark': line.remake,
|
||||
'reconciliation_time': fields.Datetime.now(),
|
||||
'receivable_log': f'当前登录人{rec.env.user.name}于{fields.Datetime.now()}对户名为{rec.bank_id.name_account}进行对账操作,对账应收金额为{rec.receivable_total},实际金额为{rec.actual_total}'
|
||||
@@ -209,7 +210,7 @@ class PropertyReconciliationWizard(models.Model):
|
||||
'property_id': line.property_id.id,
|
||||
'contract_id': line.contract_id.id,
|
||||
'delivered1': line.amount,
|
||||
'payout_date': rec.bank_id.start_time.date() if is_reconciliation else None,
|
||||
'payout_date': self.actual_date,
|
||||
'original_amount': line.rent,
|
||||
'remark': line.remake,
|
||||
'reconciliation_time': fields.Datetime.now(),
|
||||
|
||||
Reference in New Issue
Block a user