@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user