!6081 添加功能

Merge pull request !6081 from 李鹏宇/dev_zhou
This commit is contained in:
李鹏宇
2025-10-30 09:22:53 +00:00
committed by Gitee
12 changed files with 256 additions and 19 deletions
+2
View File
@@ -49,6 +49,7 @@
'views/yuthon_duty_setting_views.xml',
'views/yuthon_duty_plan_views.xml',
'views/yuthon_abnormal_approval_views.xml',
'views/expatriation_approval.xml',
'views/yuthon_abnormal_setting_views.xml',
'views/yuthon_adjustments_approval_views.xml',
'views/yuthon_shift_approval_views.xml',
@@ -59,6 +60,7 @@
'views/hr_attendance_month_views.xml',
'views/wifi_message_view.xml',
'views/hr_attendance_portal_templates.xml',
'views/meal_approval.xml',
'wizard/hr_attendance_month_wizard_views.xml',
'wizard/yuthon_delete_planning_wizard_views.xml',
'wizard/attendance_controls_wizard.xml',
@@ -8,6 +8,22 @@
<field name="company_id" eval="False"/>
</record>
<record id="seq_expatriation_approval" model="ir.sequence">
<field name="name">外派申请序列号</field>
<field name="code">expatriation_approval</field>
<field name="prefix">WP%(y)s%(month)s%(day)s</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<record id="seq_meal_approval" model="ir.sequence">
<field name="name">报餐申请序列号</field>
<field name="code">meal_approval</field>
<field name="prefix">ME%(y)s%(month)s%(day)s</field>
<field name="padding">3</field>
<field name="company_id" eval="False"/>
</record>
<record id="seq_go_approval" model="ir.sequence">
<field name="name">外出申请序列号</field>
<field name="code">go_approval</field>
+2
View File
@@ -27,6 +27,8 @@ from . import hr_attendance_wechat
from . import hr_attendance_detail_wechat
from . import hr_attendance_month
from . import wifi_message
from . import expatriation_approval
from . import meal_approval
# from odoo.tools import SQL
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, tools, _
from datetime import datetime, time, timedelta
from odoo.exceptions import UserError
class ExpatriationApproval(models.Model):
_name = 'expatriation.approval'
_inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin']
_description = '外派驻点审批'
name = fields.Char(string="标题", compute='_compute_name')
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('overtime_approval'))
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
expatriates_ids = fields.Many2many('hr.employee', string="外派人员")
start_date = fields.Date(string="开始日期")
end_date = fields.Date(string="结束日期")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
active = fields.Boolean('Active', default=True, tracking=True)
reason_application = fields.Text(string="外派事由")
document_ids = fields.Many2many('ir.attachment', string="附件")
work_end = fields.Boolean(string="结束")
is_issues = fields.Boolean(string='是否上会')
issues_result = fields.Html(string="会议结果")
related_issues_id = fields.Many2one('issue.library', string="关联议题")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
@api.onchange('is_issues')
def _onchange_is_issues(self):
if self.is_issues:
issue_id = self.env['issue.library'].create({'name': self.name, 'is_invisible_workflow': True})
self.related_issues_id = issue_id.id
self.env['issue.library.approval.line'].create({
'issue_library_id': issue_id.id,
'workflow_name': self.name,
'approval_type': self.workflow_id.name,
'res_model': self._name,
'res_id': self.id,
'code': self.code,
'approval_date': fields.Datetime.now(),
})
@@ -23,6 +23,7 @@ class HrAttendance(models.Model):
is_early_card = fields.Boolean(string="早退", group_operator='count_true')
is_late_card = fields.Boolean(string="迟到", group_operator='count_true')
is_abnormal = fields.Boolean(string="异常", group_operator='count_true')
is_expatriation = fields.Boolean(string="外派", group_operator='count_true')
is_approval_no = fields.Boolean()
is_approval_early = fields.Boolean()
is_approval_late = fields.Boolean()
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, tools, _
from datetime import datetime, time, timedelta
from odoo.exceptions import UserError
class MealApproval(models.Model):
_name = 'meal.approval'
_description = '报餐单'
_inherit = ['mail.thread.main.attachment', 'mail.activity.mixin', 'soong.workflow.mixin']
name = fields.Char(string="标题", compute='_compute_name')
code = fields.Char(string="编号", default=lambda self: self.env['ir.sequence'].next_by_code('meal_approval'))
department_id = fields.Many2one(related='users_id.employee_id.department_id', string="部门")
users_id = fields.Many2one('res.users', string="申请人", default=lambda self: self.env.user.id)
meal_date = fields.Date(string="用餐日期", default=lambda self: fields.Date.today())
reason_application = fields.Text(string="事由")
urgency_level = fields.Selection([('normal', '普件'), ('urgent', '急件'), ('emergency', '特急件')], string='紧急度',
default='normal')
work_end = fields.Boolean(string="结束")
def _get_default_name_title(self):
return self._description if self._description else self._name
name_title = fields.Char(default=_get_default_name_title)
self_users_ids = fields.Many2many('res.users', string="当前经办人", default=lambda self: [(6, 0, [self.env.user.id])])
@@ -72,3 +72,5 @@ access_applet_security,applet.security,model_applet_security,base.group_user,1,1
access_applet_security_setting,applet.security.setting,model_applet_security_setting,base.group_user,1,1,1,1
access_wifi_message,wifi.message,model_wifi_message,base.group_user,1,1,1,1
access_planning_slot_update_display_name_wizard,access_planning_slot_update_display_name_wizard,model_planning_slot_update_display_name_wizard,base.group_user,1,1,1,1
access_expatriation_approval,expatriation.approval,model_expatriation_approval,base.group_user,1,1,1,1
access_meal_approval, meal.approval,model_meal_approval,base.group_user,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
72
73
74
75
76
@@ -216,4 +216,8 @@
parent="menu_hr_attendance_approval_request" sequence="10" action="approval_request_remove_holiday"/>
<menuitem id="menu_hr_attendance_remove_card" name="补卡申请"
parent="menu_hr_attendance_approval_request" sequence="12" action="approval_request_card"/>
<menuitem id="menu_hr_attendance_expatriation" name="外派申请"
parent="menu_hr_attendance_approval_request" sequence="14" action="view_expatriation_approval_action"/>
<menuitem id="menu_hr_attendance_meal" name="报餐申请"
parent="menu_hr_attendance_approval_request" sequence="16" action="view_meal_approval_action"/>
</odoo>
@@ -0,0 +1,77 @@
<odoo>
<record id="view_expatriation_approval_tree" model="ir.ui.view">
<field name="name">expatriation.approval.tree</field>
<field name="model">expatriation.approval</field>
<field name="arch" type="xml">
<tree string="外派驻点审批">
<field name="name"/>
<field name="users_id"/>
<field name="expatriates_ids" widget="many2many_tags"/>
<field name="start_date"/>
<field name="end_date"/>
</tree>
</field>
</record>
<record id="view_expatriation_approval_form" model="ir.ui.view">
<field name="name">expatriation.approval.form</field>
<field name="model">expatriation.approval</field>
<field name="arch" type="xml">
<form string="外派驻点审批">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
invisible="urgency_level != 'emergency'"/>
<group col="4">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group>
<field name="is_issues"/>
</group>
<group>
<field name="related_issues_id" invisible="is_issues == False"/>
</group>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<div class="oe_title">
<label for="name" placeholder="请输入标题"/>
<h1>
<field name="name" required="1"/>
</h1>
</div>
<group>
<field name="users_id"/>
<field name="expatriates_ids" widget="many2many_tags"/>
<field name="work_end" invisible="1"/>
<label for="start_date"/>
<div class="d-inline-flex w-100">
<field name="start_date" string='外派日期' class="me-2"
style="max-width: 10rem !important;"/>至
<field name="end_date" string=" " class="ms-2"
style="max-width: 10rem !important;"/>
</div>
<field name="reason_application"/>
<field name="issues_result" invisible="is_issues == False"/>
<field name="self_users_ids" invisible="1"/>
<field name="document_ids" widget="preview_many2many"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_expatriation_approval_action" model="ir.actions.act_window">
<field name="name">外派申请</field>
<field name="res_model">expatriation.approval</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -0,0 +1,57 @@
<odoo>
<record id="view_meal_approval_tree" model="ir.ui.view">
<field name="name">meal.approval.tree</field>
<field name="model">meal.approval</field>
<field name="arch" type="xml">
<tree string="报餐单">
<field name="name"/>
<field name="users_id"/>
<field name="meal_date"/>
</tree>
</field>
</record>
<record id="view_meal_approval_form" model="ir.ui.view">
<field name="name">meal.approval.form</field>
<field name="model">meal.approval</field>
<field name="arch" type="xml">
<form string="报餐单">
<sheet>
<widget name="web_ribbon" title="普件" bg_color="text-bg-success"
invisible="urgency_level != 'normal'"/>
<widget name="web_ribbon" title="急件" bg_color="text-bg-warning"
invisible="urgency_level != 'urgent'"/>
<widget name="web_ribbon" title="特级" bg_color="text-bg-danger"
invisible="urgency_level != 'emergency'"/>
<group col="4">
<group>
<field name="code" string="流水号" readonly="1"/>
</group>
<group>
<field name="urgency_level" readonly="1"/>
</group>
<group/>
<group/>
</group>
<div class="col-12 text-center">
<h1>
<field name="name_title" readonly="1"/>
</h1>
</div>
<group>
<field name="name"/>
<field name="users_id"/>
<field name="work_end" invisible="1"/>
<field name="meal_date" required="1"/>
<field name="reason_application"/>
<field name="self_users_ids" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_meal_approval_action" model="ir.actions.act_window">
<field name="name">报餐申请</field>
<field name="res_model">meal.approval</field>
<field name="view_mode">tree,form</field>
</record>
</odoo>
@@ -92,7 +92,6 @@ class ClickReconciliationWizard(models.Model):
modify = self.env['receivable.modify.line'].search([
('receivable_id', '=', rec.id),
('bank_id', '=', statements[0].id),
('not_collected', '=', rec.rent),
('is_write', '=', True),
('is_penalty', '=', False),
('reconciliation_date', '=', (fields.Datetime.from_string(statements[0].start_time) - timedelta(hours=8)).date()),
@@ -102,7 +101,6 @@ class ClickReconciliationWizard(models.Model):
self.env['receivable.modify.line'].create({
'is_write': True,
'is_penalty': False,
'not_collected': rec.rent,
'bank_id': statements[0].id,
'reconciliation_date': (fields.Datetime.from_string(statements[0].start_time) - timedelta(hours=8)).date(),
'receivable_id': rec.id,
@@ -296,16 +296,27 @@ class PropertyReconciliationWizard(models.Model):
def create_reconciliation_vals(self):
"""
按已生成的明细行 分配金额
按已生成的明细行 分配金额(优先处理押金)
:return:
"""
remaining_amount = self.bank_id.no_amount
rent_lines = [line for line in self.reconciliation_line_ids if line.collection_type == "rent"]
other_lines = [line for line in self.reconciliation_line_ids if line.collection_type != "rent"]
deposit_lines = [line for line in self.reconciliation_line_ids if line.collection_type == "deposit"] # 押金行
rent_lines = [line for line in self.reconciliation_line_ids if line.collection_type == "rent"] # 租金行
other_lines = [line for line in self.reconciliation_line_ids if line.collection_type not in ["deposit", "rent"]]
# 核心修改:按「到期日期最早」且「金额最小」排序租金行
# 1. 优先按 due_date 升序(最早的日期先处理)
# 2. 日期相同则按 rent 升序(金额最小的先处理)
# 优先处理押金行
sorted_deposit_lines = sorted(deposit_lines, key=lambda line: line.due_date)
for line in sorted_deposit_lines:
if remaining_amount <= 0:
break
deposit = line.rent or 0
line.amount = 0
assign_amount = min(deposit, remaining_amount)
line.amount = assign_amount
remaining_amount -= assign_amount
line.onchange_remake()
# 3. 处理租金行(原有逻辑不变,按“日期最早+金额最小”排序)
sorted_rent_lines = sorted(
rent_lines,
key=lambda line: (
@@ -313,31 +324,25 @@ class PropertyReconciliationWizard(models.Model):
line.rent or 0
)
)
sorted_other_lines = sorted(
other_lines,
key=lambda line: line.due_date
)
# 先处理所有租金类型的行
for line in sorted_rent_lines:
if remaining_amount <= 0:
break
rent = line.rent or 0
line.amount = 0 # 重置金额
# 分配不超过租金和剩余金额的数值
line.amount = 0
assign_amount = min(rent, remaining_amount)
line.amount = assign_amount
remaining_amount -= assign_amount
line.onchange_remake()
# 租金行分配完后,处理其他类型的行
# 4. 处理其他类型行(原有逻辑不变,按日期排序)
if remaining_amount > 0:
sorted_other_lines = sorted(other_lines, key=lambda line: line.due_date)
for line in sorted_other_lines:
if remaining_amount <= 0:
break
rent = line.rent or 0
amount_needed = line.rent or 0
line.amount = 0
assign_amount = min(rent, remaining_amount)
assign_amount = min(amount_needed, remaining_amount)
line.amount = assign_amount
remaining_amount -= assign_amount
line.onchange_remake()