!7166 添加功能

Merge pull request !7166 from 李鹏宇/dev_zhou
This commit is contained in:
李鹏宇
2025-12-20 11:14:04 +00:00
committed by Gitee
19 changed files with 173 additions and 80 deletions
@@ -244,7 +244,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">soong.workflow.record</field>
<field name="view_mode">tree,form,search</field>
<field name="context">{'search_default_group_by_group_soong_state': True,}</field>
<field name="context">{'search_default_group_by_group_soong_state': True, 'search_default_group_by_group_by_workflow_id': True}</field>
<field name="domain">[('reclaim_state', '=', False)]</field>
<field name="search_view_id" ref="soong_workflow_record_search1"/>
<field name="view_id" ref="soong_workflow_record_tree"/>
+18
View File
@@ -314,6 +314,8 @@ class HolidaysRequestBatch(models.Model):
is_issues = fields.Boolean(string='是否上会')
work_end = fields.Boolean(string="结束")
issues_result = fields.Html(string="会议结果")
entrusted_agent_id = fields.Many2one('res.users', string="委托代理人")
is_entrusted = fields.Boolean(string="是否生成工作流委托")
leave_by_hour = fields.Boolean(string='请假单位(小时)', default=False)
leave_by_day = fields.Boolean(string='请假单位(天)', default=True)
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
@@ -357,6 +359,22 @@ class HolidaysRequestBatch(models.Model):
# 提交
def action_submit(self):
if self.is_entrusted:
leave_batch_model = self.env['ir.model'].search(
[('model', '=', 'hr.leave.batch')],
limit=1
)
entrust_vals = {
'model_ids': [(6, 0, [leave_batch_model.id])],
'entrust_user_id': self.users_id.id,
'entrust_user_id2': self.entrusted_agent_id.id,
'is_expiration_date': True,
'start_date': fields.Date.today(),
'end_date': False,
'entrust_notice': True,
}
self.env['soong.workflow.entrust'].create(entrust_vals)
self.leave_ids.action_validate()
self.hour_leave_ids.action_validate()
"""提交请假申请,区分年假和其他假期处理"""
+3 -1
View File
@@ -44,6 +44,9 @@
<field name="is_back" invisible="1"/>
<field name="name"/>
<field name="users_id" options="{'no_create': True}"/>
<field name="department_id" invisible="1"/>
<field name="entrusted_agent_id" domain="[('employee_id.department_id', '=', department_id)]" />
<field name="is_entrusted" invisible="not entrusted_agent_id"/>
<field name="days" invisible="1"/>
<field name="employee_id" invisible="1" force_save="1"/>
<field name="text"/>
@@ -239,7 +242,6 @@
</form>
</field>
<group>
<field name="department_id" invisible="1"/>
<field name="user_role_id" invisible="1"/>
<field name="is_issues" invisible="1"/>
<field name="start_date" invisible="1"/>
+11 -10
View File
@@ -814,16 +814,17 @@ class HrAttendance(models.Model):
if is_executive:
domain = [('current_data', '=', current_date)]
attendances = self.env['hr.attendance'].search(domain)
attended_employee_ids = attendances.mapped('employee_id')
for employee in attended_employee_ids:
if is_check_in:
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
if not is_card:
self.card_in_comment(employee, '行政班次')
else:
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
if not is_card:
self.card_out_comment(employee, '行政班次')
if self._process_shift_days(current_date): # 如果是工作日则提醒
attended_employee_ids = attendances.mapped('employee_id')
for employee in attended_employee_ids:
if is_check_in:
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_in', '!=', False), ('current_data', '=', current_date)], limit=1)
if not is_card:
self.card_in_comment(employee, '行政班次')
else:
is_card = self.env['hr.attendance'].search([('employee_id', '=', employee.id), ('check_out', '!=', False), ('current_data', '=', current_date)], limit=1)
if not is_card:
self.card_out_comment(employee, '行政班次')
else:
slot_start = datetime.combine(current_date, datetime.min.time())
slot_end = datetime.combine(current_date + timedelta(days=1), datetime.min.time())
@@ -70,13 +70,15 @@ class ProcessingOrderApproval(models.Model):
name_title = fields.Char(default=_get_default_name_title)
@api.depends("company_id")
@api.depends("company_id", "repair_id", "device_id", "property_id")
def _compute_name(self):
self.name = False
if self.repair_id:
self.name = self.property_id.name + '-处理单'
if self.device_id:
self.name = self.device_id.name + '-处理单'
for record in self:
if record.repair_id and record.property_id:
record.display_name = f"{record.property_id.name}-处理单"
elif record.device_id:
record.display_name = f"{record.device_id.name}-处理单"
else:
record.display_name = False
@api.depends('property_id')
def _compute_contract_id(self):
@@ -10,6 +10,7 @@
<field name="software_processing_id"/>
<field name="report_state"/>
<field name="create_time"/>
<button name="pull_order" string="提交" type="object" class="btn-primary"/>
</tree>
</field>
</record>
@@ -12,6 +12,7 @@
<field name="leader_id"/>
<field name="report_state"/>
<field name="create_time"/>
<button name="pull_order" string="提交" type="object" class="btn-primary"/>
</tree>
</field>
</record>
@@ -262,6 +262,8 @@ class MeterArchivesLine(models.Model):
type = fields.Selection([("public", "公共"), ("fees", "收费")], string="类型")
employee_ids = fields.Many2many("hr.employee", string="抄表人")
remarks = fields.Text(string="备注")
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="yes", string="有无线损")
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
archives_state = fields.Selection([("stop", "停用"), ("use", "正常"), ("rent", "出租")], string="状态", default="use",)
state = fields.Selection([("reading", "已抄"), ("unreading", "未抄")], string="抄表状态", default="unreading",)
maximum_count = fields.Integer(string="最大位数")
@@ -227,6 +227,8 @@ class MeterWaterLine(models.Model):
remarks = fields.Text(string='备注')
employee_ids = fields.Many2many('hr.employee', string='抄表人')
maximum_count = fields.Integer(string='最大位数')
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="yes", string="有无线损")
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
is_push = fields.Boolean(string='推送', default=False)
@api.model_create_multi
@@ -118,6 +118,8 @@
<field name="last_meter" string="上次抄表日期"/>
<field name="last_dosage" string="上次用量"/>
<field name="is_push"/>
<field name="is_fix_loss" column_invisible="1"/>
<field name="is_fix_price" column_invisible="1"/>
<field name="number" column_invisible="1"/>
<field name="sequence" column_invisible="1"/>
<field name="meter_date_month" column_invisible="1"/>
@@ -120,6 +120,8 @@
<field name="last_meter" string="上次抄表日期"/>
<field name="last_dosage" string="上次用量"/>
<field name="is_push"/>
<field name="is_fix_loss" column_invisible="1"/>
<field name="is_fix_price" column_invisible="1"/>
<field name="number" column_invisible="1"/>
<field name="sequence" column_invisible="1"/>
<field name="initial_value" column_invisible="1"/>
@@ -36,6 +36,17 @@ class ElectricWaterWizard(models.TransientModel):
else:
contract_line = False
electric_id = self.env['property.electric.fee.line'].search([
('property_meter_archives_id', '=', meter.id),
('contract_id', '!=', False),
], limit=1)
if electric_id:
is_fix_loss = electric_id.is_fix_loss
is_fix_price = electric_id.is_fix_price
else:
is_fix_loss = 'yes'
is_fix_price = 'no'
# 查找上个月的记录
# 查找上个月的记录,上次用量,上次读数,上次抄表日期
last_month_line = meter.line_ids.search([('meter_date', '<', self.push_date)]).sorted('meter_date')[-1]
@@ -46,6 +57,8 @@ class ElectricWaterWizard(models.TransientModel):
meter.line_ids.create({
'archives_id': meter.id,
'is_acc': is_acc,
'is_fix_loss':is_fix_loss,
'is_fix_price':is_fix_price,
'last_meter': last_month_line.last_meter,
'last_read': last_month_line.last_read,
'last_dosage': last_month_line.last_dosage,
@@ -87,6 +100,16 @@ class ElectricWaterWizard(models.TransientModel):
else:
contract_line = False
water_id = self.env['property.water.fee.line'].search([('property_meter_water_id', '=', water.id),
('contract_id', '!=', False),
], limit=1)
if water_id:
is_fix_loss = water_id.is_fix_loss
is_fix_price = water_id.is_fix_price
else:
is_fix_loss = 'yes'
is_fix_price = 'no'
# 查找上个月的记录,上次用量,上次读数,上次抄表日期
last_month_line = water.line_ids.search([('meter_date', '<', self.push_date)]).sorted('meter_date')[-1]
# 如果当前数据不存在,则新建任务,按照天的纬度
@@ -94,6 +117,8 @@ class ElectricWaterWizard(models.TransientModel):
if not self_month_line:
water.line_ids.create({
'water_id': water.id,
'is_fix_loss': is_fix_loss,
'is_fix_price': is_fix_price,
'last_meter': last_month_line.last_meter,
'last_read': last_month_line.last_read,
'last_dosage': last_month_line.last_dosage,
+1 -2
View File
@@ -33,7 +33,6 @@ class MeterPriceWizard(models.TransientModel):
('select_time', '=', str(last_month)),
('meter_type', '=', 'electric')
], limit=1)
# 3. 赋值价格
self.price = logs_id.price if logs_id else 0.0
self.line_loss = logs_id.line_loss if logs_id else 0.0
@@ -74,7 +73,7 @@ class MeterPriceWizard(models.TransientModel):
valid.write({
'unit': unit,
'line_loss': self.line_loss
'line_loss': self.line_loss if valid.is_fix_loss == 'yes' else 0
})
valid.onchange_receivables()
+1 -1
View File
@@ -75,7 +75,7 @@ class WaterPriceWizard(models.TransientModel):
valid.write({
'unit': unit,
'line_loss': self.line_loss,
'line_loss': self.line_loss if valid.is_fix_loss == 'yes' else 0
})
valid.onchange_receivables()
@@ -2421,15 +2421,14 @@ class PropertyWaterFeeLine(models.Model):
start_date = fields.Date(related='contract_id.term_start_time', string="开始日期")
end_date = fields.Date(related='contract_id.term_end_time', string="结束日期")
unit_price = fields.Float(string='固定单价', digits=(16, 4))
line_loss = fields.Float(string='线损')
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="yes", string="有无线损")
is_fix_price = fields.Selection([('yes', '是'), ('no', '否')], default="no", string="是否固定单价")
epitope_values_id = fields.Many2one(related='property_meter_water_id.epitope_values_id', string="表位置")
@api.constrains('line_loss')
def _check_line_loss(self):
for rec in self:
if rec.property_meter_water_id.line_ids:
for line in rec.property_meter_water_id.line_ids:
line.line_loss = rec.line_loss
@api.onchange('is_fix_price')
def _onchange_is_fix_price(self):
if self.is_fix_price == 'no':
self.unit_price = 0
class PropertyElectricFeeLine(models.Model):
@@ -2443,16 +2442,14 @@ class PropertyElectricFeeLine(models.Model):
start_date = fields.Date(related='contract_id.term_start_time', string="开始日期")
end_date = fields.Date(related='contract_id.term_end_time', string="结束日期")
unit_price = fields.Float(string='固定单价', digits=(16, 4))
line_loss = fields.Float(string='线损')
is_fix_loss = fields.Selection([('yes', '有'), ('no', '无')], default="no", string="有无线损")
is_fix_price = fields.Selection([('yes', '是'),('no', '否')], default="no", string="是否固定单价")
epitope_values_id = fields.Many2one(related='property_meter_archives_id.epitope_values_id', string="表位置")
@api.constrains('line_loss')
def _check_line_loss(self):
for rec in self:
if rec.property_meter_archives_id.line_ids:
for line in rec.property_meter_archives_id.line_ids:
line.line_loss = rec.line_loss
@api.onchange('is_fix_price')
def _onchange_is_fix_price(self):
if self.is_fix_price == 'no':
self.unit_price = 0
class PropertyOtherFeeLine(models.Model):
_name = 'property.other.fee.line'
@@ -279,8 +279,9 @@
<field name="unit_number"/>
<field name="property_meter_water_id" options="{'no_open': True}"/>
<field name="rate"/>
<field name="line_loss"/>
<field name="unit_price"/>
<field name="is_fix_loss"/>
<field name="is_fix_price"/>
<field name="unit_price" readonly="is_fix_price == 'no'"/>
<field name="start_date"/>
<field name="end_date"/>
</tree>
@@ -294,8 +295,9 @@
<field name="unit_number"/>
<field name="property_meter_archives_id" options="{'no_open': True}"/>
<field name="rate"/>
<field name="line_loss"/>
<field name="unit_price"/>
<field name="is_fix_loss"/>
<field name="is_fix_price"/>
<field name="unit_price" readonly="is_fix_price == 'no'"/>
<field name="start_date"/>
<field name="end_date"/>
</tree>
@@ -819,8 +821,9 @@
<field name="unit_number"/>
<field name="property_meter_water_id" options="{'no_open': True}"/>
<field name="rate"/>
<field name="line_loss"/>
<field name="unit_price"/>
<field name="is_fix_loss"/>
<field name="is_fix_price"/>
<field name="unit_price" readonly="is_fix_price == 'no'"/>
<field name="start_date"/>
<field name="end_date"/>
</tree>
@@ -833,8 +836,9 @@
<field name="epitope_values_id"/>
<field name="unit_number"/>
<field name="property_meter_archives_id" options="{'no_open': True}"/>
<field name="rate"/>
<field name="line_loss"/>
<field name="is_fix_loss"/>
<field name="is_fix_price"/>
<field name="unit_price" readonly="is_fix_price == 'no'"/>
<field name="unit_price"/>
<field name="start_date"/>
<field name="end_date"/>
@@ -1,8 +1,7 @@
from odoo import api, fields, models, _
import re
from pypinyin import pinyin, Style
from datetime import date
from datetime import date, datetime
class HrPayrollStructure(models.Model):
@@ -18,7 +17,7 @@ class HrPayrollStructure(models.Model):
sequence = fields.Char(string='级别序号', store=True)
create_time = fields.Date(string="生效日期", default=fields.Date.today())
end_time = fields.Date(string="失效日期")
is_enable = fields.Boolean(string="启用", default=True)
is_enable = fields.Boolean(string="启用", compute= "_compute_is_enable", store=True)
currency_id = fields.Many2one("res.currency", string="货币", required=True, default=lambda self: self.env.company.currency_id)
base_salary = fields.Monetary(string="基本工资", currency_field="currency_id")
rank_salary = fields.Monetary(string="职级工资", currency_field="currency_id")
@@ -29,6 +28,17 @@ class HrPayrollStructure(models.Model):
advance_performance_bonuses = fields.Monetary(string="预发绩效奖金", currency_field="currency_id")
renk_log_ids = fields.One2many("rank.log.line", "structure_id", string="职级日志明细行")
@api.depends('create_time', 'end_time')
def _compute_is_enable(self):
today = fields.Date.today()
for record in self:
if not record.create_time:
record.is_enable = False
elif not record.end_time:
record.is_enable = record.create_time <= today
else:
record.is_enable = record.create_time <= today <= record.end_time
@api.model
def read_group(self, domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True):
res = super(HrPayrollStructure, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby,
@@ -196,6 +206,7 @@ class HrPayrollStructure(models.Model):
for rule in payroll.rule_ids:
rule.sudo().unlink()
def update_payroll_items(self):
payroll_ids = self.env["hr.payroll.structure"].browse(
self._context.get('active_ids', self._context.get('active_id')))
@@ -238,14 +249,12 @@ class HrPayrollStructure(models.Model):
payroll.renk_log_ids.unlink()
def onetime(self):
dec_2025_start = datetime(2025, 10, 31).date()
payroll_ids = self.env["hr.payroll.structure"].browse(
self._context.get('active_ids', self._context.get('active_id')))
for payroll in payroll_ids:
create_time = payroll.renk_log_ids[-1].effective_date
payroll.write({
'create_time': create_time,
})
payroll.end_time = dec_2025_start
payroll.is_enable = False
def rank_log_time(self):
"""定时任务:根据日志记录的生效时间更新主模型字段值"""
@@ -100,6 +100,7 @@
<field name="arch" type="xml">
<search string="职级查询">
<field name="name"/>
<filter name="is_enable" string="启用" domain="[('is_enable', '=', True)]"/>
<group expand="0">
<filter name="group_date" string="查询年月" context="{'group_by': 'create_time'}"/>
<filter name="group_lv_name" string="级别" context="{'group_by': 'lv_name'}"/>
@@ -112,7 +113,7 @@
<field name="name">职级</field>
<field name="res_model">hr.payroll.structure</field>
<field name="view_mode">tree,form,search</field>
<!-- <field name="context">{'group_by_no_leaf':1,'group_by':[]}</field>-->
<field name="context">{'search_default_is_enable':1}</field>
</record>
<record id="all_paroll_write_salary" model="ir.actions.server">
<field name="name">批量更新职级类型</field>
+52 -27
View File
@@ -24,19 +24,7 @@ class YuthonPayrollWizard(models.Model):
sh = book.sheet_by_index(0)
for rx in range(1, sh.nrows):
row = sh.row(rx)
self.yuthon_payroll_wg_data(row)
# if sh.row(1)[6].value == 'thtz':
# salary_rule_model = self.env['hr.salary.rule']
# all_rules = salary_rule_model.search([])
# all_rules.unlink()
# for rx in range(1, sh.nrows):
# row = sh.row(rx)
# if row[6].value == 'thtz':
# self.yuthon_payroll_tt_data(row)
# elif row[6].value == 'thwg':
# self.yuthon_payroll_wg_data(row)
# elif row[6].value == 'thlc':
# self.yuthon_payroll_lc_data(row)
self.yuthon_payroll_lc_data(row)
def yuthon_payroll_tt_data(self, row):
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', row[0].value)], limit=1)
@@ -72,17 +60,54 @@ class YuthonPayrollWizard(models.Model):
})
def yuthon_payroll_lc_data(self, row):
type_id = self.env['hr.payroll.structure.type'].search([('name', '=', row[0].value)], limit=1)
base_salary = row[1].value
position_subsidy = row[2].value
position_salary = row[3].value
advance_performance_bonuses = row[4].value
payroll_id = self.env['hr.payroll.structure'].search(
[('type_id', '=', type_id.id)])
if payroll_id:
payroll_id.write({
'base_salary': base_salary,
'position_salary': position_salary,
'position_subsidy': position_subsidy,
'advance_performance_bonuses': advance_performance_bonuses,
})
# 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})