Merge pull request !7173 from 李鹏宇/dev
This commit is contained in:
李鹏宇
2025-12-22 06:25:07 +00:00
committed by Gitee
14 changed files with 186 additions and 119 deletions
@@ -352,8 +352,8 @@ class SoongWorkflowRecord(models.Model):
for record in record_ids:
record_id = record.env[record.res_model].search([('id', '=', record.res_id)])
record_list.append(record.id)
# if record_id.log_ids and self.env.user.name != "Administrator":
# raise UserError("当前流程不可删除")
if record_id.log_ids and self.env.user.name != "Administrator":
raise UserError("当前流程不可删除")
wizard = self.env.ref("soong_workflow.view_soong_workflow_record_delete_wizard")
return {
"name": _("删除确认"),
@@ -179,7 +179,7 @@ class HrLeaveAllocation(models.Model):
def update_vacation(self):
leave_ids = self.env["hr.leave.allocation"].browse(
self._context.get('active_ids', self._context.get('active_id')))
date = datetime(2025, 10, 1) # 修改为你的日期
date = datetime(2025, 12, 1) # 修改为你的日期
for leave in leave_ids:
leave_list = []
compensatory_list = []
@@ -36,27 +36,42 @@ class LeaveAllocationWizard(models.Model):
holiday_status_id1 = self.env['hr.leave.type'].search([('name', '=', '补休')], limit=1)
accrual_plan_id = self.env['hr.leave.accrual.plan'].search([('name', '=', '年假(天河物管)')], limit=1)
if row[1].value and int(row[1].value) != 0:
number_of_days_display = int(row[1].value) / 8
self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
'name': '年假公司分配',
'number_of_days': number_of_days_display,
'employee_ids': [(6, 0, [employee_id.id])],
'holiday_status_id': holiday_status_id.id,
'accrual_plan_id': accrual_plan_id.id,
'allocation_type': 'accrual',
"number_of_days_display": number_of_days_display,
'notes': '年假公司分配'
})
number_of_days_display = int(row[1].value)
allocation_id = self.env['hr.leave.allocation'].search([('employee_id', '=', employee_id.id),
('holiday_status_id', '=', holiday_status_id.id)])
if allocation_id:
allocation_id.write({
'number_of_days': number_of_days_display
})
else:
self.env['hr.leave.allocation'].create({
'employee_id': employee_id.id,
'name': '年假公司分配',
'number_of_days': number_of_days_display,
'employee_ids': [(6, 0, [employee_id.id])],
'holiday_status_id': holiday_status_id.id,
'accrual_plan_id': accrual_plan_id.id,
'allocation_type': 'accrual',
'date_from': datetime(2025, 1, 1),
'notes': '年假公司分配'
})
if row[2].value and int(row[2].value) != 0:
self.env['hr.leave.allocation'].create({
'holiday_status_id': holiday_status_id1.id,
'employee_id': employee_id.id,
'name': '补休',
'employee_ids': [(6, 0, [employee_id.id])],
'number_of_hours_display': int(row[2].value)
})
allocation_id = self.env['hr.leave.allocation'].search([('employee_id', '=', employee_id.id),
('holiday_status_id', '=', holiday_status_id1.id)])
if allocation_id:
allocation_id.write({
'number_of_hours': int(row[2].value),
})
else:
self.env['hr.leave.allocation'].create({
'holiday_status_id': holiday_status_id1.id,
'employee_id': employee_id.id,
'name': '补休',
'date_from': datetime(2025, 12, 1),
'employee_ids': [(6, 0, [employee_id.id])],
'number_of_hours_display': int(row[2].value)
})
@@ -4,7 +4,7 @@
<field name="name">yuthon.vacation.reports.tree</field>
<field name="model">yuthon.vacation.reports</field>
<field name="arch" type="xml">
<tree string="假期额度记录" editable="bottom" edit="0" default_order="vacation_date desc" js_class="custom_vacation_put_button">
<tree string="假期额度记录" editable="bottom" edit="0" default_order="vacation_date desc" js_class="custom_vacation_put_button" limit="10">
<field name="vacation_state" widget="badge" decoration-info="vacation_state == 'not_sent'"
decoration-success="vacation_state == 'confirmed'"/>
<field name="employee_id" options="{'no_open': True}"/>
@@ -452,7 +452,7 @@
<field name="name">考勤确认单台账</field>
<field name="res_model">yuthon.vacation.reports</field>
<field name="view_mode">tree,form</field>
<field name="context">{'search_default_group_by_employee_id': 1, 'search_default_group_by_vacation_year': True, 'search_default_group_by_vacation_month': True}</field>
<field name="context">{'search_default_group_by_employee_id': 1, 'search_default_group_by_vacation_month': True}</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_tree')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('yuthon_hr_attendance.view_yuthon_vacation_reports_form')})]"/>
@@ -50,6 +50,7 @@
<field name="work_end" invisible="1"/>
<field name="users_id"/>
<field name="reason_issuance"/>
<field name="company_id" invisible="1"/>
<field name="issues_result" invisible="is_issues == False"/>
<field name="service_type"/>
<field name="employee_id" widget="ztree_select"/>
@@ -91,13 +91,16 @@ class ProcessingOrderApproval(models.Model):
],
limit=1
)
else:
record.contract_id = False
if contract_id and contract_id.lease_id:
record.contract_id = contract_id.lease_id.id
else:
record.contract_id = None
record.contract_id = False
@api.onchange('repair_id')
def _onchange_repair_id(self):
def onchange_repair_id(self):
if self.repair_id:
self.property_id = self.repair_id.property_id
self.lessee_id = self.repair_id.lessee_id
@@ -143,16 +146,17 @@ class ProcessingOrderApproval(models.Model):
def end_approval(self):
for rec in self:
menu_id = self.env['ir.ui.menu'].search([('name', '=', '处理单')])
url = f'https://oa.thtzjt.com/web#id={self.id}&cids=2&action={menu_id.action.id}&model=processing.order.approval&view_type=list&menu_id={menu_id.id}'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa',
user_id=rec.applicant_id.employee_id.wecom_userid,
title="处理单",
description="你有一份已处理的报时报修",
url=url, btntxt="详细信息")
if rec.device_id:
rec.device_id.report_state = 'done'
else:
rec.repair_id.report_state = 'done'
if rec.processing_results in ['done', 'part']:
menu_id = self.env['ir.ui.menu'].search([('name', '=', '处理单审批')])
url = f'https://oa.thtzjt.com/web#id={self.id}&cids=2&action={menu_id.action.id}&model=processing.order.approval&view_type=list&menu_id={menu_id.id}'
if rec.device_id:
rec.device_id.report_state = 'done'
else:
rec.repair_id.report_state = 'done'
self.sudo().env["wecom.apps"].sync_send_message_textcard(category='oa',
user_id=rec.applicant_id.employee_id.wecom_userid,
title="处理单",
description="你有一份已处理的报时报修",
url=url, btntxt="详细信息")
@@ -20,7 +20,6 @@ class PropertyRentRelief(models.Model):
lessee_id = fields.Many2one('property.tenant.information', string="承租方")
contact = fields.Char(string="联系人")
phone = fields.Char( string="联系电话")
leader_id = fields.Many2one('res.users', string="负责人")
types_repairs = fields.Selection([('hydropower', '水电维修'), ('building', '门窗维修'), ('other', '其他维修')], string='维修类型')
problem_description = fields.Text(string="问题描述")
remake = fields.Text(string="备注")
@@ -33,7 +32,7 @@ class PropertyRentRelief(models.Model):
self_users_ids = fields.Many2many('res.users', string="当前经办人",
default=lambda self: [(6, 0, [self.env.user.id])])
create_time = fields.Date(string="填报日期", default=fields.Datetime.now)
processing_order_id = fields.Many2one('processing.order.approval', string="处理单流程")
processing_order_id = fields.Many2one('processing.order.approval', string="处理单")
def _get_default_name_title(self):
return self._description if self._description else self._name
@@ -73,8 +72,10 @@ class PropertyRentRelief(models.Model):
'repair_id': self.id,
'applicant_id': self.users_id.id,
'name': self.problem_description,
'problem_description': self.problem_description,
'code': self.env['ir.sequence'].next_by_code('property_report_repair_code'),
})
order_id.onchange_repair_id()
workflow_record_id = self.env['soong.workflow.record'].search([
('code', '=', self.code),
])
@@ -9,8 +9,8 @@
<button name="pull_accounts" type="object" string="生成应收" class="oe_highlight"/>
</header>
<field name="name"/>
<field name="applicant_id"/>
<field name="users_id"/>
<field name="applicant_id"/>
<field name="processing_results"/>
<field name="create_time"/>
</tree>
@@ -7,9 +7,9 @@
<tree string="报事报修(物业)">
<field name="name"/>
<field name="code"/>
<field name="users_id"/>
<field name="property_id"/>
<field name="types_repairs"/>
<field name="leader_id"/>
<field name="report_state"/>
<field name="create_time"/>
<button name="pull_order" string="提交" type="object" class="btn-primary"/>
@@ -11,7 +11,7 @@ class HrPayrollStructure(models.Model):
company_id = fields.Many2one('res.company', string="公司", default=lambda self: self.env.company)
yuthon_company = fields.Selection([('thtz', 'thtz')], default="thtz")
type_id = fields.Many2one('hr.payroll.structure.type', string="职级类型")
level_id = fields.Many2one('yuthon.payroll.type.setting', string="级别")
level_id = fields.Many2one('yuthon.payroll.type.setting', string="职级类别")
lv_name = fields.Char(related='level_id.name', string='级别名称', store=True)
name = fields.Char(string="职级名称")
sequence = fields.Char(string='级别序号', store=True)
@@ -256,6 +256,14 @@ class HrPayrollStructure(models.Model):
payroll.end_time = dec_2025_start
payroll.is_enable = False
def two_time(self):
dec_2025_start = datetime(2025, 11, 1).date()
payroll_ids = self.env["hr.payroll.structure"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for payroll in payroll_ids:
payroll.create_time = dec_2025_start
payroll.is_enable = True
def rank_log_time(self):
"""定时任务:根据日志记录的生效时间更新主模型字段值"""
# 出发一下
@@ -279,6 +287,15 @@ class HrPayrollStructure(models.Model):
if other_logs:
other_logs.sudo().write({'is_enable': False})
def action_yuthon_salary_wizard(self):
return {
"type": "ir.actions.act_window",
"name": "批量更新工资项",
"res_model": "yuthon.salary.wizard",
"view_mode": "form",
"target": "new",
}
class RankLogLine(models.Model):
_name = 'rank.log.line'
_description = '职级日志'
@@ -28,6 +28,24 @@
<field name="lv_name" column_invisible="1"/>
</xpath>
<xpath expr="//field[@name='name']" position="after">
<field name="base_salary"/>
<field name="rank_salary" groups="yuthon_salary.group_jtbb_user,yuthon_salary.group_lc_user"/>
<field name="position_subsidy" invisible="1"/>
<field name="integrated_subsidy" groups="yuthon_salary.group_wg_user"/>
<field name="communication_subsidy" groups="yuthon_salary.group_jtbb_user,yuthon_salary.group_wg_user"/>
<field name="position_salary" groups="yuthon_salary.group_jtbb_user,yuthon_salary.group_wg_user"/>
<field name="advance_performance_bonuses" groups="yuthon_salary.group_jtbb_user, yuthon_salary.group_lc_user"/>
<field name="create_time"/>
<field name="end_time"/>
<field name="is_enable"/>
</xpath>
</field>
</record>
<record id="hr_payroll_structure_history_tree" model="ir.ui.view">
<field name="name">hr.payroll.structure.history.tree</field>
<field name="model">hr.payroll.structure</field>
<field name="arch" type="xml">
<tree string="历史职级">
<field name="base_salary"/>
<field name="rank_salary" groups="yuthon_salary.group_jtbb_user"/>
<field name="position_subsidy" groups="yuthon_salary.group_lc_user"/>
@@ -38,7 +56,7 @@
<field name="create_time"/>
<field name="end_time"/>
<field name="is_enable"/>
</xpath>
</tree>
</field>
</record>
<record id="hr_payroll_structure_inherit_form" model="ir.ui.view">
@@ -113,7 +131,16 @@
<field name="name">职级</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">tree,form,search</field>
<field name="domain">[('is_enable', '=', True)]</field>
<field name="context">{'search_default_is_enable':1}</field>
</record>
<record id="action_view_hr_payroll_structure_list_form1" model="ir.actions.act_window">
<field name="name">历史职级</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">tree,form,search</field>
<field name="domain">[('is_enable', '=', False)]</field>
<field name="context">{'search_default_group_lv_id': 1}</field>
<field name="view_id" ref="hr_payroll_structure_history_tree"/>
</record>
<record id="all_paroll_write_salary" model="ir.actions.server">
<field name="name">批量更新职级类型</field>
@@ -178,4 +205,11 @@
<field name="state">code</field>
<field name="code">action = model.onetime()</field>
</record>
<record id="all_data_write_salary" model="ir.actions.server">
<field name="name">批量导入职级</field>
<field name="model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="binding_model_id" ref="hr_payroll.model_hr_payroll_structure"/>
<field name="state">code</field>
<field name="code">action = model.action_yuthon_salary_wizard()</field>
</record>
</odoo>
+12 -51
View File
@@ -60,54 +60,15 @@ class YuthonPayrollWizard(models.Model):
})
def yuthon_payroll_lc_data(self, row):
# 1. 获取传入的行数据
type_name = row[0].value
base_salary = float(row[1].value) if row[1].value else 0.0
rank_salary = float(row[2].value) if row[2].value else 0.0
advance_performance_bonuses = float(row[3].value) if row[3].value else 0.0
# 2. 查询薪资结构类型
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', type_name)], limit=1)
if not type_id:
# 可选:添加日志提示类型不存在
self.env.user.notify_warning(message=f"未找到薪资结构类型:{type_name}")
return
# 3. 查找“天河粮储”公司的任意hr.payroll.structure记录
# 先找到公司(根据公司名称搜索,可替换为公司编码更精准)
target_company = self.env['res.company'].search([('name', '=', '天河粮储')], limit=1)
if not target_company:
self.env.user.notify_warning(message="未找到名称为「天河粮储」的公司")
return
source_structure = self.env['hr.payroll.structure'].search(
[('company_id.name', '=', target_company.id)],
limit=1 # 取任意一条
)
copied_salary_rules = []
source_salary_rules = source_structure.rule_ids
for rule in source_salary_rules:
rule_vals = rule.copy_data()[0]
for field in ['id', 'create_uid', 'create_date', 'write_uid', 'write_date']:
rule_vals.pop(field, None)
copied_salary_rules.append((0, 0, rule_vals))
new_structure = self.env['hr.payroll.structure'].create({
'name': type_name,
'type_id': type_id.id,
'company_id': target_company.id,
'rule_ids': copied_salary_rules,
})
salary_rule_mapping = {
'基本工资': base_salary,
'职级工资': rank_salary,
'预发绩效奖金': advance_performance_bonuses
}
for rule_name, target_value in salary_rule_mapping.items():
target_rule = new_structure.rule_ids.search(
[('name', '=', rule_name), ('structure_id', '=', new_structure.id)],
limit=1
)
if target_rule:
target_rule.write({'amount_fix': target_value})
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', row[0].value)], limit=1)
base_salary = row[1].value
rank_salary = row[2].value
advance_performance_bonuses = row[3].value
payroll_id = self.env['hr.payroll.structure'].search(
[('type_id', '=', type_id.id)])
if payroll_id:
payroll_id.write({
'base_salary': base_salary,
'rank_salary': rank_salary,
'advance_performance_bonuses': advance_performance_bonuses,
})
+53 -25
View File
@@ -81,37 +81,65 @@ class YuthonSalaryWizard(models.Model):
}
salary_name.create(salary_date)
struct_id.write({'default_struct_id': structure_id.id})
def salary_lc_data(self, row, salary_dates):
salary_name = self.env['hr.salary.rule']
text = row[2].value
# def salary_lc_data(self, row, salary_dates):
# salary_name = self.env['hr.salary.rule']
# text = row[2].value
# struct_id = self.env['hr.payroll.structure.type'].search([
# ('name', '=', text),
# ])
# if not struct_id:
# struct_id = self.env['hr.payroll.structure.type'].create({
# 'name': text,
# 'sequence': row[0].value})
# structure_id = self.env['hr.payroll.structure'].search([('name', '=', text)])
# level_id = self.env['yuthon.payroll.type.setting'].search([('name', '=', row[1].value)],
# )
# if not structure_id:
# structure_id = self.env['hr.payroll.structure'].create({
# 'name': text,
# 'level_id':level_id.id,
# 'type_id':struct_id.id,
# 'sequence': row[0].value,})
# struct_id.write({'default_struct_id': structure_id.id})
# for salary, r in zip(salary_dates, row[3:11]):
# name_pinyin = pinyin(salary.value, style=Style.FIRST_LETTER)
# abbreviation = "".join([p[0][0] for p in name_pinyin]).upper()
# salary_date = {
# 'sequence': row[0].value,
# 'name': salary.value, # 姓名
# 'struct_id': structure_id.id,
# 'amount_select': 'fix',
# 'amount_fix': r.value,
# }
# salary_name.create(salary_date)
def salary_lc_data(self, row, rx):
text = row[0].value
company_id = self.env['res.company'].search([('name', '=', '天河粮储')], limit=1)
level_id = self.env['yuthon.payroll.type.setting'].search([('name', '=', row[4].value),
('company_id', '=', company_id.id)
])
if not level_id:
level_id = self.env['yuthon.payroll.type.setting'].create({
'sequence': rx,
'name': row[4].value,
'company_id': company_id.id,
})
struct_id = self.env['hr.payroll.structure.type'].search([
('name', '=', text),
])
if not struct_id:
struct_id = self.env['hr.payroll.structure.type'].create({
'name': text,
'sequence': row[0].value})
structure_id = self.env['hr.payroll.structure'].search([('name', '=', text)])
level_id = self.env['yuthon.payroll.type.setting'].search([('name', '=', row[1].value)],
)
if not structure_id:
structure_id = self.env['hr.payroll.structure'].create({
'name': text,
'level_id':level_id.id,
'type_id':struct_id.id,
'sequence': row[0].value,})
struct_id.write({'default_struct_id': structure_id.id})
for salary, r in zip(salary_dates, row[3:11]):
name_pinyin = pinyin(salary.value, style=Style.FIRST_LETTER)
abbreviation = "".join([p[0][0] for p in name_pinyin]).upper()
salary_date = {
'sequence': row[0].value,
'name': salary.value, # 姓名
'struct_id': structure_id.id,
'amount_select': 'fix',
'amount_fix': r.value,
}
salary_name.create(salary_date)
'sequence': rx})
self.env['hr.payroll.structure'].create({
'name': text,
'type_id': struct_id.id,
'level_id': level_id.id,
'company_id': company_id.id,
'create_time': datetime(2025, 11, 1).date(),
'sequence': rx, })
def salary_wg_data(self, row, salary_dates):
salary_name = self.env['hr.salary.rule']
+6
View File
@@ -397,6 +397,12 @@
parent="human_payroll_items_root_board"
action="yuthon_salary.action_view_hr_payroll_structure_list_form"
sequence="15"/>
<menuitem id="human_resources_salary_root_board2"
name="历史职级"
parent="human_payroll_items_root_board"
action="yuthon_salary.action_view_hr_payroll_structure_list_form1"
groups="yuthon_salary.group_lc_user"
sequence="17"/>
<menuitem id="hr_payroll_common_board"
name="常用项"
parent="human_payroll_items_root_board"