diff --git a/oo_list_manager/static/src/views/list/list_controller.js b/oo_list_manager/static/src/views/list/list_controller.js index a6efb61e3..7cead7e9c 100644 --- a/oo_list_manager/static/src/views/list/list_controller.js +++ b/oo_list_manager/static/src/views/list/list_controller.js @@ -1,13 +1,13 @@ /** @odoo-module **/ -import {ListController} from "@web/views/list/list_controller"; -import {patch} from "@web/core/utils/patch"; -import {onWillStart, useState, useRef, useExternalListener} from "@odoo/owl"; -import {Dropdown} from "@web/core/dropdown/dropdown"; -import {CheckBox} from "@web/core/checkbox/checkbox"; -import {useSortable} from "@web/core/utils/sortable_owl"; -import {useService} from "@web/core/utils/hooks"; -import {usePosition} from "@web/core/position_hook"; +import { ListController } from "@web/views/list/list_controller"; +import { patch } from "@web/core/utils/patch"; +import { onWillStart, useState, useRef, useExternalListener,onWillRender} from "@odoo/owl"; +import { Dropdown } from "@web/core/dropdown/dropdown"; +import { CheckBox } from "@web/core/checkbox/checkbox"; +import { useSortable } from "@web/core/utils/sortable_owl"; +import { useService } from "@web/core/utils/hooks"; +import { usePosition } from "@web/core/position_hook"; patch(ListController.prototype, { @@ -18,13 +18,15 @@ patch(ListController.prototype, { this.ooColumnsRef = useRef('ooColumnsRef'); this.ooManagerRef = useRef('ooManagerRef'); this.ooListRef = useRef('ooListRef'); - this.ooManager = useState({ state: false, key: '', filter: false, serial_num: false, sticky_end: false, + default_order_field: '', + default_order_type: 'asc', + default_page_size: 0, columns: this.archInfo.columns.filter((column) => { if (column.type === "field" && column.widget !== 'handle') { return column @@ -34,28 +36,20 @@ patch(ListController.prototype, { return column.name }) }); - - console.log(this.ooManager.columns) - onWillStart(async () => { const manager_data = await this.orm.call('ir.ui.view', 'get_manager_data', [this.env.config.viewId]); - console.log(manager_data) if (!Object.keys(manager_data).length || !manager_data.columns) { this.ooManager.columns.forEach(val => { val.visibility = !!!val.column_invisible; }) } else { - // 简化逻辑:如果字段不一致(字段名判断),则重置视图 const currentColumns = this.ooManager.columns; const savedColumns = manager_data.columns || []; - // 比较字段名是否一致 const currentColumnNames = currentColumns.map(col => col.name).sort(); const savedColumnNames = savedColumns.map(col => col.name).sort(); - const isFieldConsistent = JSON.stringify(currentColumnNames) === JSON.stringify(savedColumnNames); - if (!isFieldConsistent) { // 字段不一致,重置视图配置 this.ooManager.columns.forEach(val => { @@ -69,7 +63,19 @@ patch(ListController.prototype, { } this.ooManager.show = manager_data.show; }) - + onWillRender(() => { + if (this.ooManager.default_page_size>0) { + this.model.config.limit = this.ooManager.default_page_size; + // this.model.load(); + } + if (this.ooManager.default_order_field) { + this.model.config.orderBy = []; + this.model.config.orderBy.push({ + name: this.ooManager.default_order_field, + [this.ooManager.default_order_type]: true + }); + } + }); usePosition('ooListRef', () => this.ooManagerRef.el, { position: "bottom-start", }) @@ -84,7 +90,6 @@ patch(ListController.prototype, { useExternalListener(window, "click", this.onGlobalClick.bind(this)); }, - onGlobalClick(ev) { if (this.ooListRef.el && !this.ooListRef.el.contains(ev.target)) { this.ooManager.state = false; @@ -169,7 +174,7 @@ patch(ListController.prototype, { * @param params */ sortColumnDrop(params) { - const {element, previous} = params; + const { element, previous } = params; const fromId = element.dataset.id; const toId = previous ? previous.dataset.id : null; @@ -192,7 +197,6 @@ patch(ListController.prototype, { this.ooManager.columns = columns; }, - /** * 保存 * @returns {*} @@ -208,7 +212,10 @@ patch(ListController.prototype, { columns: this.ooManager.columns, filter: this.ooManager.filter, serial_num: this.ooManager.serial_num, - sticky_end: this.ooManager.sticky_end + sticky_end: this.ooManager.sticky_end, + default_order_field: this.ooManager.default_order_field, + default_order_type: this.ooManager.default_order_type, + default_page_size: this.ooManager.default_page_size, } ] ); diff --git a/oo_list_manager/static/src/views/list/list_controller.xml b/oo_list_manager/static/src/views/list/list_controller.xml index b5db23122..8a9e0eaa6 100644 --- a/oo_list_manager/static/src/views/list/list_controller.xml +++ b/oo_list_manager/static/src/views/list/list_controller.xml @@ -39,6 +39,41 @@ + +
+
+ + +
+
+ + +
+
+ + +
+
diff --git a/oo_list_manager/static/src/views/list/list_renderer.js b/oo_list_manager/static/src/views/list/list_renderer.js index 7e4af5c07..ac646e542 100644 --- a/oo_list_manager/static/src/views/list/list_renderer.js +++ b/oo_list_manager/static/src/views/list/list_renderer.js @@ -206,7 +206,6 @@ patch(ListRenderer.prototype, { } if (this.props.ooManagerStickyEnd) { - console.log('ooManagerStickyEnd') let rightOffset = 0; const rightStickyIndices = []; @@ -262,7 +261,6 @@ patch(ListRenderer.prototype, { * @returns {boolean} */ get hasOptionalFields() { - console.log('hasOptionalFields') return false }, get displayOptionalFields() { @@ -272,7 +270,6 @@ patch(ListRenderer.prototype, { getActiveColumns(list) { if (this.props.ooManagerColumns) { - console.log(this.allColumns) const columns = this.allColumns.filter((col) => { if (list.isGrouped && col.widget === "handle") return false; const mColumn = this.props.ooManagerColumns.find(item => item.id === col.id); diff --git a/soong_workflow/views/soong_user_role_views.xml b/soong_workflow/views/soong_user_role_views.xml index 40e871ebe..3acc48e71 100644 --- a/soong_workflow/views/soong_user_role_views.xml +++ b/soong_workflow/views/soong_user_role_views.xml @@ -4,7 +4,7 @@ soong.user.role.tree soong.user.role - + diff --git a/yuthon_holiday/__manifest__.py b/yuthon_holiday/__manifest__.py index 6a6a9b8f3..1c1d9e763 100644 --- a/yuthon_holiday/__manifest__.py +++ b/yuthon_holiday/__manifest__.py @@ -9,11 +9,9 @@ 'security/ir.model.access.csv', 'security/yuthon_holiday_group.xml', 'data/yuthon_holiday_data.xml', - 'data/mothly_report_time.xml', 'views/inherit_hr_type_views.xml', 'views/inherit_hr_leave_allocation_views.xml', 'views/inherit_hr_leave_accrual_plan_views.xml', - 'views/yuthon_vacation_reports_views.xml', 'views/hr_leave_accrual_views.xml', 'views/yuthon_fixes_approval_views.xml', 'views/hr_leave_batch.xml', diff --git a/yuthon_holiday/models/__init__.py b/yuthon_holiday/models/__init__.py index 0164de29d..b45a80492 100644 --- a/yuthon_holiday/models/__init__.py +++ b/yuthon_holiday/models/__init__.py @@ -3,5 +3,4 @@ from . import inherit_hr_leave_type from . import inherit_hr_leave from . import inherit_hr_leave_accrual_plan from . import yuthon_fixes_approval -from . import yuthon_holiday_setting -from . import yuthon_vacation_reports \ No newline at end of file +from . import yuthon_holiday_setting \ No newline at end of file diff --git a/yuthon_holiday/security/ir.model.access.csv b/yuthon_holiday/security/ir.model.access.csv index 583d690e2..0b7747768 100644 --- a/yuthon_holiday/security/ir.model.access.csv +++ b/yuthon_holiday/security/ir.model.access.csv @@ -6,10 +6,3 @@ access_yuthon_fixes_wizard,yuthon_fixes_wizard,model_yuthon_fixes_wizard,base.gr access_yuthon_holiday_setting,yuthon_holiday_setting,model_yuthon_holiday_setting,base.group_user,1,1,1,1 access_leave_allocation_wizard,leave_allocation_wizard,model_leave_allocation_wizard,base.group_user,1,1,1,1 access_yuthon_leave_wizard,yuthon_leave_wizard,model_yuthon_leave_wizard,base.group_user,1,1,1,1 -access_yuthon_vacation_reports,yuthon_vacation_reports,model_yuthon_vacation_reports,base.group_user,1,1,1,1 -access_vacation_leave_line,vacation_leave_line,model_vacation_leave_line,base.group_user,1,1,1,1 -access_vacation_meal_line,vacation_meal_line,model_vacation_meal_line,base.group_user,1,1,1,1 -access_vacation_over_line,vacation_over_line,model_vacation_over_line,base.group_user,1,1,1,1 -access_details_tree, details_tree,model_details_tree,base.group_user,1,1,1,1 -access_vacation_medical_line,vacation_medical_line,model_vacation_medical_line,base.group_user,1,1,1,1 -access_vacation_other_line,vacation_other_line,model_vacation_other_line,base.group_user,1,1,1,1 diff --git a/yuthon_holiday/security/yuthon_holiday_group.xml b/yuthon_holiday/security/yuthon_holiday_group.xml index eea6b9581..76f799240 100644 --- a/yuthon_holiday/security/yuthon_holiday_group.xml +++ b/yuthon_holiday/security/yuthon_holiday_group.xml @@ -13,10 +13,5 @@ - - 假期额度记录多公司 - - [('company_id', 'in', company_ids)] - \ No newline at end of file diff --git a/yuthon_hr_attendance/__manifest__.py b/yuthon_hr_attendance/__manifest__.py index e425d747b..75a573742 100644 --- a/yuthon_hr_attendance/__manifest__.py +++ b/yuthon_hr_attendance/__manifest__.py @@ -18,6 +18,7 @@ 'security/ir.model.access.csv', 'security/planning_group.xml', 'data/hr_attendance_time.xml', + 'data/mothly_report_time.xml', 'data/attendance_code_data.xml', 'data/attendance_time_data.xml', 'data/attendance_month_date.xml', @@ -31,6 +32,7 @@ 'views/yuthon_customer_approval_views.xml', 'views/yuthon_shift_planning_views.xml', 'views/yuthon_run_planning_views.xml', + 'views/yuthon_vacation_reports_views.xml', 'views/hr_attendance_wechat_views.xml', 'views/hr_attendance_detail_wechat_views.xml', 'views/overtime_approval.xml', diff --git a/yuthon_holiday/data/mothly_report_time.xml b/yuthon_hr_attendance/data/mothly_report_time.xml similarity index 100% rename from yuthon_holiday/data/mothly_report_time.xml rename to yuthon_hr_attendance/data/mothly_report_time.xml diff --git a/yuthon_hr_attendance/models/__init__.py b/yuthon_hr_attendance/models/__init__.py index 2f34dff75..2d2cbfa36 100644 --- a/yuthon_hr_attendance/models/__init__.py +++ b/yuthon_hr_attendance/models/__init__.py @@ -8,6 +8,7 @@ from . import remove_holiday_approval from . import card_approval from . import planning_template_inherit from . import overtime_page +from . import yuthon_vacation_reports from . import inherit_planning_role from . import yuthon_shift_planning from . import yuthon_run_planning diff --git a/yuthon_holiday/models/yuthon_vacation_reports.py b/yuthon_hr_attendance/models/yuthon_vacation_reports.py similarity index 77% rename from yuthon_holiday/models/yuthon_vacation_reports.py rename to yuthon_hr_attendance/models/yuthon_vacation_reports.py index 8cf280782..31323f057 100644 --- a/yuthon_holiday/models/yuthon_vacation_reports.py +++ b/yuthon_hr_attendance/models/yuthon_vacation_reports.py @@ -2,12 +2,15 @@ from datetime import datetime, timedelta, time from email.policy import default from odoo import models, fields, api, _ from odoo.exceptions import ValidationError +import calendar +from datetime import date class YuthonVacationReports(models.Model): _name = 'yuthon.vacation.reports' _description = '假期额度记录' _rec_name = "employee_id" + _order = "vacation_date desc" employee_id = fields.Many2one('hr.employee', string='员工') department_id = fields.Many2one(related='employee_id.department_id', string="部门") @@ -19,10 +22,118 @@ class YuthonVacationReports(models.Model): other_fee_ids = fields.One2many('vacation.other.line', 'vacation_id', string='其他明细') vacation_date = fields.Date(string='日期', default=lambda self: fields.Date.today()) - leave = fields.Char(string='年假', compute='_compute_leave', store=True) + leave = fields.Char(string='年假', compute='_compute_leave', store=True, digits=(16, 3)) working_overtime = fields.Char(string='加班时', compute='_compute_working_overtime', store=True) meal_fee = fields.Integer(string="误餐次数", compute='_compute_meal_fee', store=True) medical_fee = fields.Float(string="体检费", compute='_compute_medical_fee', store=True) + compensatory_leave = fields.Integer(string="调休") + leave_of_absence = fields.Integer(string="事假", digits=(16, 3)) + statutory_leave = fields.Integer(string="法定假") + cop_leave = fields.Float(string='补休', digits=(16, 3)) + duty_off_leave = fields.Integer(string='值班调休') + marriage_leave = fields.Integer(string='婚假') + maternity_leave = fields.Integer(string='产假') + paternity_leave = fields.Integer(string='陪产假') + family_planning_leave = fields.Integer(string='计生假') + bereavement_leave = fields.Float(string='丧假') + home_visit_leave = fields.Integer(string='探亲假') + parents_meeting_leave = fields.Integer(string='家长会假') + general_sick_leave = fields.Float(string='病假(普通)') + hospital_sick_leave = fields.Float(string='病假(住院期)') + recovery_sick_leave = fields.Float(string='病假(出院恢复期)') + exam_leave = fields.Integer(string='考试假') + + is_late_card = fields.Integer(string="迟到", compute='_compute_attendance_fields', store=True) + is_early_card = fields.Integer(string="早退", compute='_compute_attendance_fields', store=True) + is_no_card = fields.Integer(string="缺卡", compute='_compute_attendance_fields', store=True) + is_work = fields.Integer(string='旷工', compute='_compute_attendance_fields', store=True) + is_abnormal = fields.Boolean(string="异常", compute='_compute_attendance_fields', store=True) + + vacation_state = fields.Selection( + selection=[ + ('unconfirmed', "未确认"), + ('confirmed', "已确认"), + ('pending', "待定"), + ], + string="状态", + readonly=True, copy=False, index=True, + tracking=3, + default='unconfirmed') + + @api.depends('employee_id', 'vacation_date') + def _compute_attendance_fields(self): + for rec in self: + # 初始化字段值 + is_late = 0 + is_early = 0 + is_no = 0 + is_work = 0 + is_abnormal = False + if rec.employee_id and rec.vacation_date: + year = rec.vacation_date.year + month = rec.vacation_date.month + days_in_month = calendar.monthrange(year, month)[1] + for day in range(1, days_in_month + 1): + current_date = date(year, month, day) + attendances = self.env["hr.attendance"].sudo().search([ + ('employee_id', '=', rec.employee_id.id), + ("current_data", '=', current_date) + ]) + for att in attendances: + if att.is_late_card: + is_late += 1 + if att.is_early_card: + is_early += 1 + if att.is_no_card: + is_no += 1 + if att.absenteeism_card: + is_work += 1 + if att.is_abnormal: + is_abnormal = True + + rec.is_late_card = is_late + rec.is_early_card = is_early + rec.is_no_card = is_no + rec.is_work = is_work + rec.is_abnormal = is_abnormal + + def button_put(self): + menu_id = self.env['ir.ui.menu'].search([('name', '=', '考勤确认'), ('parent_id', '!=', False)]) + url = f'https://oa.thtzjt.com/web#id={self.id}&cids=2&action={menu_id.action.id}&model=hr.attendance.month.detail&view_type=list&menu_id={menu_id.id}' + we_id = self.env['hr.employee'].search([('id', '=', self.employee_id.id)]).wecom_userid + self.sudo().env["wecom.apps"].sync_send_message_textcard(category='default', user_id=we_id, title="考勤确认", + description=self.employee_id.name + '请确认你的考勤:', + url=url, btntxt="详细信息") + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': '确认通知已发送', + 'sticky': False, + } + } + + def button_all_put(self): + detail_ids = self.env["yuthon.vacation.reports"].browse(self._context.get('active_ids', self._context.get('active_id'))) + unique_employee_ids = list({detail.employee_id.id for detail in detail_ids if detail.employee_id}) + for employee_id in unique_employee_ids: + menu_id = self.env['ir.ui.menu'].search([('name', '=', '考勤确认'), ('parent_id', '!=', False)]) + url = f'https://oa.thtzjt.com/web#id={self.id}&cids=2&action={menu_id.action.id}&model=hr.attendance.month.detail&view_type=list&menu_id={menu_id.id}' + we_id = self.env['hr.employee'].search([('id', '=', employee_id)]).wecom_userid + self.sudo().env["wecom.apps"].sync_send_message_textcard(category='attendance', user_id=we_id, title="考勤确认", + description=employee_id.name + '请确认你的考勤:', + url=url, btntxt="详细信息") + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': '确认通知已发送', + 'sticky': False, + } + } + @api.depends('medical_fee_ids.update_type', 'medical_fee_ids.lines', 'medical_fee_ids.is_void') def _compute_medical_fee(self): @@ -172,7 +283,6 @@ class YuthonVacationReports(models.Model): overtime_hours += line_total elif line.update_type == 'reduce': overtime_hours -= line_total - overtime_days = overtime_hours / 8 record.working_overtime = f"{overtime_hours:.2f}小时({overtime_days:.2f}天)" @@ -188,34 +298,6 @@ class YuthonVacationReports(models.Model): meal_total -= int(line.update_lines or 0) record.meal_fee = meal_total - def button_fixes_approval(self): - form_id = self.env.ref('yuthon_holiday.view_yuthon_fixes_approval_form').id - return { - "type": "ir.actions.act_window", - "name": "修正申请", - "res_model": "yuthon.fixes.approval", - "views": [[form_id, "form"]], - "context": { - 'default_users_id': self.employee_id.user_id.id, - 'default_vacation_id': self.id, - 'default_now_type': 'hours', - 'default_holiday_status': 'annual' - } - } - - def vacation_details(self): - domain =[('workflow_id.name', 'in', ['请假', '加班', '外出']), ('create_uid', '=', self.employee_id.user_id.id)] - action = { - 'name': '审批详情', - 'type': 'ir.actions.act_window', - 'res_model': 'soong.workflow.record', - 'view_mode': 'tree', - 'domain': domain, - 'context': {'group_by': ['workflow_id'], - 'tree_view_ref':'yuthon_holiday.details_tree_view', - }} - return action - def update_vacation(self): employees = self.env['hr.employee'].search([ ('is_salary', '=', True), diff --git a/yuthon_hr_attendance/security/ir.model.access.csv b/yuthon_hr_attendance/security/ir.model.access.csv index ed36d674e..b442ac26d 100644 --- a/yuthon_hr_attendance/security/ir.model.access.csv +++ b/yuthon_hr_attendance/security/ir.model.access.csv @@ -8,6 +8,13 @@ access_overtime_page,overtime.page,model_overtime_page,base.group_user,1,1,1,1 access_duty_approval,duty.approval,model_duty_approval,base.group_user,1,1,1,1 access_duty_approval_line,duty.approval.line,model_duty_approval_line,base.group_user,1,1,1,1 access_mac_line, mac.line,model_mac_line,base.group_user,1,1,1,1 +access_yuthon_vacation_reports,yuthon_vacation_reports,model_yuthon_vacation_reports,base.group_user,1,1,1,1 +access_vacation_leave_line,vacation_leave_line,model_vacation_leave_line,base.group_user,1,1,1,1 +access_vacation_meal_line,vacation_meal_line,model_vacation_meal_line,base.group_user,1,1,1,1 +access_vacation_over_line,vacation_over_line,model_vacation_over_line,base.group_user,1,1,1,1 +access_details_tree, details_tree,model_details_tree,base.group_user,1,1,1,1 +access_vacation_medical_line,vacation_medical_line,model_vacation_medical_line,base.group_user,1,1,1,1 +access_vacation_other_line,vacation_other_line,model_vacation_other_line,base.group_user,1,1,1,1 access_yuthon_shift_planning,yuthon.shift.planning,model_yuthon_shift_planning,base.group_user,1,1,1,1 diff --git a/yuthon_hr_attendance/security/planning_group.xml b/yuthon_hr_attendance/security/planning_group.xml index da7981476..9d35897ed 100644 --- a/yuthon_hr_attendance/security/planning_group.xml +++ b/yuthon_hr_attendance/security/planning_group.xml @@ -34,5 +34,10 @@ [('company_id', 'in', company_ids)] + + 假期额度记录多公司 + + [('company_id', 'in', company_ids)] + diff --git a/yuthon_hr_attendance/views/hr_attendance_month_views.xml b/yuthon_hr_attendance/views/hr_attendance_month_views.xml index afe3b957c..da1827b6e 100644 --- a/yuthon_hr_attendance/views/hr_attendance_month_views.xml +++ b/yuthon_hr_attendance/views/hr_attendance_month_views.xml @@ -108,7 +108,6 @@