diff --git a/room/models/room_booking.py b/room/models/room_booking.py index 97ecd6fa5..fa4392681 100644 --- a/room/models/room_booking.py +++ b/room/models/room_booking.py @@ -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="会议地点") diff --git a/room/security/ir_rule.xml b/room/security/ir_rule.xml index f92da61dd..7dd5ed968 100644 --- a/room/security/ir_rule.xml +++ b/room/security/ir_rule.xml @@ -6,7 +6,11 @@ - + + 预定会议多公司 + + [('company_id', 'in', company_ids)] + diff --git a/room/views/room_booking_views.xml b/room/views/room_booking_views.xml index ea9e07898..20d92d38c 100644 --- a/room/views/room_booking_views.xml +++ b/room/views/room_booking_views.xml @@ -155,11 +155,11 @@ - + - + diff --git a/yuthon_holiday/models/inherit_hr_leave.py b/yuthon_holiday/models/inherit_hr_leave.py index 015242ff7..65f0fcb11 100644 --- a/yuthon_holiday/models/inherit_hr_leave.py +++ b/yuthon_holiday/models/inherit_hr_leave.py @@ -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: diff --git a/yuthon_property/models/property_business_statements.py b/yuthon_property/models/property_business_statements.py index b7c2a7f61..5e85ab1d6 100644 --- a/yuthon_property/models/property_business_statements.py +++ b/yuthon_property/models/property_business_statements.py @@ -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='本月实收') diff --git a/yuthon_salary/models/inherit_hr_payslip.py b/yuthon_salary/models/inherit_hr_payslip.py index 0e21b1a81..a3708bbd5 100644 --- a/yuthon_salary/models/inherit_hr_payslip.py +++ b/yuthon_salary/models/inherit_hr_payslip.py @@ -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) diff --git a/yuthon_salary/views/inherit_hr_payslip_views.xml b/yuthon_salary/views/inherit_hr_payslip_views.xml index 8c1caa54e..9529f716c 100644 --- a/yuthon_salary/views/inherit_hr_payslip_views.xml +++ b/yuthon_salary/views/inherit_hr_payslip_views.xml @@ -176,15 +176,26 @@ + + + + + + + + + + + diff --git a/yuthon_salary/wizard/salary_payslip_wizard.py b/yuthon_salary/wizard/salary_payslip_wizard.py index 432b7ef00..f512d3ae8 100644 --- a/yuthon_salary/wizard/salary_payslip_wizard.py +++ b/yuthon_salary/wizard/salary_payslip_wizard.py @@ -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, - }) \ No newline at end of file + '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) \ No newline at end of file diff --git a/yuthon_salary/wizard/salary_payslip_wizard_views.xml b/yuthon_salary/wizard/salary_payslip_wizard_views.xml index b10d148df..ffe465b5e 100644 --- a/yuthon_salary/wizard/salary_payslip_wizard_views.xml +++ b/yuthon_salary/wizard/salary_payslip_wizard_views.xml @@ -10,13 +10,11 @@ salary.payslip.wizard
+

请严格按照模板和字段名称来导入数据。B列为姓名U列为累计减除费用

-
-
+ diff --git a/yuthon_will_task/views/yuthon_will_task_views.xml b/yuthon_will_task/views/yuthon_will_task_views.xml index 6add1361f..376364231 100644 --- a/yuthon_will_task/views/yuthon_will_task_views.xml +++ b/yuthon_will_task/views/yuthon_will_task_views.xml @@ -135,7 +135,7 @@ - + @@ -199,7 +199,7 @@ 领导日程 yuthon.will.task tree,calendar,form - [('user_role_ids.name', 'in', ['董事长', '分管领导', '总经理', '部门副经理', '部门经理', '副总经理'])] + [('user_role_ids.name', 'in', ['董事长', '分管领导', '总经理', '部门副经理', '部门经理', '副总经理', '司机'])] {'search_default_next_seven_days': 1}