添加功能

This commit is contained in:
zhou
2025-05-10 15:19:39 +08:00
parent 0e52ad68e7
commit 041e26ba0e
10 changed files with 171 additions and 47 deletions
+1 -1
View File
@@ -40,7 +40,7 @@ class RoomBooking(models.Model):
other_company_id = fields.Many2one('res.partner', string="外部公司")
host = fields.Many2one('res.users', string="主持人")
stationed_group = fields.Boolean(string="驻组参会")
other_company_user_ids = fields.One2many(related="other_company_id.child_ids", string="其他人员")
other_company_user_ids = fields.Many2many('other.meet.employee', string="其他人员")
fleet_id = fields.Many2one('fleet.vehicle', string="车辆")
meeting_place = fields.Char(string="会议地点")
+5 -1
View File
@@ -6,7 +6,11 @@
<field name="implied_ids" eval="[Command.link(ref('base.group_user'))]"/>
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/>
</record>
<record model="ir.rule" id="room_booking_rule">
<field name="name">预定会议多公司</field>
<field name="model_id" ref="model_room_booking"/>
<field name="domain_force">[('company_id', 'in', company_ids)]</field>
</record>
<!-- <record id="room_room_comp_rule" model="ir.rule">-->
<!-- <field name="name">Room Room MC Rule</field>-->
<!-- <field name="model_id" ref="model_room_room"/>-->
+2 -2
View File
@@ -155,11 +155,11 @@
<field name="driver" invisible="meeting_type != 'exterior'"/>
<field name="fleet_id" invisible="meeting_type != 'exterior'"/>
<field name="meeting_place" invisible="meeting_type != 'exterior'"/>
<field name="room_id" string="会议地点"/>
<field name="room_id" string="会议地点" domain=""/>
</group>
<group>
<field name="department_id" widget="ztree_select"/>
<field name="meeting_type_id" required="1"/>
<field name="meeting_type_id" required="1" domain="[('company_id', '=', company_id)]"/>
</group>
</group>
<group col="4">
+45 -10
View File
@@ -168,21 +168,56 @@ class HrLeave(models.Model):
holiday.number_of_days = days
if holiday.holiday_status_id.type_of_work == "0":
calendar_leaves = self.env['resource.calendar.leaves'].search([("calendar_id", "=", "行政考勤工作日")])
target_day = holiday.request_date_from
for leaves in calendar_leaves:
shift_days = leaves.shift_replacement_day.split(',') if leaves.shift_replacement_day else []
for day_str in shift_days:
day = datetime.strptime(day_str, '%m月%d日')
if day.month == target_day.month and day.day == target_day.day:
hour = float(holiday.request_hour_to) - float(holiday.request_hour_from) -2
holiday.number_of_hours = hour
holidays_list = []
shift_days_list = []
holidays_list = [] # 假期
shift_days_list = [] #调休
for leaves in calendar_leaves:
if leaves.holidays:
holidays_list.extend(leaves.holidays.split(','))
if leaves.shift_replacement_day:
shift_days_list.extend(leaves.shift_replacement_day.split(','))
target_day = holiday.request_date_from
target_day_str = f"{target_day.month}月{target_day.day}日"
is_weekend = self.request_date_from.weekday() in [5, 6]
# 判断是否为假期
if target_day_str in holidays_list:
holiday.number_of_hours = 0
# 判断是否为调休日
elif target_day_str in shift_days_list:
if holiday.request_hour_from and holiday.request_hour_to:
# 调休日无论是否在周末都按正常逻辑计算
start_hour = int(holiday.request_hour_from)
end_hour = int(holiday.request_hour_to)
# 跨中午12点的情况
if start_hour < 12 and end_hour > 12:
hour = float(end_hour) - float(start_hour) - 1
holiday.number_of_hours = hour
# 9点到12点的情况
elif start_hour == 9 and end_hour == 12:
holiday.number_of_hours = 4
# 其他情况按正常计算
else:
hour = float(end_hour) - float(start_hour)
holiday.number_of_hours = hour
# 非假期且非调休日的情况
else:
# 如果是周末且不在调休列表中,小时数为0
if is_weekend:
holiday.number_of_hours = 0
# 普通工作日按正常逻辑计算
else:
if holiday.request_hour_from and holiday.request_hour_to:
start_hour = int(holiday.request_hour_from)
end_hour = int(holiday.request_hour_to)
if start_hour < 12 and end_hour > 12:
hour = float(end_hour) - float(start_hour) - 1
holiday.number_of_hours = hour
elif start_hour == 9 and end_hour == 12:
holiday.number_of_hours = 4
else:
hour = float(end_hour) - float(start_hour)
holiday.number_of_hours = hour
days = (self.request_date_to - self.request_date_from).days + 1
current_date = self.request_date_from
while current_date <= self.request_date_to:
@@ -12,8 +12,6 @@ class PropertyBusinessStatements(models.Model):
pre_receipt = fields.Float(string='前期预收')
receivable_month = fields.Float(string='本月应收')
total_received = fields.Float(string='实收总额')
accumulated_underpayment = fields.Float(string='累计欠收')
cumulative_income = fields.Float(string='累计收入')
# 其他收入 违约金
penalty_month = fields.Float(string='本月应收')
penalty_received = fields.Float(string='本月实收')
@@ -77,6 +77,19 @@ class InheritHrPayslip(models.Model):
based_pay = fields.Float(string='临时绩效工资')
life_salary = fields.Float(string='生活补贴')
january_performance = fields.Float(string='1月份绩效奖金补发')
accumulated_underpayment = fields.Float(string='累计欠收')
cumulative_income = fields.Float(string='其他单位累计收入')
other_cum_deductions = fields.Float(string='其他单位累计扣除')
other_cumulative_deductions = fields.Float(string='其他单位累计减免税额')
other_cumulative_tax_paid = fields.Float(string='其他单位累计已缴税额')
cumulative_taxable = fields.Float(string='累计应纳税所得额')
quick_deductions = fields.Float(string='速算扣除数')
payable = fields.Float(string='累计应纳税额')
tariff = fields.Float(string='税率')
cumulative_deductions = fields.Float(string='累计减免税额')
amount_tax_withheld = fields.Float(string='累计应扣缴税额')
remake = fields.Text(string='备注')
performance_deduction = fields.Float(string='扣发绩效奖金', compute='_compute_deduction', store=True)
commuting_deduction = fields.Float(string='扣发通信补贴', compute='_compute_deduction', store=True)
@@ -176,15 +176,26 @@
<field name="housing_loan_interest"/>
<field name="housing_rent"/>
<field name="child_education"/>
<field name="accumulated_underpayment"/>
<field name="cumulative_income"/>
<field name="other_cum_deductions"/>
<field name="other_cumulative_deductions"/>
</group>
<group>
<field name="continuing_education"/>
<field name="elderly_support"/>
<field name="infant_care"/>
<field name="cumulative_taxable"/>
<field name="quick_deductions"/>
<field name="payable"/>
<field name="tariff"/>
</group>
<group>
<field name="tax"/>
<field name="total_before_tax"/>
<field name="cumulative_deductions"/>
<field name="amount_tax_withheld"/>
<field name="remake"/>
<field name="full_attendance_award" invisible="1"/>
<field name="commuting_allowance" invisible="1"/>
<field name="post_salary" invisible="1" required="0"/>
+90 -25
View File
@@ -5,7 +5,8 @@ from pypinyin import pinyin, Style
import xlrd
import base64
import datetime
from datetime import datetime
from datetime import datetime, timedelta
class SalaryPayslipWizard(models.Model):
@@ -14,22 +15,77 @@ class SalaryPayslipWizard(models.Model):
excel_file = fields.Binary(string="上传Excel表")
excel_name = fields.Char(string="文件名")
select_time = fields.Selection([('1', '一月'), ('2', '二月'), ('3', '三月'), ('4', '四月'),
('5', '五月'), ('6', '六月'), ('7', '七月'), ('8', '八月'),
('9', '九月'), ('10', '十月'), ('11', '十一月'),
('12', '十二月')], string='选择月份',
default=lambda self: self._get_default_month())
def confirm(self):
if not self.excel_file:
raise ValidationError('请上传文件。')
book = xlrd.open_workbook(file_contents=base64.decodebytes(self.excel_file))
sh = book.sheet_by_index(0)
field_mapping = {
# 格式: 'Excel表头': ('模型字段', 列索引)
'累计减除费用': ('deduction_standard', 20), # U列
'累计专项扣除': ('specialized_deduction', 21), # V列
'累计子女教育支出扣除': ('child_education', 22), # W列
'累计继续教育支出扣除': ('continuing_education', 23), # X列
'累计住房贷款利息支出扣除': ('housing_loan_interest', 24), # Y列
'累计住房租金支出扣除': ('housing_rent', 25), # Z列
'累计赡养老人支出扣除': ('elderly_support', 26), # AA列
'累计3岁以下婴幼儿照护': ('infant_care', 27), # AB列
'累计个人养老金': ('elderly_support_deduction', 28), # AC列
'累计其他扣除': ('others', 29), # AD列
'累计准予扣除的捐赠': ('deductible_donations', 30), # AE列
'其他单位累计收入': ('cumulative_income', 31), # AF列
'其他单位累计扣除': ('other_cum_deductions', 32), # AG列
'其他单位累计减免税额': ('other_cumulative_deductions', 33), # AH列
'其他单位累计已缴税额': ('other_cumulative_tax_paid', 34), # AI列
'累计应纳税所得额': ('cumulative_taxable', 35), # AJ列
'税率': ('tariff', 36), # AK列
'速算扣除数': ('quick_deductions', 37), # AL列
'累计应纳税额': ('payable', 38), # AM列
'累计减免税额': ('cumulative_deductions', 39), # AN列
'累计应扣缴税额': ('amount_tax_withheld', 40), # AO列
'已缴税额': ('paid_tax', 41), # AP列
'应补(退)税额': ('tax_payable', 42), # AQ列
'备注': ('remake', 43), # AR列
}
header_row = sh.row(0)
headers = [cell.value.strip() for cell in header_row]
# 定义列索引到字母的映射函数
def index_to_column_letter(index):
"""将列索引(0-based)转换为Excel列字母(A, B, C...)"""
letter = ''
while index >= 0:
letter = chr(index % 26 + ord('A')) + letter
index = index // 26 - 1
return letter
missing_headers = [header for header in field_mapping.keys() if header not in headers]
if missing_headers:
raise UserError("该字段没有找到: %s。请核对模板和字段名称" % ", ".join(missing_headers))
for field_name, (internal_name, expected_col_idx) in field_mapping.items():
actual_col_index = headers.index(field_name)
if actual_col_index != expected_col_idx:
expected_letter = index_to_column_letter(expected_col_idx)
actual_letter = index_to_column_letter(actual_col_index)
raise UserError(f"列位置不匹配: {field_name} 应位于列 {expected_letter},但实际位于列 {actual_letter}")
for rx in range(1, sh.nrows):
row = sh.row(rx)
self.yuthon_payroll_data(row)
def yuthon_payroll_data(self, row):
employee_id = self.env['hr.employee'].search([('name', '=', row[1].value)])
year = (row[4].value).split('-')[0]
month = (row[4].value).split('-')[1]
payslip_run_name = f'{year}年-{int(month)}月'
current_year = datetime.now().year
payslip_run_name = f'{current_year}年-{int(self.select_time)}月'
month = int(self.select_time)
payslip_run_id = self.env['hr.payslip.run'].search([('name', '=', payslip_run_name)])
date_from = datetime(current_year, month, 1).strftime('%Y-%m-%d')
last_day = (datetime(current_year, month % 12 + 1, 1) - timedelta(days=1)).strftime('%Y-%m-%d')
if not payslip_run_id:
payslip_run_id = self.env['hr.payslip.run'].create({
'name': payslip_run_name,
@@ -39,25 +95,34 @@ class SalaryPayslipWizard(models.Model):
'payslip_count': 0
})
payslip_id = self.env['hr.payslip'].search([('employee_id', '=', employee_id.id), ('is_push', '=', True), ('is_salary_push', '=', False),
('date_from', '>=', row[4].value), ('date_to', '<=', row[5].value)])
('date_from', '>=', date_from), ('date_to', '<=', last_day)])
payslip_id.write({
'name': employee_id.name,
'employee_id': employee_id.id,
'payslip_run_id': payslip_run_id.id,
'state': 'draft',
'child_education': row[12].value,
'continuing_education': row[13].value,
'housing_loan_interest': row[14].value,
'housing_rent':row[15].value,
'elderly_support':row[16].value,
'infant_care':row[17].value,
'elderly_support_deduction':row[18].value,
'commercial_health_insurance': row[20].value,
'tax_deferred_pension_insurance': row[21].value,
'others': row[22].value,
'deductible_donations': row[23].value,
'total_pre_tax_deductions': row[24].value,
'tax_reduction': row[25].value,
'deduction_standard': row[26].value,
'paid_tax': row[27].value,
})
'deduction_standard': row[20].value,
'specialized_deduction': row[21].value,
'child_education': row[22].value,
'continuing_education': row[23].value,
'housing_loan_interest': row[24].value,
'housing_rent': row[25].value,
'elderly_support': row[26].value,
'infant_care': row[27].value,
'elderly_support_deduction': row[28].value,
'others': row[29].value,
'deductible_donations': row[30].value,
'cumulative_income': row[31].value,
'other_cum_deductions': row[32].value,
'other_cumulative_deductions': row[33].value,
'other_cumulative_tax_paid': row[34].value,
'cumulative_taxable': row[35].value,
'tariff': row[36].value,
'quick_deductions': row[37].value,
'payable': row[38].value,
'cumulative_deductions': row[39].value,
'amount_tax_withheld': row[40].value,
'paid_tax': row[41].value,
'tax_payable': row[42].value,
'remake': row[43].value,
})
def _get_default_month(self):
current_month = datetime.now().month
return str(current_month)
@@ -10,13 +10,11 @@
<field name="model">salary.payslip.wizard</field>
<field name="arch" type="xml">
<form>
<p>请严格按照模板和字段名称来导入数据。B列为姓名U列为累计减除费用</p>
<sheet>
<header>
<button name="%(payslip_template_downloads_tian_he_action)d" string="模板下载" type="action"
class="btn btn-primary"/>
</header>
<group>
<group>
<field name="select_time"/>
<field name="excel_file" filename="excel_name"/>
<field name="excel_name" invisible="1"/>
</group>
@@ -135,7 +135,7 @@
</group>
</group>
<group>
<field name="user_id"/>
<field name="user_id" domain="[('company_id', '=', company_id)]"/>
<field name="employee_ids" widget="many2many_tags" options="{'no_create': True}"/>
<field name='employee_ids2' widget="many2many_tags" domain="[('user_role_ids.name', 'in', ['司机'])]"/>
<field name='users_ids' widget="many2many_tags" invisible="1"/>
@@ -199,7 +199,7 @@
<field name='name'>领导日程</field>
<field name='res_model'>yuthon.will.task</field>
<field name='view_mode'>tree,calendar,form</field>
<field name='domain'>[('user_role_ids.name', 'in', ['董事长', '分管领导', '总经理', '部门副经理', '部门经理', '副总经理'])]</field>
<field name='domain'>[('user_role_ids.name', 'in', ['董事长', '分管领导', '总经理', '部门副经理', '部门经理', '副总经理', '司机'])]</field>
<field name="context">{'search_default_next_seven_days': 1}</field>
</record>
</odoo>