添加功能
This commit is contained in:
@@ -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="会议地点")
|
||||
|
||||
@@ -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"/>-->
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user